# 管理员 (/docs/plugins/admin)

Better Auth 的管理员插件



管理员插件为您的应用程序提供了一套用户管理的管理功能。它允许管理员执行各种操作，如创建用户、管理用户角色、禁止/解禁用户、模拟用户身份等。

## 安装 [#安装]

<Steps>
  <Step>
    ### 在您的 auth 配置中添加插件 [#在您的-auth-配置中添加插件]

    使用管理员插件时，将其添加到您的 auth 配置中。

    ```ts title="auth.ts"
    import { betterAuth } from "better-auth"
    import { admin } from "better-auth/plugins" // [!code highlight]

    export const auth = betterAuth({
        // ... 其他配置选项
        plugins: [
            admin() // [!code highlight]
        ]
    })
    ```
  </Step>

  <Step>
    ### 迁移数据库 [#迁移数据库]

    运行迁移或生成 schema，以向数据库添加必要的字段和表。

    <Tabs items="[&#x22;migrate&#x22;, &#x22;generate&#x22;]">
      <Tab value="migrate">
        <CodeBlockTabs defaultValue="npm" groupId="persist-install">
          <CodeBlockTabsList>
            <CodeBlockTabsTrigger value="npm">
              npm
            </CodeBlockTabsTrigger>

            <CodeBlockTabsTrigger value="pnpm">
              pnpm
            </CodeBlockTabsTrigger>

            <CodeBlockTabsTrigger value="yarn">
              yarn
            </CodeBlockTabsTrigger>

            <CodeBlockTabsTrigger value="bun">
              bun
            </CodeBlockTabsTrigger>
          </CodeBlockTabsList>

          <CodeBlockTab value="npm">
            ```bash
            npx auth migrate
            ```
          </CodeBlockTab>

          <CodeBlockTab value="pnpm">
            ```bash
            pnpm dlx auth migrate
            ```
          </CodeBlockTab>

          <CodeBlockTab value="yarn">
            ```bash
            yarn dlx auth migrate
            ```
          </CodeBlockTab>

          <CodeBlockTab value="bun">
            ```bash
            bun x auth migrate
            ```
          </CodeBlockTab>
        </CodeBlockTabs>
      </Tab>

      <Tab value="generate">
        <CodeBlockTabs defaultValue="npm" groupId="persist-install">
          <CodeBlockTabsList>
            <CodeBlockTabsTrigger value="npm">
              npm
            </CodeBlockTabsTrigger>

            <CodeBlockTabsTrigger value="pnpm">
              pnpm
            </CodeBlockTabsTrigger>

            <CodeBlockTabsTrigger value="yarn">
              yarn
            </CodeBlockTabsTrigger>

            <CodeBlockTabsTrigger value="bun">
              bun
            </CodeBlockTabsTrigger>
          </CodeBlockTabsList>

          <CodeBlockTab value="npm">
            ```bash
            npx auth generate
            ```
          </CodeBlockTab>

          <CodeBlockTab value="pnpm">
            ```bash
            pnpm dlx auth generate
            ```
          </CodeBlockTab>

          <CodeBlockTab value="yarn">
            ```bash
            yarn dlx auth generate
            ```
          </CodeBlockTab>

          <CodeBlockTab value="bun">
            ```bash
            bun x auth generate
            ```
          </CodeBlockTab>
        </CodeBlockTabs>
      </Tab>
    </Tabs>

    参见 [Schema](#schema) 章节以手动添加这些字段。
  </Step>

  <Step>
    ### 添加客户端插件 [#添加客户端插件]

    接下来，在您的身份验证客户端实例中包含管理员客户端插件。

    ```ts title="auth-client.ts"
    import { createAuthClient } from "better-auth/client"
    import { adminClient } from "better-auth/client/plugins"  // [!code highlight]

    export const authClient = createAuthClient({
        plugins: [
            adminClient()  // [!code highlight]
        ]
    })
    ```
  </Step>
</Steps>

## 使用 [#使用]

在执行任何管理员操作之前，用户必须使用管理员帐户进行身份验证。管理员是指分配了 `admin` 角色的任何用户，或者其 ID 包含在 `adminUserIds` 选项中的任何用户。

要创建第一个管理员用户，请在添加 Admin 插件并应用 schema 后运行 CLI：

<CodeBlockTabs defaultValue="npm" groupId="persist-install">
  <CodeBlockTabsList>
    <CodeBlockTabsTrigger value="npm">
      npm
    </CodeBlockTabsTrigger>

    <CodeBlockTabsTrigger value="pnpm">
      pnpm
    </CodeBlockTabsTrigger>

    <CodeBlockTabsTrigger value="yarn">
      yarn
    </CodeBlockTabsTrigger>

    <CodeBlockTabsTrigger value="bun">
      bun
    </CodeBlockTabsTrigger>
  </CodeBlockTabsList>

  <CodeBlockTab value="npm">
    ```bash title="Terminal"
    npx auth@latest create-admin --email admin@example.com --name "Admin" --role admin
    ```
  </CodeBlockTab>

  <CodeBlockTab value="pnpm">
    ```bash title="Terminal"
    pnpm dlx auth@latest create-admin --email admin@example.com --name "Admin" --role admin
    ```
  </CodeBlockTab>

  <CodeBlockTab value="yarn">
    ```bash title="Terminal"
    yarn dlx auth@latest create-admin --email admin@example.com --name "Admin" --role admin
    ```
  </CodeBlockTab>

  <CodeBlockTab value="bun">
    ```bash title="Terminal"
    bun x auth@latest create-admin --email admin@example.com --name "Admin" --role admin
    ```
  </CodeBlockTab>
</CodeBlockTabs>

如果用户已经存在，CLI 会在创建另一个管理员之前要求确认。使用 `--force` 或 `--yes` 可跳过该提示。CLI 默认会将管理员电子邮件标记为已验证；传入 `--no-email-verified` 可禁用此行为。

### 创建用户 [#创建用户]

允许管理员创建新用户。

**Endpoint:** `POST /admin/create-user`

### Client Side

```ts
const { data: newUser, error } = await authClient.admin.createUser({
    email: "user@example.com", // required, 用户的电子邮件。
    password: "some-secure-password", // required, 用户的密码。
    name: "James Smith", // required, 用户的名称。
    role: "user", // 表示要应用于新用户的角色的字符串或字符串数组。
    data: { customField: "customValue" }, // 用户的额外字段。包括自定义附加字段。
});
```

### Server Side

```ts
const newUser = await auth.api.createUser({
    body: {
        email: "user@example.com", // required, 用户的电子邮件。
        password: "some-secure-password", // required, 用户的密码。
        name: "James Smith", // required, 用户的名称。
        role: "user", // 表示要应用于新用户的角色的字符串或字符串数组。
        data: { customField: "customValue" }, // 用户的额外字段。包括自定义附加字段。
    },
});
```

### Type Definition

```ts
type createUser = {
    /**
     * 用户的电子邮件。 
     */
    email: string = "user@example.com"
    /**
     * 用户的密码。 
     */
    password: string = "some-secure-password"
    /**
     * 用户的名称。 
     */
    name: string = "James Smith"
    /**
     * 表示要应用于新用户的角色的字符串或字符串数组。 
     */
    role?: string | string[] = "user"
    /**
     * 用户的额外字段。包括自定义附加字段。 
     */
    data?: Record<string, any> = { customField: "customValue" }
}
```

### 列出用户 [#列出用户]

允许管理员列出数据库中所有用户。

**Endpoint:** `GET /admin/list-users`

> **Note:** 所有属性均可选配置。默认返回 100 行，可通过 `limit` 属性进行配置。

### Client Side

```ts
const { data: users, error } = await authClient.admin.listUsers({
    query: {
        searchValue: "some name", // 要搜索的值。
        searchField: "name", // 要搜索的字段，默认是 email。可以是 `email` 或 `name`。
        searchOperator: "contains", // 搜索要使用的操作符。可以是 `contains`、`starts_with` 或 `ends_with`。
        limit: 100, // 要返回的用户数量。默认是 100。
        offset: 100, // 起始偏移量。
        sortBy: "name", // 用于排序的字段。
        sortDirection: "desc", // 排序方向。
        filterField: "email", // 用于过滤的字段。
        filterValue: "hello@example.com", // 用于过滤的值。
        filterOperator: "eq", // 过滤时使用的操作符。
    },
});
```

### Server Side

```ts
const users = await auth.api.listUsers({
    query: {
        searchValue: "some name", // 要搜索的值。
        searchField: "name", // 要搜索的字段，默认是 email。可以是 `email` 或 `name`。
        searchOperator: "contains", // 搜索要使用的操作符。可以是 `contains`、`starts_with` 或 `ends_with`。
        limit: 100, // 要返回的用户数量。默认是 100。
        offset: 100, // 起始偏移量。
        sortBy: "name", // 用于排序的字段。
        sortDirection: "desc", // 排序方向。
        filterField: "email", // 用于过滤的字段。
        filterValue: "hello@example.com", // 用于过滤的值。
        filterOperator: "eq", // 过滤时使用的操作符。
    },
    // This endpoint requires session cookies.
    headers: await headers(),
});
```

### Type Definition

```ts
type listUsers = {
  /**
   * 要搜索的值。 
   */
  searchValue?: string = "some name"
  /**
   * 要搜索的字段，默认是 email。可以是 `email` 或 `name`。 
   */
  searchField?: "email" | "name" = "name"
  /**
   * 搜索要使用的操作符。可以是 `contains`、`starts_with` 或 `ends_with`。 
   */
  searchOperator?: "contains" | "starts_with" | "ends_with" = "contains"
  /**
   * 要返回的用户数量。默认是 100。
   */
  limit?: string | number = 100
  /**
   * 起始偏移量。 
   */
  offset?: string | number = 100
  /**
   * 用于排序的字段。 
   */
  sortBy?: string = "name"
  /**
   * 排序方向。 
   */
  sortDirection?: "asc" | "desc" = "desc"
  /**
   * 用于过滤的字段。 
   */
  filterField?: string = "email"
  /**
   * 用于过滤的值。 
   */
  filterValue?: string | number | boolean | string[] | number[] = "hello@example.com"
  /**
   * 过滤时使用的操作符。
   */
  filterOperator?: "eq" | "ne" | "lt" | "lte" | "gt" | "gte" | "in" | "not_in" | "contains" | "starts_with" | "ends_with" = "eq"
}
```

#### 查询过滤 [#查询过滤]

`listUsers` 支持多种过滤操作符，包括 `eq`、`contains`、`starts_with` 和 `ends_with`。

#### 分页 [#分页]

`listUsers` 函数支持分页，响应中会返回用户列表和元数据。返回字段如下：

```ts
{
  users: User[],   // 返回的用户数组
  total: number,   // 过滤和搜索后用户总数
  limit: number | undefined,   // 查询中提供的 limit
  offset: number | undefined   // 查询中提供的 offset
}
```

##### 如何实现分页 [#如何实现分页]

使用 `total`、`limit` 和 `offset` 计算：

* **总页数：** `Math.ceil(total / limit)`
* **当前页：** `(offset / limit) + 1`
* **下一页偏移量：** `Math.min(offset + limit, (total - 1))` – 下一页要使用的 `offset` 值，确保它不超过总页数。
* **上一页偏移量：** `Math.max(0, offset - limit)` – 上一页要使用的 `offset` 值（确保它不会小于零）。

##### 示例用法 [#示例用法]

获取第二页，每页 10 个用户：

```ts
import { authClient } from "@/lib/auth-client";

const pageSize = 10;
const currentPage = 2;

const users = await authClient.admin.listUsers({
    query: {
        limit: pageSize,
        offset: (currentPage - 1) * pageSize
    }
});

const totalUsers = users.total;
const totalPages = Math.ceil(totalUsers / pageSize)
```

### 获取用户 [#获取用户]

通过 ID 获取用户信息。

**Endpoint:** `GET /admin/get-user`

### Client Side

```ts
const { data, error } = await authClient.admin.getUser({
    query: {
        id: "user-id", // required, 您要获取的用户的 ID。
    },
});
```

### Server Side

```ts
const data = await auth.api.getUser({
    query: {
        id: "user-id", // required, 您要获取的用户的 ID。
    },
    // This endpoint requires session cookies.
    headers: await headers(),
});
```

### Type Definition

```ts
type getUser = {
  /**
  * 您要获取的用户的 ID。
  */
  id: string = "user-id"
}
```

#### 返回值 [#返回值]

成功时，`data` 包含用户对象。失败时，`error` 会包含 `code`、`message`、`status` 和 `statusText`。

```ts
type GetUserResponse = {
  data: User | null;
  error: null | {
    message: string;
    status: number; // HTTP 状态码
    statusText: string;
    code: string;
}
```

### 设置用户角色 [#设置用户角色]

更改用户角色。

**Endpoint:** `POST /admin/set-role`

### Client Side

```ts
const { data, error } = await authClient.admin.setRole({
    userId: "user-id", // 您要为其设置角色的用户 ID。
    role: "admin", // required, 要设置的角色，这可以是字符串或字符串数组。
});
```

### Server Side

```ts
const data = await auth.api.setRole({
    body: {
        userId: "user-id", // 您要为其设置角色的用户 ID。
        role: "admin", // required, 要设置的角色，这可以是字符串或字符串数组。
    },
    // This endpoint requires session cookies.
    headers: await headers(),
});
```

### Type Definition

```ts
type setRole = {
    /**
     * 您要为其设置角色的用户 ID。
     */
    userId?: string = "user-id"
    /**
     * 要设置的角色，这可以是字符串或字符串数组。 
     */
    role: string | string[] = "admin"
}
```

### 设置用户密码 [#设置用户密码]

为用户设置密码。如果用户还没有凭据账户，则会创建一个。

**Endpoint:** `POST /admin/set-user-password`

### Client Side

```ts
const { data, error } = await authClient.admin.setUserPassword({
    newPassword: 'new-password', // required, 新密码。
    userId: 'user-id', // required, 您要为其设置密码的用户 ID。
});
```

### Server Side

```ts
const data = await auth.api.setUserPassword({
    body: {
        newPassword: 'new-password', // required, 新密码。
        userId: 'user-id', // required, 您要为其设置密码的用户 ID。
    },
    // This endpoint requires session cookies.
    headers: await headers(),
});
```

### Type Definition

```ts
type setUserPassword = {
    /**
     * 新密码。 
     */
    newPassword: string = 'new-password'
    /**
     * 您要为其设置密码的用户 ID。
     */
    userId: string = 'user-id'
}
```

### 更新用户 [#更新用户]

更新用户详情。

**Endpoint:** `POST /admin/update-user`

### Client Side

```ts
const { data, error } = await authClient.admin.updateUser({
    userId: "user-id", // required, 您要更新的用户 ID。
    data: { name: "John Doe" }, // required, 要更新的数据。
});
```

### Server Side

```ts
const data = await auth.api.adminUpdateUser({
    body: {
        userId: "user-id", // required, 您要更新的用户 ID。
        data: { name: "John Doe" }, // required, 要更新的数据。
    },
    // This endpoint requires session cookies.
    headers: await headers(),
});
```

### Type Definition

```ts
type adminUpdateUser = {
    /**
     * 您要更新的用户 ID。
     */
    userId: string = "user-id"
    /**
     * 要更新的数据。
     */
    data: Record<string, any> = { name: "John Doe" }
}
```

### 禁止用户 [#禁止用户]

**Endpoint:** `POST /admin/ban-user`

### Client Side

```ts
await authClient.admin.banUser({
    userId: "user-id", // required, 您要禁止的用户 ID。
    banReason: "Spamming", // 禁止原因。
    banExpiresIn: 60 * 60 * 24 * 7, // 距离封禁过期还有多少秒。如果未提供，则封禁永不过期。
});
```

### Server Side

```ts
await auth.api.banUser({
    body: {
        userId: "user-id", // required, 您要禁止的用户 ID。
        banReason: "Spamming", // 禁止原因。
        banExpiresIn: 60 * 60 * 24 * 7, // 距离封禁过期还有多少秒。如果未提供，则封禁永不过期。
    },
    // This endpoint requires session cookies.
    headers: await headers(),
});
```

### Type Definition

```ts
type banUser = {
    /**
     * 您要禁止的用户 ID。
     */
    userId: string = "user-id"
    /**
     * 禁止原因。 
     */
    banReason?: string = "Spamming"
    /**
     * 距离封禁过期还有多少秒。如果未提供，则封禁永不过期。 
     */
    banExpiresIn?: number = 60 * 60 * 24 * 7
}
```

### 解禁用户 [#解禁用户]

解除用户禁止状态，允许用户重新登录。

**Endpoint:** `POST /admin/unban-user`

### Client Side

```ts
await authClient.admin.unbanUser({
    userId: "user-id", // required, 您要解禁的用户 ID。
});
```

### Server Side

```ts
await auth.api.unbanUser({
    body: {
        userId: "user-id", // required, 您要解禁的用户 ID。
    },
    // This endpoint requires session cookies.
    headers: await headers(),
});
```

### Type Definition

```ts
type unbanUser = {
    /**
     * 您要解禁的用户 ID。
     */
    userId: string = "user-id"
}
```

### 列出用户会话 [#列出用户会话]

列出用户所有会话。

**Endpoint:** `POST /admin/list-user-sessions`

### Client Side

```ts
const { data, error } = await authClient.admin.listUserSessions({
    userId: "user-id", // required, 用户 ID。
});
```

### Server Side

```ts
const data = await auth.api.listUserSessions({
    body: {
        userId: "user-id", // required, 用户 ID。
    },
    // This endpoint requires session cookies.
    headers: await headers(),
});
```

### Type Definition

```ts
type listUserSessions = {
    /**
     * 用户 ID。 
     */
    userId: string = "user-id"
}
```

### 撤销用户会话 [#撤销用户会话]

**Endpoint:** `POST /admin/revoke-user-session`

### Client Side

```ts
const { data, error } = await authClient.admin.revokeUserSession({
    sessionToken: "session_token_here", // required, 您要撤销的会话令牌。
});
```

### Server Side

```ts
const data = await auth.api.revokeUserSession({
    body: {
        sessionToken: "session_token_here", // required, 您要撤销的会话令牌。
    },
    // This endpoint requires session cookies.
    headers: await headers(),
});
```

### Type Definition

```ts
type revokeUserSession = {
    /**
     * 您要撤销的会话令牌。 
     */
    sessionToken: string = "session_token_here"
}
```

### 撤销用户所有会话 [#撤销用户所有会话]

撤销用户的所有会话。

**Endpoint:** `POST /admin/revoke-user-sessions`

### Client Side

```ts
const { data, error } = await authClient.admin.revokeUserSessions({
    userId: "user-id", // required, 您要撤销其所有会话的用户 ID。
});
```

### Server Side

```ts
const data = await auth.api.revokeUserSessions({
    body: {
        userId: "user-id", // required, 您要撤销其所有会话的用户 ID。
    },
    // This endpoint requires session cookies.
    headers: await headers(),
});
```

### Type Definition

```ts
type revokeUserSessions = {
    /**
     * 您要撤销其所有会话的用户 ID。 
     */
    userId: string = "user-id"
}
```

### 模拟用户 [#模拟用户]

此功能允许管理员创建一个模拟指定用户的会话。该会话将在浏览器会话结束或达到 1 小时后失效。您可以通过设置 `impersonationSessionDuration` 选项更改此时长。

**Endpoint:** `POST /admin/impersonate-user`

### Client Side

```ts
const { data, error } = await authClient.admin.impersonateUser({
    userId: "user-id", // required, 您要模拟的用户 ID。
});
```

### Server Side

```ts
const data = await auth.api.impersonateUser({
    body: {
        userId: "user-id", // required, 您要模拟的用户 ID。
    },
    // This endpoint requires session cookies.
    headers: await headers(),
});
```

### Type Definition

```ts
type impersonateUser = {
    /**
     * 您要模拟的用户 ID。 
     */
    userId: string = "user-id"
}
```

默认情况下，管理员不能模拟其他管理员用户。若要允许此操作，请为角色授予 `impersonate-admins` 权限：

```ts title="auth.ts"
const superAdmin = ac.newRole({
  ...adminAc.statements,
  user: ["impersonate-admins", ...adminAc.statements.user],
});
```

<Callout type="info">
  旧版选项 `allowImpersonatingAdmins` 仍受支持，但已弃用，将在未来版本中移除。
</Callout>

### 停止模拟用户 [#停止模拟用户]

停止模拟用户，继续使用管理员账号。

**Endpoint:** `POST /admin/stop-impersonating`

### Client Side

```ts
await authClient.admin.stopImpersonating();
```

### Server Side

```ts
await auth.api.stopImpersonating({
    // This endpoint requires session cookies.
    headers: await headers(),
});
```

### Type Definition

```ts
type stopImpersonating = {
}
```

### 删除用户 [#删除用户]

从数据库中彻底删除用户。

**Endpoint:** `POST /admin/remove-user`

### Client Side

```ts
const { data: deletedUser, error } = await authClient.admin.removeUser({
    userId: "user-id", // required, 您要删除的用户 ID。
});
```

### Server Side

```ts
const deletedUser = await auth.api.removeUser({
    body: {
        userId: "user-id", // required, 您要删除的用户 ID。
    },
    // This endpoint requires session cookies.
    headers: await headers(),
});
```

### Type Definition

```ts
type removeUser = {
    /**
     * 您要删除的用户 ID。 
     */
    userId: string = "user-id"
}
```

## 访问控制 [#访问控制]

管理员插件提供了高度灵活的访问控制系统，允许您基于用户角色管理权限。您可以定义自定义权限集以满足需求。

### 角色 [#角色]

默认情况下，有两个角色：

`admin`：具有管理员角色的用户对其他用户拥有完全控制权。

`user`：具有用户角色的用户对其他用户无任何控制权。

<Callout>
  一个用户可以拥有多个角色。多个角色以逗号（","）分隔字符串存储。
</Callout>

### 权限 [#权限]

默认情况下，有两个资源及其对应权限。

**user**:
`create` `list` `set-role` `ban` `impersonate` `impersonate-admins` `delete` `set-password` `set-email` `get` `update`

**session**:
`list` `revoke` `delete`

拥有管理员角色的用户对所有资源和操作拥有完全控制权。拥有用户角色的用户对任何操作均无控制权。

### 自定义权限 [#自定义权限]

该插件提供简便的方式为每个角色定义自己的权限集。

<Steps>
  <Step>
    #### 创建访问控制 [#创建访问控制]

    您首先需要通过调用 `createAccessControl` 函数并传入 statement 对象来创建访问控制器。statement 对象应以资源名称作为键，以操作数组作为值。

    ```ts title="permissions.ts"
    import { createAccessControl } from "better-auth/plugins/access";

    /**
     * 确保使用 `as const`，以便 TypeScript 正确推断类型
     */
    const statement = { // [!code highlight]
        project: ["create", "share", "update", "delete"], // [!code highlight]
    } as const; // [!code highlight]

    const ac = createAccessControl(statement); // [!code highlight]
    ```

    <Callout type="warning">
      为减小包体积，请确保从 `better-auth/plugins/access` 导入，而非 `better-auth/plugins`。
    </Callout>
  </Step>

  <Step>
    #### 创建角色 [#创建角色]

    创建完访问控制器后，即可为定义的权限创建角色。

    ```ts title="permissions.ts"
    import { createAccessControl } from "better-auth/plugins/access";

    export const statement = {
        project: ["create", "share", "update", "delete"], // <-- 创建角色可用的权限
    } as const;

    export const ac = createAccessControl(statement);

    export const user = ac.newRole({ // [!code highlight]
        project: ["create"], // [!code highlight]
    }); // [!code highlight]

    export const admin = ac.newRole({ // [!code highlight]
        project: ["create", "update"], // [!code highlight]
    }); // [!code highlight]

    export const myCustomRole = ac.newRole({ // [!code highlight]
        project: ["create", "update", "delete"], // [!code highlight]
        user: ["ban"], // [!code highlight]
    }); // [!code highlight]
    ```

    当您为已有角色创建自定义角色时，这些角色预定义的权限将被覆盖。若要将已有权限添加到自定义角色中，您需要导入 `defaultStatements` 并将其与新 statement 合并，同时将这些角色的权限集与默认角色合并。

    ```ts title="permissions.ts"
    import { createAccessControl } from "better-auth/plugins/access";
    import { defaultStatements, adminAc } from "better-auth/plugins/admin/access";

    const statement = {
        ...defaultStatements, // [!code highlight]
        project: ["create", "share", "update", "delete"],
    } as const;

    const ac = createAccessControl(statement);

    const admin = ac.newRole({
        project: ["create", "update"],
        ...adminAc.statements, // [!code highlight]
    });
    ```
  </Step>

  <Step>
    #### 将角色传递给插件 [#将角色传递给插件]

    创建角色后，您可以在客户端和服务端都将它们传递给管理员插件。

    ```ts title="auth.ts"
    import { betterAuth } from "better-auth"
    import { admin as adminPlugin } from "better-auth/plugins"
    import { ac, admin, user } from "@/auth/permissions"

    export const auth = betterAuth({
        plugins: [
            adminPlugin({
                ac,
                roles: {
                    admin,
                    user,
                    myCustomRole
                }
            }),
        ],
    });
    ```

    您还需要将访问控制器和角色传递给客户端插件。

    ```ts title="auth-client.ts"
    import { createAuthClient } from "better-auth/client"
    import { adminClient } from "better-auth/client/plugins"
    import { ac, admin, user, myCustomRole } from "@/auth/permissions"

    export const client = createAuthClient({
        plugins: [
            adminClient({
                ac,
                roles: {
                    admin,
                    user,
                    myCustomRole
                }
            })
        ]
    })
    ```
  </Step>
</Steps>

### 访问控制用法 [#访问控制用法]

**拥有权限**：

**Endpoint:** `POST /admin/has-permission`

### Client Side

```ts
const { data, error } = await authClient.admin.hasPermission({
    userId: "user-id", // 您要检查其权限的用户 ID。
    permission: { "project": ["create", "update"] } /* 必须使用此字段或 permissions */, // 可选地检查是否授予单个权限。必须使用此字段或 permissions。
    permissions, // 可选地检查是否授予多个权限。必须使用此字段或 permission。
});
```

### Server Side

```ts
const data = await auth.api.userHasPermission({
    body: {
        userId: "user-id", // 您要检查其权限的用户 ID。
        role: "admin", // server-only, 检查角色权限。
        permission: { "project": ["create", "update"] } /* 必须使用此字段或 permissions */, // 可选地检查是否授予单个权限。必须使用此字段或 permissions。
        permissions, // 可选地检查是否授予多个权限。必须使用此字段或 permission。
    },
});
```

### Type Definition

```ts
type userHasPermission = {
    /**
     * 您要检查其权限的用户 ID。 
     */
    userId?: string = "user-id"
    /**
     * 检查角色权限。
     * @serverOnly
     */
    role?: string = "admin"
    /**
     * 可选地检查是否授予单个权限。必须使用此字段或 permissions。 
     */
    permission?: Record<string, string[]> = { "project": ["create", "update"] } /* 必须使用此字段或 permissions */,
    /**
     * 可选地检查是否授予多个权限。必须使用此字段或 permission。 
     */
    permissions?: Record<string, string[]>
}
```

示例用法：

```ts
import { authClient } from "@/lib/auth-client";

const canCreateProject = await authClient.admin.hasPermission({
  permissions: {
    project: ["create"],
  },
});

// 也可以同时检查多个资源权限
const canCreateProjectAndCreateSale = await authClient.admin.hasPermission({
  permissions: {
    project: ["create"],
    sale: ["create"]
  },
});
```

如果您想在服务端检查用户权限，可以使用 `api` 提供的 `userHasPermission` 操作来检查用户权限。

```ts title="permission.ts"
import { auth } from "@/lib/auth"

await auth.api.userHasPermission({
  body: {
    userId: 'id', // 用户 id
    permissions: {
      project: ["create"], // 必须匹配访问控制中的结构
    },
  },
});

// 也可以直接传递角色
await auth.api.userHasPermission({
  body: {
   role: "admin",
    permissions: {
      project: ["create"], // 必须匹配访问控制中的结构
    },
  },
});

// 也可以同时检查多个资源权限
await auth.api.userHasPermission({
  body: {
   role: "admin",
    permissions: {
      project: ["create"], // 必须匹配访问控制中的结构
      sale: ["create"]
    },
  },
});
```

**检查角色权限**：

注意此函数不会直接检查当前登录用户权限，而是检查指定角色拥有哪些权限。该函数为同步函数，调用时无需 `await`。

```ts
import { authClient } from "@/lib/auth-client";

const canCreateProject = authClient.admin.checkRolePermission({
  permissions: {
    user: ["delete"],
  },
  role: "admin",
});

// 也可以同时检查多个资源权限
const canDeleteUserAndRevokeSession = authClient.admin.checkRolePermission({
  permissions: {
    user: ["delete"],
    session: ["revoke"]
  },
  role: "admin",
});
```

## 架构 [#架构]

该插件为 `user` 表添加以下字段：



<DatabaseTable name="user" fields="adminUserTableFields" />

并在 `session` 表中添加一个字段：



<DatabaseTable name="session" fields="adminSessionTableFields" />

### 电子邮件枚举保护 [#电子邮件枚举保护]

如果您使用 [电子邮件枚举保护](/docs/authentication/email-password#邮箱枚举保护)（`requireEmailVerification` 或 `autoSignIn: false`），您需要配置 `customSyntheticUser`，在伪造的注册响应中包含管理员插件字段：

```ts title="auth.ts"
export const auth = betterAuth({
  emailAndPassword: {
    enabled: true,
    requireEmailVerification: true,
    customSyntheticUser: ({ coreFields, additionalFields, id }) => ({
      ...coreFields,
      // 管理员插件字段（按架构顺序）
      role: "user", // 或您配置的 defaultRole
      banned: false,
      banReason: null,
      banExpires: null,
      ...additionalFields,
      id,
    }),
  },
  plugins: [admin()],
});
```

## 选项 [#选项]

### 默认角色 [#默认角色]

用户的默认角色。默认为 `user`。

```ts title="auth.ts"
admin({
  defaultRole: "regular",
});
```

### 管理员角色 [#管理员角色]

指定哪些角色被视为管理员角色。默认为 `["admin"]`。自定义角色（例如 `superadmin`）必须在自定义访问控制中定义。

```ts title="auth.ts"
admin({
  // 需要在自定义访问控制中的 `roles` 里定义 `superadmin`
  adminRoles: ["admin", "superadmin"],
});
```

<Callout type="warning">
  **注意：** 使用自定义访问控制（通过 `ac` 和 `roles`）时，**不需要** `adminRoles` 选项。当您定义带有特定权限的自定义角色时，这些角色将仅具有您通过访问控制系统授予它们的权限。

  **警告：** 在**未**使用自定义访问控制时，仅有 `admin` 和 `user` 是有效角色。任何不在 `adminRoles` 列表中的角色都将**无法**执行管理员操作。
</Callout>

### 管理员用户 ID [#管理员用户-id]

您可以传入一个管理员用户 ID 数组，默认为 `[]`

```ts title="auth.ts"
admin({
    adminUserIds: ["user_id_1", "user_id_2"]
})
```

如果用户 ID 在 `adminUserIds` 列表中，他们将能执行任何管理员操作。

### impersonationSessionDuration [#impersonationsessionduration]

模拟会话的持续时长，单位秒。默认为 1 小时。

```ts title="auth.ts"
admin({
  impersonationSessionDuration: 60 * 60 * 24, // 1 天
});
```

### 默认禁止原因 [#默认禁止原因]

管理员创建用户时的默认禁止原因。默认为 `No reason`。

```ts title="auth.ts"
admin({
  defaultBanReason: "Spamming",
});
```

### 默认禁止过期时间 [#默认禁止过期时间]

管理员创建用户时的默认禁止过期时间，单位秒。默认为 `undefined`（即禁止永不过期）。

```ts title="auth.ts"
admin({
  defaultBanExpiresIn: 60 * 60 * 24, // 1 天
});
```

### 禁止用户消息 [#禁止用户消息]

禁止用户尝试登录时显示的消息。默认为“您已被禁止使用此应用程序。如果您认为这是一个错误，请联系支持团队。”

您也可以传入一个同步或异步函数，该函数接收被禁止的用户并返回消息。

```ts title="auth.ts"
admin({
  bannedUserMessage: "自定义禁止用户提示信息",
});
```

```ts title="auth.ts"
admin({
  bannedUserMessage: (user) => {
    return user.banReason
      ? `You have been banned. Reason: ${user.banReason}`
      : "You have been banned.";
  },
});
```

