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';
|
2025-05-26 19:56:34 +08:00
|
|
|
|
|
2025-05-26 22:25:28 +08:00
|
|
|
|
async function getClients() {
|
|
|
|
|
const dbClients = await prisma.oidcClient.findMany?.();
|
2025-05-26 23:11:24 +08:00
|
|
|
|
const dbClientList = (dbClients && dbClients.length > 0)
|
|
|
|
|
? dbClients.map(c => ({
|
2025-05-26 22:25:28 +08:00
|
|
|
|
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,
|
2025-05-26 23:11:24 +08:00
|
|
|
|
}))
|
|
|
|
|
: [];
|
|
|
|
|
|
|
|
|
|
// 管理后台client,通过环境变量读取
|
2025-05-27 08:17:40 +08:00
|
|
|
|
const defaultClient = {
|
2025-05-26 23:11:24 +08:00
|
|
|
|
client_id: process.env.OIDC_CLIENT_ID || 'admin-client',
|
|
|
|
|
client_secret: process.env.OIDC_CLIENT_SECRET || 'admin-secret',
|
|
|
|
|
grant_types: ['authorization_code', 'refresh_token'],
|
2025-05-27 08:17:40 +08:00
|
|
|
|
redirect_uris: [process.env.OIDC_REDIRECT_URI || 'http://localhost:3000/callback'],
|
2025-05-26 23:11:24 +08:00
|
|
|
|
response_types: ['code'],
|
|
|
|
|
scope: 'openid email profile',
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// 检查是否与数据库client_id重复
|
2025-05-27 08:17:40 +08:00
|
|
|
|
const allClients = [defaultClient, ...dbClientList.filter(c => c.client_id !== defaultClient.client_id)];
|
2025-05-26 23:11:24 +08:00
|
|
|
|
|
|
|
|
|
return allClients;
|
2025-05-26 22:25:28 +08:00
|
|
|
|
}
|
|
|
|
|
|
2025-05-26 23:11:24 +08:00
|
|
|
|
const OIDC_COOKIE_KEY = process.env.OIDC_COOKIE_KEY || 'HrbEPlzByV0CcjFJhl2pjKV2iG8FgQIc';
|
2025-05-26 22:25:28 +08:00
|
|
|
|
|
|
|
|
|
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
|
|
|
|
},
|
2025-05-27 08:17:40 +08:00
|
|
|
|
jwks: {
|
|
|
|
|
keys: [
|
|
|
|
|
{
|
|
|
|
|
d: 'VEZOsY07JTFzGTqv6cC2Y32vsfChind2I_TTuvV225_-0zrSej3XLRg8iE_u0-3GSgiGi4WImmTwmEgLo4Qp3uEcxCYbt4NMJC7fwT2i3dfRZjtZ4yJwFl0SIj8TgfQ8ptwZbFZUlcHGXZIr4nL8GXyQT0CK8wy4COfmymHrrUoyfZA154ql_OsoiupSUCRcKVvZj2JHL2KILsq_sh_l7g2dqAN8D7jYfJ58MkqlknBMa2-zi5I0-1JUOwztVNml_zGrp27UbEU60RqV3GHjoqwI6m01U7K0a8Q_SQAKYGqgepbAYOA-P4_TLl5KC4-WWBZu_rVfwgSENwWNEhw8oQ',
|
|
|
|
|
dp: 'E1Y-SN4bQqX7kP-bNgZ_gEv-pixJ5F_EGocHKfS56jtzRqQdTurrk4jIVpI-ZITA88lWAHxjD-OaoJUh9Jupd_lwD5Si80PyVxOMI2xaGQiF0lbKJfD38Sh8frRpgelZVaK_gm834B6SLfxKdNsP04DsJqGKktODF_fZeaGFPH0',
|
|
|
|
|
dq: 'F90JPxevQYOlAgEH0TUt1-3_hyxY6cfPRU2HQBaahyWrtCWpaOzenKZnvGFZdg-BuLVKjCchq3G_70OLE-XDP_ol0UTJmDTT-WyuJQdEMpt_WFF9yJGoeIu8yohfeLatU-67ukjghJ0s9CBzNE_LrGEV6Cup3FXywpSYZAV3iqc',
|
|
|
|
|
e: 'AQAB',
|
|
|
|
|
kty: 'RSA',
|
|
|
|
|
n: 'xwQ72P9z9OYshiQ-ntDYaPnnfwG6u9JAdLMZ5o0dmjlcyrvwQRdoFIKPnO65Q8mh6F_LDSxjxa2Yzo_wdjhbPZLjfUJXgCzm54cClXzT5twzo7lzoAfaJlkTsoZc2HFWqmcri0BuzmTFLZx2Q7wYBm0pXHmQKF0V-C1O6NWfd4mfBhbM-I1tHYSpAMgarSm22WDMDx-WWI7TEzy2QhaBVaENW9BKaKkJklocAZCxk18WhR0fckIGiWiSM5FcU1PY2jfGsTmX505Ub7P5Dz75Ygqrutd5tFrcqyPAtPTFDk8X1InxkkUwpP3nFU5o50DGhwQolGYKPGtQ-ZtmbOfcWQ',
|
|
|
|
|
p: '5wC6nY6Ev5FqcLPCqn9fC6R9KUuBej6NaAVOKW7GXiOJAq2WrileGKfMc9kIny20zW3uWkRLm-O-3Yzze1zFpxmqvsvCxZ5ERVZ6leiNXSu3tez71ZZwp0O9gys4knjrI-9w46l_vFuRtjL6XEeFfHEZFaNJpz-lcnb3w0okrbM',
|
|
|
|
|
q: '3I1qeEDslZFB8iNfpKAdWtz_Wzm6-jayT_V6aIvhvMj5mnU-Xpj75zLPQSGa9wunMlOoZW9w1wDO1FVuDhwzeOJaTm-Ds0MezeC4U6nVGyyDHb4CUA3ml2tzt4yLrqGYMT7XbADSvuWYADHw79OFjEi4T3s3tJymhaBvy1ulv8M',
|
|
|
|
|
qi: 'wSbXte9PcPtr788e713KHQ4waE26CzoXx-JNOgN0iqJMN6C4_XJEX-cSvCZDf4rh7xpXN6SGLVd5ibIyDJi7bbi5EQ5AXjazPbLBjRthcGXsIuZ3AtQyR0CEWNSdM7EyM5TRdyZQ9kftfz9nI03guW3iKKASETqX2vh0Z8XRjyU',
|
|
|
|
|
use: 'sig',
|
|
|
|
|
}, {
|
|
|
|
|
crv: 'P-256',
|
|
|
|
|
d: 'K9xfPv773dZR22TVUB80xouzdF7qCg5cWjPjkHyv7Ws',
|
|
|
|
|
kty: 'EC',
|
|
|
|
|
use: 'sig',
|
|
|
|
|
x: 'FWZ9rSkLt6Dx9E3pxLybhdM6xgR5obGsj5_pqmnz5J4',
|
|
|
|
|
y: '_n8G69C-A2Xl4xUW2lF0i8ZGZnk_KPYrhv4GbTGu5G4',
|
|
|
|
|
},
|
|
|
|
|
],
|
|
|
|
|
},
|
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;
|