import { Configuration } from 'oidc-provider'; import { RedisAdapter } from './redis-adapter'; import { prisma } from '@repo/db'; async function getClients() { const dbClients = await prisma.oidcClient.findMany?.(); const dbClientList = (dbClients && dbClients.length > 0) ? dbClients.map(c => ({ client_id: c.clientId, client_secret: c.clientSecret, grant_types: JSON.parse(c.grantTypes), // string -> string[] redirect_uris: JSON.parse(c.redirectUris), // string -> string[] response_types: JSON.parse(c.responseTypes), // string -> string[] scope: c.scope, })) : []; // 管理后台client,通过环境变量读取 const adminClient = { client_id: process.env.OIDC_CLIENT_ID || 'admin-client', client_secret: process.env.OIDC_CLIENT_SECRET || 'admin-secret', grant_types: ['authorization_code', 'refresh_token'], redirect_uris: [process.env.OIDC_REDIRECT_URI || 'http://localhost:3000/admin/callback'], response_types: ['code'], scope: 'openid email profile', }; // 检查是否与数据库client_id重复 const allClients = [adminClient, ...dbClientList.filter(c => c.client_id !== adminClient.client_id)]; return allClients; } const OIDC_COOKIE_KEY = process.env.OIDC_COOKIE_KEY || 'HrbEPlzByV0CcjFJhl2pjKV2iG8FgQIc'; const config: Configuration = { adapter: RedisAdapter, // 注意:clients字段现在是Promise,需在Provider初始化时await clients: await getClients(), pkce: { required: () => true, }, features: { devInteractions: { enabled: false }, resourceIndicators: { enabled: true }, revocation: { enabled: true }, userinfo: { enabled: true }, registration: { enabled: true }, }, cookies: { keys: [OIDC_COOKIE_KEY], }, jwks: [], ttl: { AccessToken: 3600, AuthorizationCode: 600, IdToken: 3600, RefreshToken: 1209600, BackchannelAuthenticationRequest: 600, ClientCredentials: 600, DeviceCode: 600, Grant: 1209600, Interaction: 3600, Session: 1209600, RegistrationAccessToken: 3600, DPoPProof: 300, PushedAuthorizationRequest: 600, ReplayDetection: 3600, LogoutToken: 600, }, findAccount: async (ctx, id) => { const user = await prisma.user.findUnique({ where: { id } }); if (!user) return undefined; return { accountId: user.id, async claims() { return { sub: user.id, email: user.email, name: user.name, }; }, }; }, }; export default config;