管理员

Better Auth 的管理员插件

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

安装

在您的 auth 配置中添加插件

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

auth.ts
import { betterAuth } from "better-auth"
import { admin } from "better-auth/plugins"

export const auth = betterAuth({
    // ... 其他配置选项
    plugins: [
        admin() 
    ]
})

迁移数据库

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

npx auth migrate
npx auth generate

参见 Schema 章节以手动添加这些字段。

添加客户端插件

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

auth-client.ts
import { createAuthClient } from "better-auth/client"
import { adminClient } from "better-auth/client/plugins"

export const authClient = createAuthClient({
    plugins: [
        adminClient()  
    ]
})

使用

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

创建用户

允许管理员创建新用户。

POST/admin/create-user
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" },});
Parameters
emailstringrequired

用户的电子邮件。

passwordstringrequired

用户的密码。

namestringrequired

用户的名称。

rolestring | string[]

表示要应用于新用户的角色的字符串或字符串数组。

dataRecord<string, any>

用户的额外字段。包括自定义附加字段。

列出用户

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

GET/admin/list-users
Notes

所有属性均可选配置。默认返回 100 行,可通过 limit 属性进行配置。

const { data: users, error } = await authClient.admin.listUsers({    query: {        searchValue: "some name",        searchField: "name",        searchOperator: "contains",        limit: 100,        offset: 100,        sortBy: "name",        sortDirection: "desc",        filterField: "email",        filterValue: "hello@example.com",        filterOperator: "eq",    },});
Parameters
searchValuestring

要搜索的值。

searchField"email" | "name"

要搜索的字段,默认是 email。可以是 emailname

searchOperator"contains" | "starts_with" | "ends_with"

搜索要使用的操作符。可以是 containsstarts_withends_with

limitstring | number

要返回的用户数量。默认是 100。

offsetstring | number

起始偏移量。

sortBystring

用于排序的字段。

sortDirection"asc" | "desc"

排序方向。

filterFieldstring

用于过滤的字段。

filterValuestring | number | boolean | string[] | number[]

用于过滤的值。

filterOperator"eq" | "ne" | "lt" | "lte" | "gt" | "gte" | "in" | "not_in" | "contains" | "starts_with" | "ends_with"

过滤时使用的操作符。

查询过滤

listUsers 支持多种过滤操作符,包括 eqcontainsstarts_withends_with

分页

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

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

使用 totallimitoffset 计算:

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

获取第二页,每页 10 个用户:

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 获取用户信息。

