feat(zulip): Add Zulip account management and integrate with auth system

- Add ZulipAccountsEntity, repository, and module for persistent Zulip account storage
- Create ZulipAccountService in core layer for managing Zulip account lifecycle
- Integrate Zulip account creation into login flow via LoginService
- Add comprehensive test suite for Zulip account creation during user registration
- Create quick test script for validating registered user Zulip integration
- Update UsersEntity to support Zulip account associations
- Update auth module to include Zulip and ZulipAccounts dependencies
- Fix WebSocket connection protocol from ws:// to wss:// in API documentation
- Enhance LoginCoreService to coordinate Zulip account provisioning during authentication
This commit is contained in:
angjustinl
2026-01-05 17:41:54 +08:00
parent fcb81f80d9
commit 2b87eac495
14 changed files with 2698 additions and 38 deletions

View File

@@ -31,6 +31,7 @@ import {
IZulipClientPoolService,
IZulipConfigService,
} from '../../core/zulip/interfaces/zulip-core.interfaces';
import { ApiKeySecurityService } from '../../core/zulip/services/api_key_security.service';
/**
* 玩家登录请求接口
@@ -114,6 +115,7 @@ export class ZulipService {
private readonly eventProcessor: ZulipEventProcessorService,
@Inject('ZULIP_CONFIG_SERVICE')
private readonly configManager: IZulipConfigService,
private readonly apiKeySecurityService: ApiKeySecurityService,
) {
this.logger.log('ZulipService初始化完成');
@@ -321,36 +323,38 @@ export class ZulipService {
// 从Token中提取用户ID模拟
const userId = `user_${token.substring(0, 8)}`;
// 为测试用户提供真实的 Zulip API Key
// 从ApiKeySecurityService获取真实的Zulip API Key
let zulipApiKey = undefined;
let zulipEmail = undefined;
// 检查是否是配置了真实 Zulip API Key 的测试用户
const hasTestApiKey = token.includes('lCPWCPf');
const hasUserApiKey = token.includes('W2KhXaQx');
const hasOldApiKey = token.includes('MZ1jEMQo');
const isRealUserToken = token === 'real_user_token_with_zulip_key_123';
this.logger.log('Token检查', {
operation: 'validateGameToken',
userId,
tokenPrefix: token.substring(0, 20),
hasUserApiKey,
hasOldApiKey,
isRealUserToken,
});
if (isRealUserToken || hasUserApiKey || hasTestApiKey || hasOldApiKey) {
// 使用用户的真实 API Key
// 注意这个API Key对应的Zulip用户邮箱是 user8@zulip.xinghangee.icu
zulipApiKey = 'lCPWCPfGh7WUHxwN56GF8oYXOpqNfGF8';
zulipEmail = 'angjustinl@mail.angforever.top';
try {
// 尝试从Redis获取存储的API Key
const apiKeyResult = await this.apiKeySecurityService.getApiKey(userId);
this.logger.log('配置真实Zulip API Key', {
if (apiKeyResult.success && apiKeyResult.apiKey) {
zulipApiKey = apiKeyResult.apiKey;
// TODO: 从数据库获取用户的Zulip邮箱
// 暂时使用模拟数据
zulipEmail = 'angjustinl@163.com';
this.logger.log('从存储获取到Zulip API Key', {
operation: 'validateGameToken',
userId,
hasApiKey: true,
zulipEmail,
});
} else {
this.logger.debug('用户没有存储的Zulip API Key', {
operation: 'validateGameToken',
userId,
});
}
} catch (error) {
const err = error as Error;
this.logger.warn('获取Zulip API Key失败', {
operation: 'validateGameToken',
userId,
zulipEmail,
hasApiKey: true,
error: err.message,
});
}
@@ -358,7 +362,6 @@ export class ZulipService {
userId,
username: `Player_${userId.substring(5, 10)}`,
email: `${userId}@example.com`,
// 实际项目中从数据库获取
zulipEmail,
zulipApiKey,
};