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);
|
||
}
|
||
}
|
||
};
|