feat(image): 新建 knowai-core:1.0.0 镜像并完成推送
Some checks reported errors
continuous-integration/drone/push Build was killed
Some checks reported errors
continuous-integration/drone/push Build was killed
- 搭建 api、auth、utils 等逻辑模块 - 通过 tsc、eslint、vitest 测试验证 BREAKING CHANGE: 新镜像分支
This commit is contained in:
217
auth/README.md
Normal file
217
auth/README.md
Normal file
@@ -0,0 +1,217 @@
|
||||
# 认证模块
|
||||
|
||||
## 概述
|
||||
|
||||
认证模块提供基于Session的认证机制,支持用户登录、注册、登出和会话管理功能。该模块采用适配器模式,支持多种存储方式(Cookie、LocalStorage、内存),以适应不同的运行环境(浏览器、SSR等)。
|
||||
|
||||
## 核心组件
|
||||
|
||||
### 1. 认证服务 (AuthService)
|
||||
|
||||
`AuthService` 接口定义了认证相关的核心功能:
|
||||
|
||||
- `login(credentials)`: 用户登录
|
||||
- `register(userData)`: 用户注册
|
||||
- `logout()`: 用户登出
|
||||
- `isAuthenticated()`: 检查是否已认证
|
||||
- `getCurrentUser()`: 获取当前用户信息
|
||||
- `refreshSession()`: 刷新会话
|
||||
- `getSession()`: 获取会话信息
|
||||
|
||||
### 2. 会话管理器 (SessionManager)
|
||||
|
||||
`SessionManager` 负责管理用户会话状态,包括:
|
||||
|
||||
- 会话的创建、验证、刷新和清除
|
||||
- 用户信息的获取和缓存
|
||||
- 会话状态的持久化存储
|
||||
|
||||
### 3. 存储适配器 (StorageAdapter)
|
||||
|
||||
`StorageAdapter` 提供统一的存储接口,支持多种存储方式:
|
||||
|
||||
- `CookieStorageAdapter`: 使用Cookie存储,适用于SSR环境
|
||||
- `LocalStorageAdapter`: 使用浏览器LocalStorage存储
|
||||
- `MemoryStorageAdapter`: 使用内存存储,适用于测试或临时会话
|
||||
|
||||
### 4. 事件管理器 (EventManager)
|
||||
|
||||
`EventManager` 负责管理认证相关事件:
|
||||
|
||||
- 登录事件 (`login`)
|
||||
- 注册事件 (`register`)
|
||||
- 登出事件 (`logout`)
|
||||
- 错误事件 (`error`)
|
||||
|
||||
### 5. 类型定义
|
||||
|
||||
模块包含完整的TypeScript类型定义,确保类型安全。
|
||||
|
||||
## 使用方法
|
||||
|
||||
### 基本使用
|
||||
|
||||
```typescript
|
||||
import { authService } from '@/auth';
|
||||
|
||||
// 用户登录
|
||||
const loginResult = await authService.login({
|
||||
username: 'user@example.com',
|
||||
password: 'password123'
|
||||
});
|
||||
|
||||
if (loginResult.success) {
|
||||
console.log('登录成功', loginResult.data);
|
||||
} else {
|
||||
console.error('登录失败', loginResult.error);
|
||||
}
|
||||
|
||||
// 检查认证状态
|
||||
if (await authService.isAuthenticated()) {
|
||||
// 获取当前用户信息
|
||||
const userResult = await authService.getCurrentUser();
|
||||
if (userResult.success) {
|
||||
console.log('当前用户:', userResult.data);
|
||||
}
|
||||
}
|
||||
|
||||
// 用户登出
|
||||
await authService.logout();
|
||||
```
|
||||
|
||||
### 测试环境使用
|
||||
|
||||
```typescript
|
||||
import { getAuthService, resetAuthService } from '@/auth';
|
||||
|
||||
// 在测试前重置服务实例
|
||||
resetAuthService();
|
||||
|
||||
// 获取新的服务实例
|
||||
const authService = getAuthService();
|
||||
```
|
||||
|
||||
### 自定义存储方式
|
||||
|
||||
```typescript
|
||||
import { createStorageAdapter } from '@/auth';
|
||||
|
||||
// 创建自定义存储适配器
|
||||
const customStorage = createStorageAdapter('localStorage');
|
||||
|
||||
// 注意:当前版本使用单例模式,自定义存储需要修改auth-service.ts中的实现
|
||||
```
|
||||
|
||||
### 使用自定义存储适配器
|
||||
|
||||
```typescript
|
||||
import { createAuthService, createStorageAdapter } from '@/auth';
|
||||
|
||||
// 创建自定义Cookie存储适配器
|
||||
const cookieStorage = createStorageAdapter('cookie', {
|
||||
domain: '.example.com',
|
||||
secure: true,
|
||||
httpOnly: false,
|
||||
sameSite: 'strict'
|
||||
});
|
||||
|
||||
// 使用自定义存储适配器
|
||||
const authService = createAuthService(undefined, cookieStorage);
|
||||
```
|
||||
|
||||
### 事件监听
|
||||
|
||||
```typescript
|
||||
import { createAuthService, createEventManager } from '@/auth';
|
||||
|
||||
const eventManager = createEventManager();
|
||||
const authService = createAuthService();
|
||||
|
||||
// 监听登录事件
|
||||
eventManager.on('login', (data) => {
|
||||
console.log('用户登录:', data.user);
|
||||
});
|
||||
|
||||
// 监听登出事件
|
||||
eventManager.on('logout', () => {
|
||||
console.log('用户已登出');
|
||||
});
|
||||
```
|
||||
|
||||
## 会话管理
|
||||
|
||||
### 会话存储
|
||||
|
||||
会话信息通过StorageAdapter存储,默认使用Cookie存储,以支持SSR环境。会话信息包括:
|
||||
|
||||
- `sessionId`: 会话ID
|
||||
- `userId`: 用户ID
|
||||
- `expiresAt`: 过期时间
|
||||
- `createdAt`: 创建时间
|
||||
|
||||
### 会话验证
|
||||
|
||||
SessionManager会自动验证会话的有效性:
|
||||
|
||||
1. 检查本地是否存在会话ID
|
||||
2. 验证会话是否过期
|
||||
3. 向服务器验证会话有效性
|
||||
4. 自动刷新过期会话
|
||||
|
||||
### 会话刷新
|
||||
|
||||
当会话即将过期时,SessionManager会自动尝试刷新会话:
|
||||
|
||||
1. 使用当前会话ID请求刷新
|
||||
2. 更新本地存储的会话信息
|
||||
3. 清除缓存的用户信息,下次获取时重新请求
|
||||
|
||||
## API端点
|
||||
|
||||
认证模块需要以下API端点:
|
||||
|
||||
- `POST /auth/login`: 用户登录
|
||||
- `POST /auth/register`: 用户注册
|
||||
- `POST /auth/logout`: 用户登出
|
||||
- `GET /auth/session/:sessionId`: 获取会话信息
|
||||
- `POST /auth/session/refresh`: 刷新会话
|
||||
- `GET /auth/user/:userId`: 获取用户信息
|
||||
|
||||
## 设计模式
|
||||
|
||||
认证模块采用以下设计模式:
|
||||
|
||||
1. **适配器模式**: 通过StorageAdapter接口支持多种存储方式
|
||||
2. **工厂模式**: 提供createAuthService等工厂函数简化实例创建
|
||||
3. **观察者模式**: 通过EventManager实现事件发布订阅
|
||||
4. **策略模式**: 不同存储方式采用不同策略
|
||||
|
||||
## 安全考虑
|
||||
|
||||
1. **会话安全**: 使用HttpOnly Cookie存储会话ID,防止XSS攻击
|
||||
2. **CSRF防护**: 通过SameSite Cookie属性防止CSRF攻击
|
||||
3. **会话过期**: 设置合理的会话过期时间,并支持自动刷新
|
||||
4. **HTTPS**: 在生产环境中使用HTTPS传输敏感数据
|
||||
|
||||
## SSR支持
|
||||
|
||||
认证模块完全支持SSR环境:
|
||||
|
||||
1. 默认使用Cookie存储,可在服务器端读取
|
||||
2. 提供统一的StorageAdapter接口,可针对不同环境实现
|
||||
3. 会话状态可在服务器和客户端之间同步
|
||||
|
||||
## 测试
|
||||
|
||||
认证模块包含完整的单元测试,覆盖:
|
||||
|
||||
- 会话管理功能
|
||||
- 存储适配器功能
|
||||
- 认证服务功能
|
||||
- 错误处理
|
||||
|
||||
运行测试:
|
||||
|
||||
```bash
|
||||
npm test auth
|
||||
```
|
||||
170
auth/auth-service.ts
Normal file
170
auth/auth-service.ts
Normal file
@@ -0,0 +1,170 @@
|
||||
/**
|
||||
* 认证服务实现
|
||||
* 集成事件管理、会话管理和存储适配器功能
|
||||
* 完全实现AuthService接口定义
|
||||
*/
|
||||
import type { ApiClient } from '@/api/types';
|
||||
import type { User } from '@/types';
|
||||
import type {
|
||||
AuthService,
|
||||
AuthEventType
|
||||
} from './types';
|
||||
import type {
|
||||
LoginRequest,
|
||||
LoginResponse,
|
||||
RegisterRequest,
|
||||
RegisterResponse
|
||||
} from '@/types/user';
|
||||
import { AuthError } from './errors';
|
||||
import { authEventManager } from './event-manager';
|
||||
import { createSessionManager } from './session-manager';
|
||||
import { createStorageAdapter } from './storage-adapter';
|
||||
|
||||
/**
|
||||
* 默认认证服务实现
|
||||
*/
|
||||
export class DefaultAuthService implements AuthService {
|
||||
private readonly apiClient: ApiClient;
|
||||
private readonly sessionManager: ReturnType<typeof createSessionManager>;
|
||||
private readonly storage: ReturnType<typeof createStorageAdapter>;
|
||||
|
||||
constructor(apiClient: ApiClient) {
|
||||
this.apiClient = apiClient;
|
||||
this.storage = createStorageAdapter('memory');
|
||||
this.sessionManager = createSessionManager(apiClient, this.storage);
|
||||
}
|
||||
|
||||
/**
|
||||
* 用户登录
|
||||
* @param credentials 登录凭证
|
||||
* @returns 登录响应,包含用户信息和会话ID
|
||||
*/
|
||||
async login(credentials: LoginRequest): Promise<LoginResponse> {
|
||||
try {
|
||||
const response = await this.apiClient.post<LoginResponse>('/auth/login', credentials);
|
||||
|
||||
// 触发登录成功事件
|
||||
authEventManager.emit('login', response.user);
|
||||
|
||||
// 更新会话管理器中的用户信息
|
||||
await this.sessionManager.getUserInfo();
|
||||
|
||||
return response;
|
||||
} catch (error) {
|
||||
throw AuthError.loginFailed('Login failed', error);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 用户注册
|
||||
* @param userData 注册数据
|
||||
* @returns 注册响应,包含用户信息和会话ID
|
||||
*/
|
||||
async register(userData: RegisterRequest): Promise<RegisterResponse> {
|
||||
try {
|
||||
const response = await this.apiClient.post<RegisterResponse>('/auth/register', userData);
|
||||
|
||||
// 触发注册成功事件
|
||||
authEventManager.emit('register', response.user);
|
||||
|
||||
// 更新会话管理器中的用户信息
|
||||
await this.sessionManager.getUserInfo();
|
||||
|
||||
return response;
|
||||
} catch (error) {
|
||||
throw AuthError.registerFailed('Registration failed', error);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 用户登出
|
||||
* 调用服务器端登出API,清除会话
|
||||
*/
|
||||
async logout(): Promise<void> {
|
||||
try {
|
||||
// 调用服务器端登出API
|
||||
await this.apiClient.post('/auth/logout');
|
||||
|
||||
// 清除本地缓存
|
||||
this.sessionManager.clearCache();
|
||||
|
||||
// 触发登出事件
|
||||
authEventManager.emit('logout');
|
||||
} catch (error) {
|
||||
// 即使API调用失败,也要清除本地状态
|
||||
this.sessionManager.clearCache();
|
||||
throw AuthError.logoutFailed('Logout failed', error);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前用户信息
|
||||
* @returns 当前用户信息
|
||||
*/
|
||||
async getCurrentUser(): Promise<User> {
|
||||
try {
|
||||
const user = await this.sessionManager.getUserInfo();
|
||||
if (!user) {
|
||||
throw AuthError.notAuthenticated();
|
||||
}
|
||||
return user;
|
||||
} catch (error) {
|
||||
// 如果已经是AuthError,直接抛出
|
||||
if (error instanceof AuthError) {
|
||||
throw error;
|
||||
}
|
||||
throw AuthError.userNotFound('Failed to get current user', error);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查用户是否已认证
|
||||
* @returns 是否已认证
|
||||
*/
|
||||
async isAuthenticated(): Promise<boolean> {
|
||||
try {
|
||||
return await this.sessionManager.isAuthenticated();
|
||||
} catch (error) {
|
||||
// 如果已经是AuthError,直接抛出
|
||||
if (error instanceof AuthError) {
|
||||
throw error;
|
||||
}
|
||||
throw AuthError.unknown('Authentication check failed', error);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加认证事件监听器
|
||||
* @param event 事件类型
|
||||
* @param listener 事件监听器
|
||||
*/
|
||||
on(event: AuthEventType, listener: (...args: unknown[]) => void): void {
|
||||
authEventManager.on(event, listener);
|
||||
}
|
||||
|
||||
/**
|
||||
* 移除认证事件监听器
|
||||
* @param event 事件类型
|
||||
* @param listener 事件监听器
|
||||
*/
|
||||
off(event: AuthEventType, listener: (...args: unknown[]) => void): void {
|
||||
authEventManager.off(event, listener);
|
||||
}
|
||||
|
||||
/**
|
||||
* 清除本地缓存
|
||||
* 不影响服务器端session
|
||||
*/
|
||||
clearCache(): void {
|
||||
this.sessionManager.clearCache();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建认证服务实例
|
||||
* @param apiClient API客户端
|
||||
* @returns 认证服务实例
|
||||
*/
|
||||
export function createAuthService(apiClient: ApiClient): AuthService {
|
||||
return new DefaultAuthService(apiClient);
|
||||
}
|
||||
67
auth/errors.ts
Normal file
67
auth/errors.ts
Normal file
@@ -0,0 +1,67 @@
|
||||
/**
|
||||
* 认证模块错误处理
|
||||
*/
|
||||
|
||||
/**
|
||||
* 认证错误类
|
||||
*/
|
||||
export class AuthError extends Error {
|
||||
public readonly code: string;
|
||||
public readonly details: unknown;
|
||||
|
||||
constructor(code: string, message: string, details?: unknown) {
|
||||
super(message);
|
||||
this.name = 'AuthError';
|
||||
this.code = code;
|
||||
this.details = details;
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建登录失败错误
|
||||
*/
|
||||
static loginFailed(message: string, details?: unknown): AuthError {
|
||||
return new AuthError('LOGIN_FAILED', message, details);
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建登出失败错误
|
||||
*/
|
||||
static logoutFailed(message: string, details?: unknown): AuthError {
|
||||
return new AuthError('LOGOUT_FAILED', message, details);
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建注册失败错误
|
||||
*/
|
||||
static registerFailed(message: string, details?: unknown): AuthError {
|
||||
return new AuthError('REGISTER_FAILED', message, details);
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建用户未找到错误
|
||||
*/
|
||||
static userNotFound(message: string, details?: unknown): AuthError {
|
||||
return new AuthError('USER_NOT_FOUND', message, details);
|
||||
}
|
||||
|
||||
/**
|
||||
* Session过期
|
||||
*/
|
||||
static sessionExpired(message: string, details?: unknown): AuthError {
|
||||
return new AuthError('SESSION_EXPIRED', message, details);
|
||||
}
|
||||
|
||||
/**
|
||||
* Session未认证
|
||||
*/
|
||||
static notAuthenticated(message: string = 'User not authenticated', details?: unknown): AuthError {
|
||||
return new AuthError('NOT_AUTHENTICATED', message, details);
|
||||
}
|
||||
|
||||
/**
|
||||
* 通用未知报错
|
||||
*/
|
||||
static unknown(message: string = 'Unknown authentication error', details?: unknown): AuthError {
|
||||
return new AuthError('UNKNOWN', message, details);
|
||||
}
|
||||
}
|
||||
65
auth/event-manager.ts
Normal file
65
auth/event-manager.ts
Normal file
@@ -0,0 +1,65 @@
|
||||
/**
|
||||
* 认证事件管理器
|
||||
* 管理认证相关的事件监听和触发
|
||||
*/
|
||||
import type { AuthEventType, AuthEventListener } from './types';
|
||||
import { AuthError } from './errors';
|
||||
|
||||
/**
|
||||
* 认证事件管理器
|
||||
*/
|
||||
export class AuthEventManager {
|
||||
private listeners: Map<AuthEventType, AuthEventListener[]> = new Map();
|
||||
|
||||
/**
|
||||
* 添加事件监听器
|
||||
*/
|
||||
on(event: AuthEventType, listener: AuthEventListener): void {
|
||||
if (!this.listeners.has(event)) {
|
||||
this.listeners.set(event, []);
|
||||
}
|
||||
const eventListeners = this.listeners.get(event);
|
||||
if (eventListeners) {
|
||||
eventListeners.push(listener);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 移除事件监听器
|
||||
*/
|
||||
off(event: AuthEventType, listener: AuthEventListener): void {
|
||||
const eventListeners = this.listeners.get(event);
|
||||
if (eventListeners) {
|
||||
const index = eventListeners.indexOf(listener);
|
||||
if (index !== -1) {
|
||||
eventListeners.splice(index, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 触发事件
|
||||
*/
|
||||
emit(event: AuthEventType, ...args: unknown[]): void {
|
||||
const eventListeners = this.listeners.get(event);
|
||||
if (eventListeners) {
|
||||
eventListeners.forEach(listener => {
|
||||
try {
|
||||
listener(...args);
|
||||
} catch (error) {
|
||||
throw AuthError.unknown(`Error in auth event listener for ${event}`, error);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 清除所有监听器
|
||||
*/
|
||||
clear(): void {
|
||||
this.listeners.clear();
|
||||
}
|
||||
}
|
||||
|
||||
// 创建全局事件管理器实例
|
||||
export const authEventManager = new AuthEventManager();
|
||||
22
auth/index.ts
Normal file
22
auth/index.ts
Normal file
@@ -0,0 +1,22 @@
|
||||
/**
|
||||
* 认证模块入口文件
|
||||
*/
|
||||
|
||||
// 导出类型定义
|
||||
export type {
|
||||
AuthEventType,
|
||||
AuthEventListener,
|
||||
StorageAdapter,
|
||||
AuthService,
|
||||
SessionManager
|
||||
} from './types';
|
||||
|
||||
// 导出实现类
|
||||
export { DefaultAuthService } from './auth-service';
|
||||
export { DefaultSessionManager } from './session-manager';
|
||||
export { AuthEventManager, authEventManager } from './event-manager';
|
||||
export { MemoryStorageAdapter, createStorageAdapter } from './storage-adapter';
|
||||
|
||||
// 导出工厂函数
|
||||
export { createAuthService } from './auth-service';
|
||||
export { createSessionManager } from './session-manager';
|
||||
92
auth/session-manager.ts
Normal file
92
auth/session-manager.ts
Normal file
@@ -0,0 +1,92 @@
|
||||
/**
|
||||
* 会话管理器
|
||||
* 负责查询用户认证状态,不主动管理session
|
||||
* session完全由服务器端控制,前端只通过API查询状态
|
||||
*/
|
||||
import type { ApiClient } from '@/api/types';
|
||||
import type { User } from '@/types';
|
||||
import type { StorageAdapter } from './types';
|
||||
import { authEventManager } from './event-manager';
|
||||
|
||||
export class DefaultSessionManager {
|
||||
private readonly apiClient: ApiClient;
|
||||
private readonly storage: StorageAdapter;
|
||||
private currentUser: User | null = null;
|
||||
|
||||
constructor(apiClient: ApiClient, storage: StorageAdapter) {
|
||||
this.apiClient = apiClient;
|
||||
this.storage = storage;
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查是否已认证
|
||||
* 通过API调用验证用户认证状态,而不是直接访问cookie
|
||||
* @returns 是否已认证
|
||||
*/
|
||||
async isAuthenticated(): Promise<boolean> {
|
||||
try {
|
||||
// 通过调用API验证认证状态
|
||||
await this.getUserInfo();
|
||||
return true;
|
||||
} catch (error) {
|
||||
// 如果认证失败,触发session_expired事件
|
||||
authEventManager.emit('session_expired', error);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前用户信息
|
||||
* 幂等操作,每次都从服务器获取最新用户信息
|
||||
* @returns 用户信息
|
||||
* @throws 当获取用户信息失败时抛出错误
|
||||
*/
|
||||
async getUserInfo(): Promise<User> {
|
||||
try {
|
||||
// API客户端的get方法已经返回解构后的数据,不需要访问.data
|
||||
const response = await this.apiClient.get<{ user: User }>('/auth/me');
|
||||
this.currentUser = response.user;
|
||||
// 如果成功获取用户信息,触发session_authenticated事件
|
||||
authEventManager.emit('session_authenticated', this.currentUser);
|
||||
return this.currentUser;
|
||||
} catch (error) {
|
||||
this.currentUser = null;
|
||||
// 如果获取用户信息失败,触发session_expired事件
|
||||
authEventManager.emit('session_expired', error);
|
||||
// 抛出错误,让调用者处理
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 清除本地缓存
|
||||
* 不影响服务器端session,只清除前端缓存
|
||||
*/
|
||||
clearCache(): void {
|
||||
this.currentUser = null;
|
||||
// 清除存储适配器中的所有项(如果支持)
|
||||
if ('clear' in this.storage && typeof this.storage.clear === 'function') {
|
||||
this.storage.clear();
|
||||
} else {
|
||||
// 如果不支持clear方法,逐个删除已知项
|
||||
const keys = ['user_preferences', 'ui_state']; // 示例键
|
||||
keys.forEach(key => this.storage.removeItem(key));
|
||||
}
|
||||
// 触发session_logout事件
|
||||
authEventManager.emit('session_logout');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建会话管理器
|
||||
* @param apiClient API客户端
|
||||
* @param storage 存储适配器,仅用于非敏感数据缓存
|
||||
* @returns 会话管理器实例
|
||||
*/
|
||||
export function createSessionManager(
|
||||
apiClient: ApiClient,
|
||||
storage: StorageAdapter
|
||||
): DefaultSessionManager {
|
||||
return new DefaultSessionManager(apiClient, storage);
|
||||
}
|
||||
|
||||
55
auth/storage-adapter.ts
Normal file
55
auth/storage-adapter.ts
Normal file
@@ -0,0 +1,55 @@
|
||||
/**
|
||||
* 存储适配器接口
|
||||
* 提供统一的存储接口,用于非敏感数据的临时存储
|
||||
* 注意:此存储适配器不用于session管理,session完全由服务器端控制
|
||||
*/
|
||||
import type { StorageAdapter } from './types';
|
||||
|
||||
/**
|
||||
* 内存存储适配器
|
||||
* 适用于非敏感数据的临时存储,如UI状态、用户偏好设置等
|
||||
*/
|
||||
export class MemoryStorageAdapter implements StorageAdapter {
|
||||
private storage: Record<string, string> = {};
|
||||
|
||||
getItem(key: string): string | null {
|
||||
return this.storage[key] || null;
|
||||
}
|
||||
|
||||
setItem(key: string, value: string): void {
|
||||
this.storage[key] = value;
|
||||
}
|
||||
|
||||
removeItem(key: string): void {
|
||||
delete this.storage[key];
|
||||
}
|
||||
|
||||
/**
|
||||
* 清空所有存储项
|
||||
*/
|
||||
clear(): void {
|
||||
this.storage = {};
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取所有存储键
|
||||
* @returns 存储键数组
|
||||
*/
|
||||
keys(): string[] {
|
||||
return Object.keys(this.storage);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建存储适配器
|
||||
* @param type 存储类型,目前只支持memory
|
||||
* @returns 存储适配器实例
|
||||
*/
|
||||
export function createStorageAdapter(type: 'memory' = 'memory'): StorageAdapter {
|
||||
switch (type) {
|
||||
case 'memory':
|
||||
return new MemoryStorageAdapter();
|
||||
default:
|
||||
return new MemoryStorageAdapter();
|
||||
}
|
||||
}
|
||||
85
auth/types.d.ts
vendored
Normal file
85
auth/types.d.ts
vendored
Normal file
@@ -0,0 +1,85 @@
|
||||
/**
|
||||
* 认证模块类型定义
|
||||
*/
|
||||
|
||||
import type { AxiosRequestConfig } from 'axios';
|
||||
import type { User } from '@/types';
|
||||
import type {
|
||||
LoginRequest,
|
||||
LoginResponse,
|
||||
RegisterRequest,
|
||||
RegisterResponse
|
||||
} from '@/types/user';
|
||||
|
||||
// 事件类型定义
|
||||
export type AuthEventType = 'login' | 'logout' | 'register' | 'session_expired' | 'session_authenticated' | 'session_logout';
|
||||
|
||||
// 事件监听器类型
|
||||
export type AuthEventListener = (...args: unknown[]) => void;
|
||||
|
||||
// 存储适配器接口 - 仅用于非敏感数据存储,不涉及session管理
|
||||
export interface StorageAdapter {
|
||||
/**
|
||||
* 获取存储项
|
||||
* @param key 存储键
|
||||
* @returns 存储值或null
|
||||
*/
|
||||
getItem(key: string): string | null;
|
||||
|
||||
/**
|
||||
* 设置存储项
|
||||
* @param key 存储键
|
||||
* @param value 存储值
|
||||
*/
|
||||
setItem(key: string, value: string): void;
|
||||
|
||||
/**
|
||||
* 删除存储项
|
||||
* @param key 存储键
|
||||
*/
|
||||
removeItem(key: string): void;
|
||||
|
||||
/**
|
||||
* 清空所有存储项
|
||||
*/
|
||||
clear(): void;
|
||||
|
||||
/**
|
||||
* 获取所有存储键
|
||||
* @returns 存储键数组
|
||||
*/
|
||||
keys(): string[];
|
||||
}
|
||||
|
||||
// 认证服务接口
|
||||
export interface AuthService {
|
||||
login(credentials: LoginRequest): Promise<LoginResponse>;
|
||||
register(userData: RegisterRequest): Promise<RegisterResponse>;
|
||||
logout(): Promise<void>;
|
||||
getCurrentUser(): Promise<User>;
|
||||
isAuthenticated(): Promise<boolean>; // 改为异步,通过getUser验证
|
||||
|
||||
// 事件管理方法
|
||||
on(event: AuthEventType, listener: AuthEventListener): void;
|
||||
off(event: AuthEventType, listener: AuthEventListener): void;
|
||||
|
||||
// 会话管理方法
|
||||
clearCache(): void;
|
||||
}
|
||||
|
||||
// 会话管理器接口 - 仅作为状态查询器,不主动管理session
|
||||
export interface SessionManager {
|
||||
// 通过getUser验证用户认证状态,而不是直接访问cookie
|
||||
isAuthenticated(): Promise<boolean>;
|
||||
// 获取当前用户信息,幂等操作
|
||||
getUserInfo(): Promise<User | null>;
|
||||
// 清除本地缓存,不影响服务器端session
|
||||
clearCache(): void;
|
||||
}
|
||||
|
||||
// 扩展 Axios 请求配置以支持认证选项
|
||||
declare module 'axios' {
|
||||
interface AxiosRequestConfig {
|
||||
skipAuth?: boolean;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user