上手实践
认证与管理员角色
使用数据库管理只读/读写管理员角色,保护管理 API,并介绍本模板的认证流程。
认证与管理员角色
本模板基于 Better Auth + Drizzle。RBAC 仅存储在数据库中,不支持通过环境变量临时提升权限。
基础:认证 vs 授权
- 认证(Authentication):证明“你是谁”(注册/登录),最终得到一个会话(session)。
- 授权(Authorization):决定“你能做什么”。在本模板中由
users
表的role
字段控制。
我们使用的角色:
user
— 默认角色。admin_ro
— 只读管理员(可查看管理数据,不能写)。admin_rw
— 读写管理员(含授予积分等管理操作)。
一个简单的类比
在机场安检出示身份证是“认证”(证明身份);登机口出示登机牌是“授权”(验证你是否被允许登机)。
快速对比
维度 | 认证 | 授权 |
---|---|---|
目的 | 验证身份(是谁) | 验证权限(能做什么) |
时机 | 在授权之前 | 成功认证之后 |
常见输入 | 凭证(密码、邮件链接、社交登录) | 策略/角色(如 user 、admin_ro 、admin_rw ) |
产物 | 会话/身份 | 被允许的操作与受保护路由 |
常见标准(一般情况) | OIDC、ID Token | OAuth 2.0、scopes |
在本模板中:使用服务器端的 HttpOnly 会话 Cookie(不在前端持有 token),并用数据库中的 role
做授权判断。
什么是 Better Auth?
一个面向 TypeScript、轻量的 Next.js 认证库。
- 存储:通过
src/lib/auth.ts
使用 Drizzle ORM + Postgres。 - 数据模型:
users
、sessions
、accounts
、verifications
(见src/db/schema.ts
)。 - 会话:写入 HttpOnly Cookie 并在
sessions
表中持久化;服务端路由通过auth.api.getSession({ headers })
读取会话。 - 扩展字段:通过
additionalFields
将uuid
与role
暴露给会话,便于服务端检查。
密钥与 URL(入门)
BETTER_AUTH_SECRET
:仅服务器可见的、足够随机的密钥,用于签名/校验认证相关的 Cookie/令牌。只生成一次并妥善保管。- 生成:
openssl rand -base64 32
- 轮换提示:修改该值会让所有用户掉线(旧会话不再可验证)。
- 生成:
BETTER_AUTH_URL
:认证库使用的服务端基址(通常即站点 URL)。NEXT_PUBLIC_AUTH_BASE_URL
:客户端使用的基址(大多数情况下等于站点 URL)。- Cookie 在生产环境下使用
HttpOnly
且secure
(见src/lib/auth.ts
中advanced.defaultCookieAttributes
)。
如果出现“只登录一次就失效”或“重启后会话丢失”的情况,请检查以上环境变量并重启开发服务器。
角色
user
:默认角色。admin_ro
:只读管理员;可查看用户列表/订单列表及用户积分汇总。admin_rw
:读写管理员;在只读权限基础上可为用户增加积分(system_add
)。
迁移 0001_add_user_role.sql
会为 users
表新增 role
字段,默认 user
。
授权
src/lib/authz.ts
仅从会话/数据库获取角色:requireAdminRead()
→ 允许admin_ro
/admin_rw
。requireAdminWrite()
→ 仅允许admin_rw
。
管理 API
GET /api/admin/users
→ 用户列表(分页:page
,limit
)。GET /api/admin/orders
→ 已支付订单(分页)。GET /api/admin/users/:uuid/credits
→ 用户积分汇总。POST /api/admin/credits/grant
→ 以system_add
方式增加积分。
配置步骤
- 数据库迁移:
pnpm drizzle-kit migrate --config src/db/config.ts
- 使用管理员账号验证以上接口。
修改角色
以数据库为唯一来源:
- SQL:
update users set role = 'admin_rw' where uuid = '<uuid>';
- 代码助手:
updateUserRole(uuid, 'admin_ro' | 'admin_rw' | 'user')
位于src/models/user.ts
。
说明
- 管理账号建议开启 MFA/SSO,并缩短会话有效期。
- 管理页面需在服务端做权限校验,未授权则重定向。
- 角色不通过 .env 控制;请在数据库中进行赋权/回收。
社交登录(Google)
- 提供商在
src/lib/auth.ts
的socialProviders.google
中配置,并从.env
读取GOOGLE_CLIENT_ID
/GOOGLE_CLIENT_SECRET
。 - 在
.env
中设置:GOOGLE_CLIENT_ID
、GOOGLE_CLIENT_SECRET
,并确保BETTER_AUTH_URL
与NEXT_PUBLIC_AUTH_BASE_URL
正确(开发可用http://localhost:3000
)。 - 在 Google Cloud Console → Credentials 添加授权回调 URI:
http://localhost:3000/api/auth/callback/google
(开发)https://你的域名.com/api/auth/callback/google
(生产)
/[locale]/login
登录页包含“使用 Google 继续”按钮,点击后进入 OAuth 流程。