Admin
Admin 插件为您的应用程序提供了一组用户管理行政功能。它允许管理员执行各种操作,例如创建用户、管理用户角色、封禁/解禁用户、模拟用户等。
安装
将插件添加到您的 auth 配置中
要使用 Admin 插件,请将其添加到您的 auth 配置中。
import { betterAuth } from "better-auth"
import { admin } from "better-auth/plugins"
export const auth = betterAuth({
// ... other config options
plugins: [
admin()
]
})迁移数据库
运行迁移或生成 schema 以向数据库添加必要的字段和表。
npx @better-auth/cli migratenpx @better-auth/cli generate请参阅 Schema 部分以手动添加字段。
添加客户端插件
接下来,在您的认证客户端实例中包含 admin 客户端插件。
import { createAuthClient } from "better-auth/client"
import { adminClient } from "better-auth/client/plugins"
export const authClient = createAuthClient({
plugins: [
adminClient()
]
})使用
在执行任何管理员操作之前,用户必须使用管理员帐户进行身份验证。管理员是任何被分配 admin 角色或其 ID 包含在 adminUserIds 选项中的用户。
创建用户
允许管理员创建新用户。
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" },});| Prop | Description | Type |
|---|---|---|
email | 用户的电子邮件。 | string |
password | 用户的密码。 | string |
name | 用户的名称。 | string |
role? | 表示要应用于新用户的角色字符串或字符串数组。 | string | string[] |
data? | 用户的额外字段。包括自定义附加字段。 | Record<string, any> |
列出用户
允许管理员列出数据库中的所有用户。
所有属性均为可选配置。默认返回 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", },});| Prop | Description | Type |
|---|---|---|
query? | 用于过滤、搜索和分页的查询参数。 | Object |
query.searchValue? | 要搜索的值。 | string |
query.searchField? | 要搜索的字段,默认值为 email。可以是 email 或 name。 | "email" | "name" |
query.searchOperator? | 用于搜索的操作符。可以是 contains、starts_with 或 ends_with。 | "contains" | "starts_with" | "ends_with" |
query.limit? | 要返回的用户数量。默认为 100。 | string | number |
query.offset? | 开始的偏移量。 | string | number |
query.sortBy? | 要排序的字段。 | string |
query.sortDirection? | 排序方向。 | "asc" | "desc" |
query.filterField? | 要过滤的字段。 | string |
query.filterValue? | 要过滤的值。 | string | number | boolean |
query.filterOperator? | 用于过滤的操作符。 | "eq" | "ne" | "lt" | "lte" | "gt" | "gte" |
查询过滤
listUsers 函数支持各种过滤操作符,包括 eq、contains、starts_with 和 ends_with。
分页
listUsers 函数通过返回用户列表伴随的元数据来支持分页。响应包括以下字段:
{
users: User[], // 返回的用户数组
total: number, // 过滤和搜索查询后的用户总数
limit: number | undefined, // 查询中提供的限制
offset: number | undefined // 查询中提供的偏移量
}如何实现分页
要分页结果,请使用 total、limit 和 offset 值来计算:
- 总页数:
Math.ceil(total / limit) - 当前页:
(offset / limit) + 1 - 下一页偏移量:
Math.min(offset + limit, (total - 1))– 用于下一页的offset值,确保它不超过总页数。 - 上一页偏移量:
Math.max(0, offset - limit)– 用于上一页的offset值(确保它不会低于零)。
示例用法
获取每页 10 个用户的第二页:
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)设置用户角色
更改用户角色。
const { data, error } = await authClient.admin.setRole({ userId: "user-id", role: "admin", // required});| Prop | Description | Type |
|---|---|---|
userId? | 要为其设置角色的用户 ID。 | string |
role | 要设置的角色,这可以是字符串或字符串数组。 | string | string[] |
设置用户密码
更改用户的密码。
const { data, error } = await authClient.admin.setUserPassword({ newPassword: 'new-password', // required userId: 'user-id', // required});| Prop | Description | Type |
|---|---|---|
newPassword | 新密码。 | string |
userId | 要为其设置密码的用户 ID。 | string |
封禁用户
封禁用户,阻止他们登录并撤销他们所有现有会话。
await authClient.admin.banUser({ userId: "user-id", // required banReason: "Spamming", banExpiresIn: 60 * 60 * 24 * 7,});| Prop | Description | Type |
|---|---|---|
userId | 要封禁的用户 ID。 | string |
banReason? | 封禁原因。 | string |
banExpiresIn? | 封禁到期前的秒数。如果未提供,封禁将永不过期。 | number |
解禁用户
从用户处移除封禁,允许他们再次登录。
await authClient.admin.unbanUser({ userId: "user-id", // required});| Prop | Description | Type |
|---|---|---|
userId | 要解禁的用户 ID。 | string |
列出用户会话
列出用户的所有会话。
const { data, error } = await authClient.admin.listUserSessions({ userId: "user-id", // required});| Prop | Description | Type |
|---|---|---|
userId | 用户 ID。 | string |
撤销用户会话
撤销用户的特定会话。
const { data, error } = await authClient.admin.revokeUserSession({ sessionToken: "session_token_here", // required});| Prop | Description | Type |
|---|---|---|
sessionToken | 要撤销的会话令牌。 | string |
撤销用户的所有会话
撤销用户的所有会话。
const { data, error } = await authClient.admin.revokeUserSessions({ userId: "user-id", // required});| Prop | Description | Type |
|---|---|---|
userId | 要撤销其所有会话的用户 ID。 | string |
模拟用户
此功能允许管理员创建模拟指定用户的会话。该会话将保持活动状态,直到浏览器会话结束或达到 1 小时。您可以通过设置 impersonationSessionDuration 选项来更改此持续时间。
const { data, error } = await authClient.admin.impersonateUser({ userId: "user-id", // required});| Prop | Description | Type |
|---|---|---|
userId | 要模拟的用户 ID。 | string |
停止模拟用户
要停止模拟用户并继续使用管理员帐户,您可以使用 stopImpersonating。
await authClient.admin.stopImpersonating();删除用户
从数据库中硬删除用户。
const { data: deletedUser, error } = await authClient.admin.removeUser({ userId: "user-id", // required});| Prop | Description | Type |
|---|---|---|
userId | 要删除的用户 ID。 | string |
访问控制
Admin 插件提供了一个高度灵活的访问控制系统,允许您基于用户的角色管理用户权限。您可以定义自定义权限集以满足您的需求。
角色
默认情况下,有两个角色:
admin:具有 admin 角色的用户对其他用户具有完全控制权。
user:具有 user 角色的用户对其他用户没有控制权。
用户可以具有多个角色。多个角色存储为逗号(",")分隔的字符串。
权限
默认情况下,有两个资源,每个资源最多六个权限。
user:
create list set-role ban impersonate delete set-password
session:
list revoke delete
具有 admin 角色的用户对所有资源和操作具有完全控制权。具有 user 角色的用户对这些操作没有任何控制权。
自定义权限
插件提供了一种简单的方式来为每个角色定义您自己的权限集。
创建访问控制
您首先需要通过调用 createAccessControl 函数并传递语句对象来创建访问控制器。语句对象应以资源名称作为键,以操作数组作为值。
import { createAccessControl } from "better-auth/plugins/access";
/**
* 确保使用 `as const` 以便 TypeScript 可以正确推断类型
*/
const statement = {
project: ["create", "share", "update", "delete"],
} as const;
const ac = createAccessControl(statement); 创建角色
创建访问控制器后,您可以创建具有您定义的权限的角色。
import { createAccessControl } from "better-auth/plugins/access";
export const statement = {
project: ["create", "share", "update", "delete"], // <-- 为创建的角色可用的权限
} as const;
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 并将其与您的新语句合并,并将角色权限集与默认角色合并。
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,
});将角色传递给插件
创建角色后,您可以将它们传递给客户端和服务器上的 admin 插件。
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
}
}),
],
});您还需要将访问控制器和角色传递给客户端插件。
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
}
})
]
})访问控制使用
具有权限:
要检查用户的权限,您可以使用客户端提供的 hasPermission 函数。
const { data, error } = await authClient.admin.hasPermission({ userId: "user-id", permission: { "project": ["create", "update"] } /* 必须使用此项,或 permissions */, permissions,});| Prop | Description | Type |
|---|---|---|
userId? | 要检查权限的用户 ID。 | string |
permission? | 可选地检查是否授予单个权限。必须使用此项,或 permissions。 | Record<string, string[]> |
permissions? | 可选地检查是否授予多个权限。必须使用此项,或 permission。 | Record<string, string[]> |
示例用法:
const canCreateProject = await authClient.admin.hasPermission({
permissions: {
project: ["create"],
},
});
// 您也可以同时检查多个资源权限
const canCreateProjectAndCreateSale = await authClient.admin.hasPermission({
permissions: {
project: ["create"],
sale: ["create"]
},
});如果您想在服务器端检查用户的权限,您可以使用 api 提供的 userHasPermission 操作来检查用户的权限。
import { auth } from "@/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"]
},
},
});检查角色权限:
在客户端使用 checkRolePermission 函数来验证给定的 角色 是否具有特定的 权限。这在定义角色及其权限后很有帮助,因为它允许您在无需联系服务器的情况下执行权限检查。
请注意,此函数 不 直接检查当前登录用户的权限。相反,它检查分配给指定角色的权限。该函数是同步的,因此在调用时无需使用 await。
const canCreateProject = authClient.admin.checkRolePermission({
permissions: {
user: ["delete"],
},
role: "admin",
});
// 您也可以同时检查多个资源权限
const canDeleteUserAndRevokeSession = authClient.admin.checkRolePermission({
permissions: {
user: ["delete"],
session: ["revoke"]
},
role: "admin",
});Schema
此插件向 user 表添加以下字段:
| Field Name | Type | Key | Description |
|---|---|---|---|
| role | string | 用户的角色。默认为 `user`。管理员将具有 `admin` 角色。 | |
| banned | boolean | 指示用户是否被封禁。 | |
| banReason | string | 用户封禁的原因。 | |
| banExpires | date | 用户封禁到期日期。 |
并在 session 表中添加一个字段:
| Field Name | Type | Key | Description |
|---|---|---|---|
| impersonatedBy | string | 正在模拟此会话的管理员 ID。 |
选项
默认角色
用户的默认角色。默认为 user。
admin({
defaultRole: "regular",
});管理员角色
被视为管理员角色的角色。默认为 ["admin"]。
admin({
adminRoles: ["admin", "superadmin"],
});adminRoles 列表中不存在的任何角色,即使它们具有权限,
也不会被视为管理员。
管理员 userIds
您可以传递一个应被视为管理员的 userIds 数组。默认为 []
admin({
adminUserIds: ["user_id_1", "user_id_2"]
})如果用户在 adminUserIds 列表中,他们将能够执行任何管理员操作。
impersonationSessionDuration
模拟会话的持续时间(以秒为单位)。默认为 1 小时。
admin({
impersonationSessionDuration: 60 * 60 * 24, // 1 天
});默认封禁原因
由管理员创建的用户默认封禁原因。默认为 No reason。
admin({
defaultBanReason: "Spamming",
});默认封禁到期时间
由管理员创建的用户默认封禁到期时间(以秒为单位)。默认为 undefined(表示封禁永不过期)。
admin({
defaultBanExpiresIn: 60 * 60 * 24, // 1 天
});bannedUserMessage
当封禁用户尝试登录时显示的消息。默认为 "You have been banned from this application. Please contact support if you believe this is an error."
admin({
bannedUserMessage: "Custom banned user message",
});