import type {InternalAxiosRequestConfig} from 'axios'; import {BaseService} from '@/lib/services/core'; import type { AuthSource, ChangePasswordRequest, ExternalAccountBinding, LoginRequest, OAuthAuthorizeResponse, OAuthCallbackRequest, OAuthCallbackResult, OAuthLoginUrlResponse, RegisterRequest, UpdateProfileRequest, User, } from './types'; /** * 认证服务 * 处理 OAuth 认证、用户信息获取、登出等 */ export class AuthService extends BaseService { protected static readonly basePath = '/api/v1'; /** * 获取 OAuth 登录 URL * @returns OAuth 授权 URL * @throws {ApiErrorBase} 当获取失败时 * * @example * ```typescript * const url = await AuthService.getLoginUrl(); * window.location.href = url; // 重定向到 OAuth 授权页面 * ``` */ static async getLoginUrl(): Promise { return this.get('/oauth/login'); } static async getAuthSources(): Promise { return this.get('/oauth/sources'); } static async getAuthorizeUrl(source: string, purpose: 'login' | 'bind' = 'login'): Promise { return this.get(`/oauth/${encodeURIComponent(source)}/authorize?purpose=${purpose}`); } /** * 处理 OAuth 回调 * @param request - OAuth 回调参数(state 和 code) * @throws {ApiErrorBase} 当回调处理失败时 * @throws {ValidationError} 当 state 无效时 * * @example * ```typescript * // 在回调页面获取 URL 参数 * const params = new URLSearchParams(window.location.search); * const state = params.get('state'); * const code = params.get('code'); * * if (state && code) { * await AuthService.handleCallback({ state, code }); * // 登录成功,跳转到首页 * router.push('/home'); * } * ``` */ static async handleCallback(request: OAuthCallbackRequest): Promise { return this.post('/oauth/callback', request); } /** * 获取当前登录用户信息 * @returns 用户信息 * @throws {UnauthorizedError} 当未登录时 * * @example * ```typescript * try { * const user = await AuthService.getUserInfo(); * console.log('当前用户:', user.username); * } catch (error) { * if (error instanceof UnauthorizedError) { * // 跳转到登录页 * router.push('/login'); * } * } * ``` */ static async getUserInfo(): Promise { return this.get('/user-info'); } /** * 用户登出 * @throws {ApiErrorBase} 当登出失败时 * * @example * ```typescript * await AuthService.logout(); * // 清除本地状态 * router.push('/login'); * ``` */ static async logout(): Promise { await this.get('/oauth/logout'); } static async login(request: LoginRequest, headers?: Record): Promise { return this.post('/user/login', request, headers ? ({ headers } as unknown as InternalAxiosRequestConfig) : undefined); } static async register(request: RegisterRequest, headers?: Record): Promise { return this.post('/user/register', request, headers ? ({ headers } as unknown as InternalAxiosRequestConfig) : undefined); } static async sendEmailCode(email: string, scene: 'register' | 'login', headers?: Record): Promise { return this.post('/user/send-email-code', { email, scene }, headers ? ({ headers } as unknown as InternalAxiosRequestConfig) : undefined); } static async changePassword(request: ChangePasswordRequest): Promise { return this.post('/user/change-password', request); } static async updateProfile(request: UpdateProfileRequest): Promise { return this.put('/user/profile', request); } static async getExternalAccountBindings(): Promise { return this.get('/oauth/external-accounts'); } static async deleteExternalAccountBinding(id: string): Promise { return this.post(`/oauth/external-accounts/${encodeURIComponent(id)}/delete`); } }