管理员
Admin 插件为您的应用程序提供了一套用户管理相关的管理功能。它允许管理员执行各种操作,例如创建用户、管理用户角色、封禁/解封用户、模拟用户登录等。
安装
将插件添加到您的 auth 配置中
要使用 Admin 插件,请将其添加到您的 auth 配置中。
import { betterAuth } from "better-auth"
import { admin } from "better-auth/plugins"
export const auth = betterAuth({
// ... 其他配置选项
plugins: [
admin()
]
})
迁移数据库
运行迁移或生成模式(schema),以向数据库添加必要的字段和表。
npx @better-auth/cli migrate
npx @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" },});
属性 | 描述 | 类型 |
---|---|---|
email | 用户的邮箱地址。 | string |
password | 用户的密码。 | string |
name | 用户的姓名。 | string |
role? | 一个字符串或字符串数组,表示要应用到新用户的角色。 | string | string[] |
data? | 用户的额外字段,包括自定义的附加字段。 | Record<string, any> |
列出用户
允许管理员列出数据库中的所有用户。
所有属性都是可选配置。默认返回100行数据,可通过 limit
属性进行配置。
const { data: users, error } = await authClient.admin.listUsers({ searchValue: "some name", searchField: "name", searchOperator: "contains", limit: 100, offset: 100, sortBy: "name", sortDirection: "desc", filterField: "email", filterValue: "hello@example.com", filterOperator: "eq",});
属性 | 描述 | 类型 |
---|---|---|
searchValue? | 要搜索的值。 | string |
searchField? | 要搜索的字段,默认为 email。可以是 email 或 name 。 | "email" | "name" |
searchOperator? | 搜索使用的运算符。可以是 contains (包含)、starts_with (开头为)或 ends_with (结尾为)。 | "contains" | "starts_with" | "ends_with" |
limit? | 要返回的用户数量。默认为100。 | string | number |
offset? | 起始偏移量。 | string | number |
sortBy? | 排序依据的字段。 | string |
sortDirection? | 排序方向。 | "asc" | "desc" |
filterField? | 筛选依据的字段。 | string |
filterValue? | 筛选依据的值。 | string | number | boolean |
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});
属性 | 描述 | 类型 |
---|---|---|
userId? | 要设置角色的用户 ID。 | string |
role | 要设置的角色,可以是字符串或字符串数组。 | string | string[] |
设置用户密码
修改用户的密码。
const { data, error } = await authClient.admin.setUserPassword({ newPassword: 'new-password', // required userId: 'user-id', // required});
属性 | 描述 | 类型 |
---|---|---|
newPassword | 新密码。 | string |
userId | 要为其设置密码的用户 ID。 | string |
封禁用户
封禁用户,阻止其登录并撤销其所有现有会话。
await authClient.admin.banUser({ userId: "user-id", // required banReason: "Spamming", banExpiresIn: 60 * 60 * 24 * 7,});
属性 | 描述 | 类型 |
---|---|---|
userId | 要封禁的用户 ID。 | string |
banReason? | 封禁原因。 | string |
banExpiresIn? | 封禁到期的秒数。如果未提供,则封禁将永久有效。 | number |
解除用户封禁
解除对用户的封禁,允许其再次登录。
await authClient.admin.unbanUser({ userId: "user-id", // required});
属性 | 描述 | 类型 |
---|---|---|
userId | 要解除封禁的用户 ID。 | string |
列出用户会话
列出用户的所有会话。
const { data, error } = await authClient.admin.listUserSessions({ userId: "user-id", // required});
属性 | 描述 | 类型 |
---|---|---|
userId | 用户 ID。 | string |
撤销用户会话
撤销用户的特定会话。
const { data, error } = await authClient.admin.revokeUserSession({ sessionToken: "session_token_here", // required});
属性 | 描述 | 类型 |
---|---|---|
sessionToken | 要撤销的会话令牌。 | string |
撤销用户所有会话
撤销指定用户的所有会话。
const { data, error } = await authClient.admin.revokeUserSessions({ userId: "user-id", // required});
属性 | 描述 | 类型 |
---|---|---|
userId | 需要撤销所有会话的用户 ID | string |
用户模拟
此功能允许管理员创建一个模拟指定用户的会话。该会话将保持活动状态,直到浏览器会话结束或达到 1 小时。您可以通过设置 impersonationSessionDuration
选项来更改此持续时间。
const { data, error } = await authClient.admin.impersonateUser({ userId: "user-id", // required});
属性 | 描述 | 类型 |
---|---|---|
userId | 需要模拟的用户 ID | string |
停止用户模拟
要停止模拟用户并继续使用管理员账户,您可以使用 stopImpersonating
await authClient.admin.stopImpersonating();
删除用户
从数据库中硬删除用户。
const { data: deletedUser, error } = await authClient.admin.removeUser({ userId: "user-id", // required});
属性 | 描述 | 类型 |
---|---|---|
userId | 需要删除的用户 ID | string |
访问控制
管理员插件提供了一个高度灵活的访问控制系统,允许您根据用户角色管理权限。您可以定义自定义权限集以满足您的需求。
角色
默认情况下,有两种角色:
admin
:具有管理员角色的用户对其他用户拥有完全控制权。
user
:具有用户角色的用户对其他用户没有控制权。
一个用户可以拥有多个角色。多个角色以逗号(",")分隔的字符串形式存储。
权限
默认情况下,有两个资源,最多有六个权限。
用户管理:
创建
列表
设置角色
封禁
模拟登录
删除
设置密码
会话管理:
列表
撤销
删除
拥有管理员角色的用户对所有资源和操作拥有完全控制权。拥有用户角色的用户则无法执行上述任何操作。
自定义权限
该插件提供了一种简单的方法来为每个角色定义您自己的权限集。
创建访问控制
您首先需要通过调用 createAccessControl
函数并传递 statement 对象来创建访问控制器。statement 对象应以资源名称为键,以操作数组为值。
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
并将其与您的新 statement 合并,同时将角色的权限集与默认角色合并。
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,});
属性 | 描述 | 类型 |
---|---|---|
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",
});
数据表结构
此插件向 user
表添加了以下字段:
字段名称 | 类型 | Key | 描述 |
---|---|---|---|
role | string | 用户的角色。默认为 `user`。管理员将拥有 `admin` 角色。 | |
banned | boolean | 指示用户是否被禁用。 | |
banReason | string | 用户被禁用的原因。 | |
banExpires | date | 用户禁用将到期的日期。 |
并在 session
表中添加了一个字段:
字段名称 | 类型 | Key | 描述 |
---|---|---|---|
impersonatedBy | string | 正在模拟此会话的管理员 ID。 |
选项
默认角色
用户的默认角色。默认为 user
。
admin({
defaultRole: "regular",
});
管理员角色
被视为管理员角色的列表。默认为 ["admin"]
。
admin({
adminRoles: ["admin", "superadmin"],
});
任何不在 adminRoles
列表中的角色,即使拥有权限,也不会被视为管理员。
管理员用户 ID
您可以传递一个应被视为管理员的用户 ID 数组。默认为 []
admin({
adminUserIds: ["user_id_1", "user_id_2"]
})
如果用户在 adminUserIds
列表中,他们将能够执行任何管理员操作。
模拟会话持续时间
模拟会话的持续时间(以秒为单位)。默认为 1 小时。
admin({
impersonationSessionDuration: 60 * 60 * 24, // 1 天
});
默认封禁原因
由管理员创建的用户默认封禁原因。默认为 No reason
(无原因)。
admin({
defaultBanReason: "Spamming",
});
默认封禁过期时间
由管理员创建的用户默认封禁过期时间(以秒为单位)。默认为 undefined
(表示封禁永不过期)。
admin({
defaultBanExpiresIn: 60 * 60 * 24, // 1 天
});
被封禁用户消息
当被封禁用户尝试登录时显示的消息。默认为 "You have been banned from this application. Please contact support if you believe this is an error."(您已被禁止使用此应用程序。如果您认为这是一个错误,请联系支持。)
admin({
bannedUserMessage: "Custom banned user message",
});