fenghuo/packages/oidc-provider/src/auth/token-manager.ts

205 lines
7.0 KiB
TypeScript

import type {
AuthorizationCode,
AccessToken,
RefreshToken,
IDToken,
} from '../types';
import type { StorageAdapter } from '../storage';
/**
* 令牌管理器
* 处理所有令牌相关的存储业务逻辑
*/
export class TokenManager {
constructor(private storage: StorageAdapter) { }
// 生成存储键
private getTokenKey(type: string, token: string): string {
return `${type}:${token}`;
}
private getUserClientKey(type: string, userId: string, clientId: string): string {
return `${type}:user:${userId}:client:${clientId}`;
}
// 授权码管理
async storeAuthorizationCode(authCode: AuthorizationCode): Promise<void> {
const key = this.getTokenKey('auth_code', authCode.code);
const ttl = Math.floor((authCode.expires_at.getTime() - Date.now()) / 1000);
const data = {
...authCode,
expires_at: authCode.expires_at.toISOString(),
created_at: authCode.created_at.toISOString(),
};
await this.storage.set(key, data, Math.max(ttl, 1));
}
async getAuthorizationCode(code: string): Promise<AuthorizationCode | null> {
const key = this.getTokenKey('auth_code', code);
const data = await this.storage.get(key);
if (!data) return null;
return {
...data,
expires_at: new Date(data.expires_at),
created_at: new Date(data.created_at),
};
}
async deleteAuthorizationCode(code: string): Promise<void> {
const key = this.getTokenKey('auth_code', code);
await this.storage.delete(key);
}
// 访问令牌管理
async storeAccessToken(token: AccessToken): Promise<void> {
const key = this.getTokenKey('access_token', token.token);
const userClientKey = this.getUserClientKey('access_tokens', token.user_id, token.client_id);
const ttl = Math.floor((token.expires_at.getTime() - Date.now()) / 1000);
const data = {
...token,
expires_at: token.expires_at.toISOString(),
created_at: token.created_at.toISOString(),
};
// 存储令牌数据
await this.storage.set(key, data, Math.max(ttl, 1));
// 存储用户-客户端索引
const existingTokens = await this.storage.get<string[]>(userClientKey) || [];
existingTokens.push(token.token);
await this.storage.set(userClientKey, existingTokens, Math.max(ttl, 1));
}
async getAccessToken(token: string): Promise<AccessToken | null> {
const key = this.getTokenKey('access_token', token);
const data = await this.storage.get(key);
if (!data) return null;
return {
...data,
expires_at: new Date(data.expires_at),
created_at: new Date(data.created_at),
};
}
async deleteAccessToken(token: string): Promise<void> {
const key = this.getTokenKey('access_token', token);
// 获取令牌数据以清理索引
const tokenData = await this.storage.get(key);
if (tokenData) {
const userClientKey = this.getUserClientKey('access_tokens', tokenData.user_id, tokenData.client_id);
const tokens = await this.storage.get<string[]>(userClientKey) || [];
const filteredTokens = tokens.filter(t => t !== token);
if (filteredTokens.length > 0) {
await this.storage.set(userClientKey, filteredTokens);
} else {
await this.storage.delete(userClientKey);
}
}
await this.storage.delete(key);
}
async deleteAccessTokensByUserAndClient(userId: string, clientId: string): Promise<void> {
const userClientKey = this.getUserClientKey('access_tokens', userId, clientId);
const tokens = await this.storage.get<string[]>(userClientKey) || [];
// 删除所有相关令牌
for (const token of tokens) {
await this.storage.delete(this.getTokenKey('access_token', token));
}
// 删除索引
await this.storage.delete(userClientKey);
}
// 刷新令牌管理
async storeRefreshToken(token: RefreshToken): Promise<void> {
const key = this.getTokenKey('refresh_token', token.token);
const userClientKey = this.getUserClientKey('refresh_tokens', token.user_id, token.client_id);
const ttl = Math.floor((token.expires_at.getTime() - Date.now()) / 1000);
const data = {
...token,
expires_at: token.expires_at.toISOString(),
created_at: token.created_at.toISOString(),
};
// 存储令牌数据
await this.storage.set(key, data, Math.max(ttl, 1));
// 存储用户-客户端索引
const existingTokens = await this.storage.get<string[]>(userClientKey) || [];
existingTokens.push(token.token);
await this.storage.set(userClientKey, existingTokens, Math.max(ttl, 1));
}
async getRefreshToken(token: string): Promise<RefreshToken | null> {
const key = this.getTokenKey('refresh_token', token);
const data = await this.storage.get(key);
if (!data) return null;
return {
...data,
expires_at: new Date(data.expires_at),
created_at: new Date(data.created_at),
};
}
async deleteRefreshToken(token: string): Promise<void> {
const key = this.getTokenKey('refresh_token', token);
// 获取令牌数据以清理索引
const tokenData = await this.storage.get(key);
if (tokenData) {
const userClientKey = this.getUserClientKey('refresh_tokens', tokenData.user_id, tokenData.client_id);
const tokens = await this.storage.get<string[]>(userClientKey) || [];
const filteredTokens = tokens.filter(t => t !== token);
if (filteredTokens.length > 0) {
await this.storage.set(userClientKey, filteredTokens);
} else {
await this.storage.delete(userClientKey);
}
}
await this.storage.delete(key);
}
// ID令牌管理
async storeIDToken(token: IDToken): Promise<void> {
const key = this.getTokenKey('id_token', token.token);
const ttl = Math.floor((token.expires_at.getTime() - Date.now()) / 1000);
const data = {
...token,
expires_at: token.expires_at.toISOString(),
created_at: token.created_at.toISOString(),
};
await this.storage.set(key, data, Math.max(ttl, 1));
}
async getIDToken(token: string): Promise<IDToken | null> {
const key = this.getTokenKey('id_token', token);
const data = await this.storage.get(key);
if (!data) return null;
return {
...data,
expires_at: new Date(data.expires_at),
created_at: new Date(data.created_at),
};
}
async deleteIDToken(token: string): Promise<void> {
const key = this.getTokenKey('id_token', token);
await this.storage.delete(key);
}
}