05262225
This commit is contained in:
parent
0e08e6ff2c
commit
a071d9575b
|
@ -37,3 +37,4 @@ npm-debug.log*
|
||||||
|
|
||||||
|
|
||||||
packages/db/generated
|
packages/db/generated
|
||||||
|
volumes
|
|
@ -1,39 +1,105 @@
|
||||||
import { Configuration } from 'oidc-provider';
|
import { Configuration } from 'oidc-provider';
|
||||||
import { nanoid } from 'nanoid';
|
|
||||||
import { RedisAdapter } from './redis-adapter';
|
import { RedisAdapter } from './redis-adapter';
|
||||||
|
import { prisma } from '@repo/db';
|
||||||
|
import { generateKeyPairSync } from 'crypto';
|
||||||
|
|
||||||
const config: Configuration = {
|
// 自动生成JWKS密钥对(如无环境变量则自动生成,建议持久化到安全存储)
|
||||||
adapter: RedisAdapter,
|
function getJWKS() {
|
||||||
clients: [
|
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 [
|
||||||
{
|
{
|
||||||
client_id: 'example-client',
|
client_id: process.env.OIDC_CLIENT_ID || 'example-client',
|
||||||
client_secret: 'example-secret',
|
client_secret: process.env.OIDC_CLIENT_SECRET || 'example-secret',
|
||||||
grant_types: ['authorization_code', 'refresh_token'],
|
grant_types: ['authorization_code', 'refresh_token'],
|
||||||
redirect_uris: ['http://localhost:3000/callback'],
|
redirect_uris: [process.env.OIDC_REDIRECT_URI || 'http://localhost:3000/callback'],
|
||||||
response_types: ['code'],
|
response_types: ['code'],
|
||||||
scope: 'openid email profile',
|
scope: 'openid email profile',
|
||||||
},
|
},
|
||||||
],
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
const OIDC_COOKIE_KEY = process.env.OIDC_COOKIE_KEY || 'default-cookie-key';
|
||||||
|
|
||||||
|
const config: Configuration = {
|
||||||
|
adapter: RedisAdapter,
|
||||||
|
// 注意:clients字段现在是Promise,需在Provider初始化时await
|
||||||
|
clients: await getClients(),
|
||||||
pkce: {
|
pkce: {
|
||||||
required: () => true, // 要求所有客户端使用PKCE
|
required: () => true,
|
||||||
},
|
},
|
||||||
features: {
|
features: {
|
||||||
devInteractions: { enabled: false }, // 禁用开发交互界面
|
devInteractions: { enabled: false },
|
||||||
resourceIndicators: { enabled: true }, // 启用资源指示器
|
resourceIndicators: { enabled: true },
|
||||||
revocation: { enabled: true }, // 启用令牌撤销
|
revocation: { enabled: true },
|
||||||
userinfo: { enabled: true }, // 启用用户信息端点
|
userinfo: { enabled: true },
|
||||||
|
registration: { enabled: true },
|
||||||
},
|
},
|
||||||
cookies: {
|
cookies: {
|
||||||
keys: [nanoid()], // 用于签署和验证cookie
|
keys: [OIDC_COOKIE_KEY],
|
||||||
},
|
},
|
||||||
jwks: {
|
jwks: {
|
||||||
keys: [], // 在实际环境中应该生成并保存密钥
|
keys: getJWKS(),
|
||||||
},
|
},
|
||||||
ttl: {
|
ttl: {
|
||||||
AccessToken: 3600, // 1小时
|
AccessToken: 3600,
|
||||||
AuthorizationCode: 600, // 10分钟
|
AuthorizationCode: 600,
|
||||||
IdToken: 3600, // 1小时
|
IdToken: 3600,
|
||||||
RefreshToken: 1209600, // 14天
|
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,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
};
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -4,7 +4,7 @@ import Redis from 'ioredis';
|
||||||
const redis = new Redis({
|
const redis = new Redis({
|
||||||
host: 'localhost', // 根据实际情况配置
|
host: 'localhost', // 根据实际情况配置
|
||||||
port: 6379,
|
port: 6379,
|
||||||
// password: 'yourpassword', // 如有需要
|
password: process.env.REDIS_PASSWORD
|
||||||
});
|
});
|
||||||
|
|
||||||
export default redis;
|
export default redis;
|
|
@ -0,0 +1,95 @@
|
||||||
|
/*
|
||||||
|
Warnings:
|
||||||
|
|
||||||
|
- You are about to drop the column `active` on the `oidc_clients` table. All the data in the column will be lost.
|
||||||
|
- You are about to drop the column `client_id` on the `oidc_clients` table. All the data in the column will be lost.
|
||||||
|
- You are about to drop the column `client_name` on the `oidc_clients` table. All the data in the column will be lost.
|
||||||
|
- You are about to drop the column `client_secret` on the `oidc_clients` table. All the data in the column will be lost.
|
||||||
|
- You are about to drop the column `client_uri` on the `oidc_clients` table. All the data in the column will be lost.
|
||||||
|
- You are about to drop the column `contacts` on the `oidc_clients` table. All the data in the column will be lost.
|
||||||
|
- You are about to drop the column `created_by` on the `oidc_clients` table. All the data in the column will be lost.
|
||||||
|
- You are about to drop the column `created_time` on the `oidc_clients` table. All the data in the column will be lost.
|
||||||
|
- You are about to drop the column `grant_types` on the `oidc_clients` table. All the data in the column will be lost.
|
||||||
|
- You are about to drop the column `jwks` on the `oidc_clients` table. All the data in the column will be lost.
|
||||||
|
- You are about to drop the column `jwks_uri` on the `oidc_clients` table. All the data in the column will be lost.
|
||||||
|
- You are about to drop the column `last_modified_time` on the `oidc_clients` table. All the data in the column will be lost.
|
||||||
|
- You are about to drop the column `logo_uri` on the `oidc_clients` table. All the data in the column will be lost.
|
||||||
|
- You are about to drop the column `policy_uri` on the `oidc_clients` table. All the data in the column will be lost.
|
||||||
|
- You are about to drop the column `post_logout_redirect_uris` on the `oidc_clients` table. All the data in the column will be lost.
|
||||||
|
- You are about to drop the column `redirect_uris` on the `oidc_clients` table. All the data in the column will be lost.
|
||||||
|
- You are about to drop the column `require_pkce` on the `oidc_clients` table. All the data in the column will be lost.
|
||||||
|
- You are about to drop the column `response_types` on the `oidc_clients` table. All the data in the column will be lost.
|
||||||
|
- You are about to drop the column `token_endpoint_auth_method` on the `oidc_clients` table. All the data in the column will be lost.
|
||||||
|
- You are about to drop the column `tos_uri` on the `oidc_clients` table. All the data in the column will be lost.
|
||||||
|
- You are about to drop the `oidc_authorization_codes` table. If the table is not empty, all the data it contains will be lost.
|
||||||
|
- You are about to drop the `oidc_consents` table. If the table is not empty, all the data it contains will be lost.
|
||||||
|
- You are about to drop the `oidc_key_pairs` table. If the table is not empty, all the data it contains will be lost.
|
||||||
|
- You are about to drop the `oidc_sessions` table. If the table is not empty, all the data it contains will be lost.
|
||||||
|
- You are about to drop the `oidc_tokens` table. If the table is not empty, all the data it contains will be lost.
|
||||||
|
- A unique constraint covering the columns `[clientId]` on the table `oidc_clients` will be added. If there are existing duplicate values, this will fail.
|
||||||
|
- Added the required column `clientId` to the `oidc_clients` table without a default value. This is not possible if the table is not empty.
|
||||||
|
- Added the required column `clientSecret` to the `oidc_clients` table without a default value. This is not possible if the table is not empty.
|
||||||
|
- Added the required column `grantTypes` to the `oidc_clients` table without a default value. This is not possible if the table is not empty.
|
||||||
|
- Added the required column `redirectUris` to the `oidc_clients` table without a default value. This is not possible if the table is not empty.
|
||||||
|
- Added the required column `responseTypes` to the `oidc_clients` table without a default value. This is not possible if the table is not empty.
|
||||||
|
- Added the required column `updatedAt` to the `oidc_clients` table without a default value. This is not possible if the table is not empty.
|
||||||
|
|
||||||
|
*/
|
||||||
|
-- DropForeignKey
|
||||||
|
ALTER TABLE "oidc_authorization_codes" DROP CONSTRAINT "oidc_authorization_codes_client_id_fkey";
|
||||||
|
|
||||||
|
-- DropForeignKey
|
||||||
|
ALTER TABLE "oidc_consents" DROP CONSTRAINT "oidc_consents_client_id_fkey";
|
||||||
|
|
||||||
|
-- DropForeignKey
|
||||||
|
ALTER TABLE "oidc_tokens" DROP CONSTRAINT "oidc_tokens_client_id_fkey";
|
||||||
|
|
||||||
|
-- DropIndex
|
||||||
|
DROP INDEX "oidc_clients_client_id_key";
|
||||||
|
|
||||||
|
-- AlterTable
|
||||||
|
ALTER TABLE "oidc_clients" DROP COLUMN "active",
|
||||||
|
DROP COLUMN "client_id",
|
||||||
|
DROP COLUMN "client_name",
|
||||||
|
DROP COLUMN "client_secret",
|
||||||
|
DROP COLUMN "client_uri",
|
||||||
|
DROP COLUMN "contacts",
|
||||||
|
DROP COLUMN "created_by",
|
||||||
|
DROP COLUMN "created_time",
|
||||||
|
DROP COLUMN "grant_types",
|
||||||
|
DROP COLUMN "jwks",
|
||||||
|
DROP COLUMN "jwks_uri",
|
||||||
|
DROP COLUMN "last_modified_time",
|
||||||
|
DROP COLUMN "logo_uri",
|
||||||
|
DROP COLUMN "policy_uri",
|
||||||
|
DROP COLUMN "post_logout_redirect_uris",
|
||||||
|
DROP COLUMN "redirect_uris",
|
||||||
|
DROP COLUMN "require_pkce",
|
||||||
|
DROP COLUMN "response_types",
|
||||||
|
DROP COLUMN "token_endpoint_auth_method",
|
||||||
|
DROP COLUMN "tos_uri",
|
||||||
|
ADD COLUMN "clientId" TEXT NOT NULL,
|
||||||
|
ADD COLUMN "clientSecret" TEXT NOT NULL,
|
||||||
|
ADD COLUMN "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
ADD COLUMN "grantTypes" TEXT NOT NULL,
|
||||||
|
ADD COLUMN "redirectUris" TEXT NOT NULL,
|
||||||
|
ADD COLUMN "responseTypes" TEXT NOT NULL,
|
||||||
|
ADD COLUMN "updatedAt" TIMESTAMP(3) NOT NULL;
|
||||||
|
|
||||||
|
-- DropTable
|
||||||
|
DROP TABLE "oidc_authorization_codes";
|
||||||
|
|
||||||
|
-- DropTable
|
||||||
|
DROP TABLE "oidc_consents";
|
||||||
|
|
||||||
|
-- DropTable
|
||||||
|
DROP TABLE "oidc_key_pairs";
|
||||||
|
|
||||||
|
-- DropTable
|
||||||
|
DROP TABLE "oidc_sessions";
|
||||||
|
|
||||||
|
-- DropTable
|
||||||
|
DROP TABLE "oidc_tokens";
|
||||||
|
|
||||||
|
-- CreateIndex
|
||||||
|
CREATE UNIQUE INDEX "oidc_clients_clientId_key" ON "oidc_clients"("clientId");
|
|
@ -1,3 +1,3 @@
|
||||||
# Please do not edit this file manually
|
# Please do not edit this file manually
|
||||||
# It should be added in your version-control system (i.e. Git)
|
# It should be added in your version-control system (e.g., Git)
|
||||||
provider = "postgresql"
|
provider = "postgresql"
|
|
@ -98,3 +98,17 @@ model UserLastVisit {
|
||||||
@@index([userId, resourceType])
|
@@index([userId, resourceType])
|
||||||
@@map("user_last_visit")
|
@@map("user_last_visit")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
model OidcClient {
|
||||||
|
id String @id @default(cuid())
|
||||||
|
clientId String @unique
|
||||||
|
clientSecret String
|
||||||
|
redirectUris String // 存储为JSON字符串
|
||||||
|
grantTypes String // 存储为JSON字符串
|
||||||
|
responseTypes String // 存储为JSON字符串
|
||||||
|
scope String
|
||||||
|
createdAt DateTime @default(now())
|
||||||
|
updatedAt DateTime @updatedAt
|
||||||
|
|
||||||
|
@@map("oidc_clients")
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue