2025-06-28 17:07:18 +08:00

129 lines
3.4 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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