diff --git a/src/app/api/auth/login/route.ts b/src/app/api/auth/login/route.ts index af84e03..ad4ea06 100644 --- a/src/app/api/auth/login/route.ts +++ b/src/app/api/auth/login/route.ts @@ -4,6 +4,7 @@ import { initDatabase } from '@/lib/db-schema' import { signSharedJwt, sharedCookieConfig } from '@/lib/jwt-shared' import { ldapAuth } from '@/lib/ldap' import { getDb } from '@/lib/db' +import { getUserPermissions } from '@/lib/permissions' import bcrypt from 'bcryptjs' export async function POST(request: NextRequest) { @@ -76,12 +77,12 @@ export async function POST(request: NextRequest) { db.prepare("UPDATE users SET last_login_at = datetime('now', '+8 hours'), last_active_at = datetime('now', '+8 hours') WHERE id = ?").run(userId) // 4. 签发两个 cookie - const localToken = await createToken({ id: userId, username, display_name: displayName, role }) + const localToken = await createToken({ id: userId, username, display_name: displayName, role, permissions: [] }) const sharedToken = signSharedJwt({ username, displayName }) const sharedCfg = sharedCookieConfig() const response = NextResponse.json({ - user: { id: userId, username, display_name: displayName, role }, + user: { id: userId, username, display_name: displayName, role, permissions: getUserPermissions(role) }, }) response.cookies.set('session_issue', localToken, { httpOnly: true, secure: process.env.NODE_ENV === 'production', sameSite: 'lax', diff --git a/src/lib/auth.ts b/src/lib/auth.ts index 166821e..e3e1fbd 100644 --- a/src/lib/auth.ts +++ b/src/lib/auth.ts @@ -8,6 +8,7 @@ export { createToken, verifyToken, type UserPayload } import { verifySharedJwt } from './jwt-shared' import { ldapUserExists } from './ldap' +import { getUserPermissions } from './permissions' export async function getCurrentUser(): Promise { const cookieStore = await cookies() @@ -29,6 +30,7 @@ export async function getCurrentUser(): Promise { ).get(sharedPayload.username) as UserPayload | undefined if (row) { db.prepare("UPDATE users SET last_active_at = datetime('now', '+8 hours') WHERE id = ?").run(row.id) + row.permissions = getUserPermissions(row.role) return row } // SSO 免登录:LLDAP 验证通过但本地无记录 → 自动创建(viewer 角色) @@ -38,7 +40,10 @@ export async function getCurrentUser(): Promise { const newRow = db.prepare( 'SELECT id, username, display_name, role FROM users WHERE username = ? AND is_active = 1' ).get(sharedPayload.username) as UserPayload | undefined - if (newRow) return newRow + if (newRow) { + newRow.permissions = getUserPermissions(newRow.role) + return newRow + } } } @@ -49,6 +54,7 @@ export async function getCurrentUser(): Promise { if (payload) { const db2 = getDb() db2.prepare("UPDATE users SET last_active_at = datetime('now', '+8 hours') WHERE id = ?").run(payload.id) + payload.permissions = getUserPermissions(payload.role) } return payload } @@ -58,7 +64,7 @@ export async function login(username: string, password: string) { const user = db.prepare('SELECT * FROM users WHERE username = ? AND is_active = 1').get(username) as any if (!user) return null if (!bcrypt.compareSync(password, user.password_hash)) return null - const payload: UserPayload = { id: user.id, username: user.username, display_name: user.display_name, role: user.role } + const payload: UserPayload = { id: user.id, username: user.username, display_name: user.display_name, role: user.role, permissions: getUserPermissions(user.role) } return { token: await createToken(payload), user: payload } } diff --git a/src/lib/jwt.ts b/src/lib/jwt.ts index e19c1db..4c9a13d 100644 --- a/src/lib/jwt.ts +++ b/src/lib/jwt.ts @@ -8,6 +8,7 @@ export interface UserPayload { username: string display_name: string role: string + permissions: string[] // 用户权限列表 } // Encode Uint8Array to base64url @@ -72,7 +73,7 @@ export async function verifyToken(token: string): Promise { const payload = JSON.parse(base64urlToStr(parts[1])) if (payload.exp && payload.exp < Math.floor(Date.now() / 1000)) return null if (payload.id == null) return null - return { id: payload.id, username: payload.username, display_name: payload.display_name, role: payload.role } + return { id: payload.id, username: payload.username, display_name: payload.display_name, role: payload.role, permissions: payload.permissions || [] } } catch { return null } diff --git a/src/lib/permissions.ts b/src/lib/permissions.ts index a6458b7..6513eb7 100644 --- a/src/lib/permissions.ts +++ b/src/lib/permissions.ts @@ -31,3 +31,15 @@ export function requirePermission(user: UserPayload | null, permission: string): if (!user) throw new Error('未登录') if (!hasPermission(user, permission)) throw new Error('权限不足') } + +export function getUserPermissions(role: string): string[] { + if (role === 'admin') return ['*'] + const db = getDb() + const row = db.prepare('SELECT permissions FROM roles WHERE name = ?').get(role) as { permissions: string } | undefined + if (!row) return [] + try { + return JSON.parse(row.permissions) + } catch { + return [] + } +}