2025-05-26 19:56:34 +08:00
|
|
|
|
import { Configuration } from 'oidc-provider';
|
2025-05-26 21:57:05 +08:00
|
|
|
|
import { RedisAdapter } from './redis-adapter';
|
2025-05-26 22:25:28 +08:00
|
|
|
|
import { prisma } from '@repo/db';
|
|
|
|
|
import { generateKeyPairSync } from 'crypto';
|
2025-05-26 19:56:34 +08:00
|
|
|
|
|
2025-05-26 22:25:28 +08:00
|
|
|
|
// 自动生成JWKS密钥对(如无环境变量则自动生成,建议持久化到安全存储)
|
|
|
|
|
function getJWKS() {
|
|
|
|
|
if (process.env.OIDC_JWKS) {
|
|
|
|
|
return JSON.parse(process.env.OIDC_JWKS);
|
|
|
|
|
}
|
|
|
|
|
// 生成RSA密钥对
|
|
|
|
|
const { publicKey, privateKey } = generateKeyPairSync('rsa', {
|
|
|
|
|
modulusLength: 2048,
|
|
|
|
|
publicKeyEncoding: { type: 'spki', format: 'pem' },
|
|
|
|
|
privateKeyEncoding: { type: 'pkcs8', format: 'pem' },
|
|
|
|
|
});
|
|
|
|
|
// 转为JWK格式(这里只做简单转换,生产建议用jose等库)
|
|
|
|
|
const jwk = require('pem-jwk').pem2jwk(publicKey);
|
|
|
|
|
jwk.use = 'sig';
|
|
|
|
|
jwk.alg = 'RS256';
|
|
|
|
|
// 打印公钥,便于配置到前端或备份
|
|
|
|
|
console.log('自动生成的OIDC公钥JWK:', JSON.stringify(jwk, null, 2));
|
|
|
|
|
return [jwk];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 支持从数据库动态加载clients
|
|
|
|
|
async function getClients() {
|
|
|
|
|
const dbClients = await prisma.oidcClient.findMany?.();
|
|
|
|
|
if (dbClients && dbClients.length > 0) {
|
|
|
|
|
return 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,
|
|
|
|
|
}));
|
|
|
|
|
}
|
|
|
|
|
return [
|
2025-05-26 19:56:40 +08:00
|
|
|
|
{
|
2025-05-26 22:25:28 +08:00
|
|
|
|
client_id: process.env.OIDC_CLIENT_ID || 'example-client',
|
|
|
|
|
client_secret: process.env.OIDC_CLIENT_SECRET || 'example-secret',
|
2025-05-26 19:56:40 +08:00
|
|
|
|
grant_types: ['authorization_code', 'refresh_token'],
|
2025-05-26 22:25:28 +08:00
|
|
|
|
redirect_uris: [process.env.OIDC_REDIRECT_URI || 'http://localhost:3000/callback'],
|
2025-05-26 19:56:40 +08:00
|
|
|
|
response_types: ['code'],
|
|
|
|
|
scope: 'openid email profile',
|
|
|
|
|
},
|
2025-05-26 22:25:28 +08:00
|
|
|
|
];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const OIDC_COOKIE_KEY = process.env.OIDC_COOKIE_KEY || 'default-cookie-key';
|
|
|
|
|
|
|
|
|
|
const config: Configuration = {
|
|
|
|
|
adapter: RedisAdapter,
|
|
|
|
|
// 注意:clients字段现在是Promise,需在Provider初始化时await
|
|
|
|
|
clients: await getClients(),
|
2025-05-26 19:56:40 +08:00
|
|
|
|
pkce: {
|
2025-05-26 22:25:28 +08:00
|
|
|
|
required: () => true,
|
2025-05-26 19:56:40 +08:00
|
|
|
|
},
|
|
|
|
|
features: {
|
2025-05-26 22:25:28 +08:00
|
|
|
|
devInteractions: { enabled: false },
|
|
|
|
|
resourceIndicators: { enabled: true },
|
|
|
|
|
revocation: { enabled: true },
|
|
|
|
|
userinfo: { enabled: true },
|
|
|
|
|
registration: { enabled: true },
|
2025-05-26 19:56:40 +08:00
|
|
|
|
},
|
|
|
|
|
cookies: {
|
2025-05-26 22:25:28 +08:00
|
|
|
|
keys: [OIDC_COOKIE_KEY],
|
2025-05-26 19:56:40 +08:00
|
|
|
|
},
|
|
|
|
|
jwks: {
|
2025-05-26 22:25:28 +08:00
|
|
|
|
keys: getJWKS(),
|
2025-05-26 19:56:40 +08:00
|
|
|
|
},
|
|
|
|
|
ttl: {
|
2025-05-26 22:25:28 +08:00
|
|
|
|
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,
|
|
|
|
|
};
|
|
|
|
|
},
|
|
|
|
|
};
|
2025-05-26 19:56:40 +08:00
|
|
|
|
},
|
2025-05-26 19:56:34 +08:00
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
export default config;
|