GET/admin/get-user
const { data, error } = await authClient.admin.getUser({    query: {        id: "user-id", // required    },});
Parameters
idstringrequired

您要获取的用户的 ID。

返回值

成功时,data 包含用户对象。失败时,error 会包含 codemessagestatusstatusText

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

设置用户角色

更改用户角色。

POST/admin/set-role
const { data, error } = await authClient.admin.setRole({    userId: "user-id",    role: "admin", // required});
Parameters
userIdstring

您要为其设置角色的用户 ID。

rolestring | string[]required

要设置的角色,这可以是字符串或字符串数组。

设置用户密码

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

POST/admin/set-user-password
const { data, error } = await authClient.admin.setUserPassword({    newPassword: 'new-password', // required    userId: 'user-id', // required});
Parameters
newPasswordstringrequired

新密码。

userIdstringrequired

您要为其设置密码的用户 ID。

更新用户

更新用户详情。

POST/admin/update-user
const { data, error } = await authClient.admin.updateUser({    userId: "user-id", // required    data: { name: "John Doe" }, // required});
Parameters
userIdstringrequired

您要更新的用户 ID。

dataRecord<string, any>required

要更新的数据。

禁止用户

POST/admin/ban-user
await authClient.admin.banUser({    userId: "user-id", // required    banReason: "Spamming",    banExpiresIn: 60 * 60 * 24 * 7,});
Parameters
userIdstringrequired

您要禁止的用户 ID。

banReasonstring

禁止原因。

banExpiresInnumber

距离封禁过期还有多少秒。如果未提供,则封禁永不过期。

解禁用户

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

POST/admin/unban-user
await authClient.admin.unbanUser({    userId: "user-id", // required});
Parameters
userIdstringrequired

您要解禁的用户 ID。

列出用户会话

列出用户所有会话。

POST/admin/list-user-sessions
const { data, error } = await authClient.admin.listUserSessions({    userId: "user-id", // required});
Parameters
userIdstringrequired

用户 ID。

撤销用户会话

POST/admin/revoke-user-session
const { data, error } = await authClient.admin.revokeUserSession({    sessionToken: "session_token_here", // required});
Parameters
sessionTokenstringrequired

您要撤销的会话令牌。

撤销用户所有会话

撤销用户的所有会话。

POST/admin/revoke-user-sessions
const { data, error } = await authClient.admin.revokeUserSessions({    userId: "user-id", // required});
Parameters
userIdstringrequired

您要撤销其所有会话的用户 ID。

模拟用户

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

POST/admin/impersonate-user
const { data, error } = await authClient.admin.impersonateUser({    userId: "user-id", // required});
Parameters
userIdstringrequired

您要模拟的用户 ID。

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

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

旧版选项 allowImpersonatingAdmins 仍受支持,但已弃用,将在未来版本中移除。

停止模拟用户

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

POST/admin/stop-impersonating
await authClient.admin.stopImpersonating();

删除用户

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

POST/admin/remove-user
const { data: deletedUser, error } = await authClient.admin.removeUser({    userId: "user-id", // required});
Parameters
userIdstringrequired

您要删除的用户 ID。

访问控制

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

角色

默认情况下,有两个角色:

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

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

一个用户可以拥有多个角色。多个角色以逗号(",")分隔字符串存储。

权限

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

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

session: list revoke delete

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

自定义权限

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

创建访问控制

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

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

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

const ac = createAccessControl(statement); 

为减小包体积,请确保从 better-auth/plugins/access 导入,而非 better-auth/plugins

创建角色

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

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({ 
    project: ["create"], 
}); 

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

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

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

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

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

const ac = createAccessControl(statement);

const admin = ac.newRole({
    project: ["create", "update"],
    ...adminAc.statements, 
});

将角色传递给插件

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

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
            }
        }),
    ],
});

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

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
            }
        })
    ]
})

访问控制用法

拥有权限

POST/admin/has-permission
const { data, error } = await authClient.admin.hasPermission({    userId: "user-id",    permission: { "project": ["create", "update"] } /* 必须使用此字段或 permissions */,    permissions,});
Parameters
userIdstring

您要检查其权限的用户 ID。

permissionRecord<string, string[]>

可选地检查是否授予单个权限。必须使用此字段或 permissions。

permissionsRecord<string, string[]>

可选地检查是否授予多个权限。必须使用此字段或 permission。

示例用法:

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 操作来检查用户权限。

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

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 表添加以下字段:

Table
字段
类型
描述
role ?
string
-
The user's role. Defaults to `user`. Admins will have the `admin` role.
banned ?
boolean
-
Indicates whether the user is banned.
banReason ?
string
-
The reason for the user's ban.
banExpires ?
date
-
The date when the user's ban will expire.

并在 session 表中添加一个字段:

Table
字段
类型
描述
impersonatedBy ?
string
-
The ID of the admin that is impersonating this session.

电子邮件枚举保护

如果您使用 电子邮件枚举保护requireEmailVerificationautoSignIn: false),您需要配置 customSyntheticUser,在伪造的注册响应中包含管理员插件字段:

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

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

管理员角色

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

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

注意: 使用自定义访问控制(通过 acroles)时,不需要 adminRoles 选项。当您定义带有特定权限的自定义角色时,这些角色将仅具有您通过访问控制系统授予它们的权限。

警告:使用自定义访问控制时,仅有 adminuser 是有效角色。任何不在 adminRoles 列表中的角色都将无法执行管理员操作。

管理员用户 ID

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

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

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

impersonationSessionDuration

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

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

默认禁止原因

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

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

默认禁止过期时间

管理员创建用户时的默认禁止过期时间,单位秒。默认为 undefined(即禁止永不过期)。

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

禁止用户消息

禁止用户尝试登录时显示的消息。默认为 "You have been banned from this application. Please contact support if you believe this is an error."

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