系统架构
整体架构
请求路径
- 未登录访问业务页:
middleware.ts导出的auth拦截,转到/auth/signin。 /auth与路径以/public开头的页面不要求登录。- Google 回调后
signIn回调调用isEmailAllowedToSignIn:空表白名单策略见 Authentication。 - JWT session 注入
user.id与user.role(查public.users;缺省为voter)。 - 写操作走 Server Actions(加入竞选、分票、CRUD),不是 REST。唯一 HTTP API 是 Auth.js。
权限边界
| 层 | 做什么 | 不做什么 |
|---|---|---|
| middleware | 未登录拦截 | 不看角色 |
app/layout.tsx 侧栏 | 按角色隐藏入口 | 不能当安全边界 |
lib/admin-auth.ts | admin / moderator 的页面与 Action | 投票提交另有专用校验 |
| 投票 Action | 登录、非 admin、ongoing、候选人合法、分票合计 | 不处理开闭投票 |
结果页 /campaigns/[id]/result 当前没有角色校验:任何已登录用户知道 URL 即可打开。进行中只显示等待文案;结束后可见排名。