Admin
Admin 플러그인은 애플리케이션에서 사용자 관리를 위한 관리 기능 세트를 제공합니다. 관리자는 사용자 생성, 사용자 역할 관리, 사용자 차단/차단 해제, 사용자 위장, 기타 다양한 작업을 수행할 수 있습니다.
설치
auth 설정에 플러그인 추가
Admin 플러그인을 사용하려면 auth 설정에 추가합니다.
import { betterAuth } from "better-auth"
import { admin } from "better-auth/plugins"
export const auth = betterAuth({
// ... 기타 설정 옵션
plugins: [
admin()
]
})데이터베이스 마이그레이션
마이그레이션을 실행하거나 스키마를 생성하여 필요한 필드와 테이블을 데이터베이스에 추가합니다.
npx @better-auth/cli migratenpx @better-auth/cli generate필드를 수동으로 추가하려면 스키마 섹션을 참조하세요.
클라이언트 플러그인 추가
다음으로, 인증 클라이언트 인스턴스에 admin 클라이언트 플러그인을 포함합니다.
import { createAuthClient } from "better-auth/client"
import { adminClient } from "better-auth/client/plugins"
export const authClient = createAuthClient({
plugins: [
adminClient()
]
})사용법
관리자 작업을 수행하기 전에 사용자는 관리자 계정으로 인증되어야 합니다. 관리자는 admin 역할이 할당된 모든 사용자 또는 adminUserIds 옵션에 포함된 ID를 가진 모든 사용자입니다.
사용자 생성
관리자가 새 사용자를 생성할 수 있습니다.
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으로 사용할 값 (0 미만으로 가지 않도록 보장합니다).
사용 예제
페이지당 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 |
사용자 업데이트
사용자의 세부 정보를 업데이트합니다.
const { data, error } = await authClient.admin.updateUser({ userId: "user-id", // required data: { name: "John Doe" }, // required});| Prop | Description | Type |
|---|---|---|
userId | 업데이트할 사용자 ID | string |
data | 업데이트할 데이터 | Record<string, any> |
사용자 차단
사용자를 차단하여 로그인을 방지하고 기존의 모든 세션을 취소합니다.
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 역할을 가진 사용자는 다른 사용자에 대한 제어 권한이 없습니다.
사용자는 여러 역할을 가질 수 있습니다. 여러 역할은 쉼표(",")로 구분된 문자열로 저장됩니다.
권한
기본적으로 최대 6개의 권한을 가진 두 개의 리소스가 있습니다.
user:
create list set-role ban impersonate delete set-password
session:
list revoke delete
admin 역할을 가진 사용자는 모든 리소스와 작업에 대한 전체 제어 권한을 가집니다. user 역할을 가진 사용자는 이러한 작업에 대한 제어 권한이 없습니다.
사용자 정의 권한
플러그인은 각 역할에 대한 자체 권한 세트를 정의하는 쉬운 방법을 제공합니다.
접근 제어 생성
먼저 createAccessControl 함수를 호출하고 statement 객체를 전달하여 접근 컨트롤러를 생성해야 합니다. statement 객체는 리소스 이름을 키로, 작업 배열을 값으로 가져야 합니다.
import { createAccessControl } from "better-auth/plugins/access";
/**
* TypeScript가 타입을 올바르게 추론할 수 있도록 `as const`를 사용해야 합니다
*/
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,});| 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",
});스키마
이 플러그인은 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 목록에 없는 역할은 권한이 있더라도 관리자로 간주되지 않습니다.
관리자 userId
관리자로 간주해야 하는 userId의 배열을 전달할 수 있습니다. 기본값은 []
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: "사용자 정의 차단 메시지",
});