144 lines
4.6 KiB
TypeScript
144 lines
4.6 KiB
TypeScript
![]() |
import { OIDCProvider } from '../src/provider';
|
|||
|
import { MemoryStorageAdapter } from '../src/storage/memory';
|
|||
|
import type { OIDCProviderConfig, OIDCUser, OIDCClient } from '../src/types';
|
|||
|
|
|||
|
// 示例:带有zod验证的OIDC Provider使用
|
|||
|
|
|||
|
// 创建存储适配器
|
|||
|
const storage = new MemoryStorageAdapter();
|
|||
|
|
|||
|
// 示例用户查找函数
|
|||
|
const findUser = async (userId: string): Promise<OIDCUser | null> => {
|
|||
|
const users: Record<string, OIDCUser> = {
|
|||
|
'user123': {
|
|||
|
sub: 'user123',
|
|||
|
username: 'john@example.com',
|
|||
|
email: 'john@example.com',
|
|||
|
email_verified: true,
|
|||
|
name: 'John Doe',
|
|||
|
given_name: 'John',
|
|||
|
family_name: 'Doe',
|
|||
|
}
|
|||
|
};
|
|||
|
return users[userId] || null;
|
|||
|
};
|
|||
|
|
|||
|
// 示例客户端查找函数
|
|||
|
const findClient = async (clientId: string): Promise<OIDCClient | null> => {
|
|||
|
const clients: Record<string, OIDCClient> = {
|
|||
|
'demo-client': {
|
|||
|
client_id: 'demo-client',
|
|||
|
client_secret: 'demo-secret',
|
|||
|
client_name: 'Demo Application',
|
|||
|
client_type: 'confidential',
|
|||
|
redirect_uris: ['https://app.example.com/callback'],
|
|||
|
grant_types: ['authorization_code', 'refresh_token'],
|
|||
|
response_types: ['code'],
|
|||
|
scopes: ['openid', 'profile', 'email'],
|
|||
|
created_at: new Date(),
|
|||
|
updated_at: new Date(),
|
|||
|
}
|
|||
|
};
|
|||
|
return clients[clientId] || null;
|
|||
|
};
|
|||
|
|
|||
|
// 密码验证器
|
|||
|
const passwordValidator = async (username: string, password: string): Promise<string | null> => {
|
|||
|
// 这里应该实现真实的密码验证逻辑
|
|||
|
if (username === 'john@example.com' && password === 'password123') {
|
|||
|
return 'user123'; // 返回用户ID
|
|||
|
}
|
|||
|
return null;
|
|||
|
};
|
|||
|
|
|||
|
// 配置OIDC Provider
|
|||
|
const config: OIDCProviderConfig = {
|
|||
|
issuer: 'https://auth.example.com',
|
|||
|
signingKey: 'your-secret-key-for-development-only',
|
|||
|
signingAlgorithm: 'HS256',
|
|||
|
storage,
|
|||
|
findUser,
|
|||
|
findClient,
|
|||
|
authConfig: {
|
|||
|
passwordValidator,
|
|||
|
sessionTTL: 3600, // 1小时
|
|||
|
pageConfig: {
|
|||
|
title: 'My Auth Server',
|
|||
|
brandName: 'Example Corp',
|
|||
|
logoUrl: 'https://example.com/logo.png',
|
|||
|
},
|
|||
|
rememberMeMaxAge: 30 * 24 * 3600, // 30天
|
|||
|
},
|
|||
|
tokenTTL: {
|
|||
|
accessToken: 3600, // 1小时
|
|||
|
refreshToken: 30 * 24 * 3600, // 30天
|
|||
|
authorizationCode: 600, // 10分钟
|
|||
|
idToken: 3600, // 1小时
|
|||
|
},
|
|||
|
enablePKCE: true,
|
|||
|
requirePKCE: true, // 对公共客户端强制要求PKCE
|
|||
|
rotateRefreshTokens: true,
|
|||
|
};
|
|||
|
|
|||
|
// 创建OIDC Provider实例
|
|||
|
const provider = new OIDCProvider(config);
|
|||
|
|
|||
|
// 导出配置好的provider
|
|||
|
export { provider };
|
|||
|
|
|||
|
// 使用示例:
|
|||
|
// 1. 授权请求会自动使用zod验证所有参数
|
|||
|
// 2. 令牌请求会验证FormData和Basic认证头
|
|||
|
// 3. 用户信息请求会验证Bearer token格式
|
|||
|
// 4. 令牌撤销和内省请求会验证相应的参数
|
|||
|
|
|||
|
// 错误处理示例:
|
|||
|
export const handleAuthorizationExample = async (query: Record<string, string>) => {
|
|||
|
try {
|
|||
|
// 这会触发zod验证
|
|||
|
const result = await provider.handleAuthorizationRequest({
|
|||
|
response_type: query.response_type,
|
|||
|
client_id: query.client_id,
|
|||
|
redirect_uri: query.redirect_uri,
|
|||
|
scope: query.scope,
|
|||
|
state: query.state,
|
|||
|
// ... 其他参数
|
|||
|
});
|
|||
|
|
|||
|
if (result.success) {
|
|||
|
console.log('授权码:', result.code);
|
|||
|
} else {
|
|||
|
console.error('授权失败:', result.error);
|
|||
|
}
|
|||
|
} catch (error) {
|
|||
|
if (error instanceof Error && error.message.includes('授权请求参数无效')) {
|
|||
|
console.error('参数验证失败:', error.message);
|
|||
|
} else {
|
|||
|
console.error('未知错误:', error);
|
|||
|
}
|
|||
|
}
|
|||
|
};
|
|||
|
|
|||
|
// 令牌请求示例
|
|||
|
export const handleTokenExample = async (formData: FormData) => {
|
|||
|
try {
|
|||
|
// 这会触发zod验证FormData
|
|||
|
const result = await provider.handleTokenRequest({
|
|||
|
grant_type: formData.get('grant_type')?.toString() || '',
|
|||
|
client_id: formData.get('client_id')?.toString() || '',
|
|||
|
// ... 其他参数会被自动验证
|
|||
|
});
|
|||
|
|
|||
|
if (result.success) {
|
|||
|
console.log('访问令牌:', result.response.access_token);
|
|||
|
} else {
|
|||
|
console.error('令牌请求失败:', result.error);
|
|||
|
}
|
|||
|
} catch (error) {
|
|||
|
if (error instanceof Error && error.message.includes('令牌请求参数无效')) {
|
|||
|
console.error('参数验证失败:', error.message);
|
|||
|
} else {
|
|||
|
console.error('未知错误:', error);
|
|||
|
}
|
|||
|
}
|
|||
|
};
|