129 lines
3.4 KiB
TypeScript
Raw Normal View History

2025-06-28 17:07:18 +08:00
import { twilioConfig } from '../config/twilio';
export interface TokenRequest {
identity: string;
roomName: string;
apiKey?: string;
apiSecret?: string;
}
export interface TokenResponse {
token: string;
identity: string;
roomName: string;
}
// 模拟Token生成服务
// 在实际生产环境中这应该是一个后端API服务
export class TokenService {
// 生成访问令牌
async generateAccessToken(request: TokenRequest): Promise<TokenResponse> {
try {
// 在实际应用中这里应该调用后端API
// 这里我们创建一个模拟的token
const mockToken = this.generateMockToken(request.identity, request.roomName);
return {
token: mockToken,
identity: request.identity,
roomName: request.roomName,
};
} catch (error) {
console.error('Error generating access token:', error);
throw new Error('Failed to generate access token');
}
}
// 生成模拟Token仅用于开发测试
private generateMockToken(identity: string, roomName: string): string {
// 这是一个简化的JWT模拟
// 实际应用中应该使用Twilio SDK在后端生成真实的token
const header = {
typ: 'JWT',
alg: 'HS256',
cty: 'twilio-fpa;v=1'
};
const payload = {
iss: twilioConfig.apiKey,
sub: twilioConfig.accountSid,
nbf: Math.floor(Date.now() / 1000),
exp: Math.floor(Date.now() / 1000) + 3600, // 1小时有效期
jti: `${twilioConfig.apiKey}-${Date.now()}`,
grants: {
identity: identity,
video: {
room: roomName
}
}
};
// 在实际应用中,这里应该用正确的签名算法
const encodedHeader = btoa(JSON.stringify(header));
const encodedPayload = btoa(JSON.stringify(payload));
const signature = btoa(`${twilioConfig.apiSecret}-signature`);
return `${encodedHeader}.${encodedPayload}.${signature}`;
}
// 验证Token模拟
validateToken(token: string): boolean {
try {
const parts = token.split('.');
if (parts.length !== 3) return false;
const payload = JSON.parse(atob(parts[1]));
const now = Math.floor(Date.now() / 1000);
return payload.exp > now;
} catch {
return false;
}
}
// 解析Token信息
parseToken(token: string): { identity: string; roomName: string } | null {
try {
const parts = token.split('.');
if (parts.length !== 3) return null;
const payload = JSON.parse(atob(parts[1]));
return {
identity: payload.grants?.identity || '',
roomName: payload.grants?.video?.room || '',
};
} catch {
return null;
}
}
}
export const tokenService = new TokenService();
// Express.js API端点示例如果需要真实的后端服务
export const createTokenEndpoint = () => {
return async (req: any, res: any) => {
try {
const { identity, roomName } = req.body;
if (!identity || !roomName) {
return res.status(400).json({
error: 'Identity and roomName are required'
});
}
const tokenResponse = await tokenService.generateAccessToken({
identity,
roomName,
});
res.json(tokenResponse);
} catch (error) {
console.error('Token generation error:', error);
res.status(500).json({
error: 'Failed to generate token'
});
}
};
};