diff --git a/Dockerfile b/Dockerfile index 8e6cc9d..bc1646a 100644 --- a/Dockerfile +++ b/Dockerfile @@ -19,6 +19,6 @@ RUN npm install --omit=dev && \ node_modules/@next/swc-linux-x64-musl COPY --from=builder /app/.next/static ./.next/static COPY --from=builder /app/public ./public -RUN mkdir -p /app/data /app/uploads +RUN apt-get update && apt-get install -y --no-install-recommends sqlite3 && rm -rf /var/lib/apt/lists/* && mkdir -p /app/data /app/uploads EXPOSE 3000 CMD ["sh", "-c", "HOSTNAME=0.0.0.0 node server.js"] diff --git a/src/app/api/internal/users/role/route.ts b/src/app/api/internal/users/role/route.ts new file mode 100644 index 0000000..84baf8f --- /dev/null +++ b/src/app/api/internal/users/role/route.ts @@ -0,0 +1,23 @@ +// PUT /api/internal/users/role — 供 OA 修改用户角色 +import { NextResponse } from 'next/server' +import { execFileSync } from 'child_process' + +const INTERNAL_KEY = process.env.INTERNAL_API_KEY || 'oa-internal-key-tlyq-2026' +const DB_PATH = process.env.DATABASE_PATH || '/app/data/assets.db' + +export async function PUT(request: Request) { + const key = request.headers.get('x-internal-key') + if (key !== INTERNAL_KEY) return NextResponse.json({ error: 'Forbidden' }, { status: 403 }) + + try { + const { username, role } = await request.json() + if (!username || !role) return NextResponse.json({ error: '参数不完整' }, { status: 400 }) + execFileSync('sqlite3', [DB_PATH], { + input: `UPDATE users SET role='${role}', updated_at=datetime('now', '+8 hours') WHERE username='${username}';`, + timeout: 3000, + }) + return NextResponse.json({ success: true }) + } catch { + return NextResponse.json({ error: '更新失败' }, { status: 500 }) + } +} diff --git a/src/middleware.ts b/src/middleware.ts index bbc504b..620f5c2 100644 --- a/src/middleware.ts +++ b/src/middleware.ts @@ -7,8 +7,9 @@ const cookieDomain = process.env.COOKIE_DOMAIN || '.tlyq.ai' export const middleware = createMiddlewareV2({ jwtSecret, cookieDomain, - allowedIssuers: ['*'], // 迁移模式 + allowedIssuers: ['*'], enableApiKey: true, + publicPaths: ['/login', '/api/auth', '/api/health', '/api/internal', '/_next', '/favicon.ico'], }) export const config = { matcher: ['/((?!_next/static|_next/image|favicon.ico|public).*)'] }