|
|
@ -1,9 +1,15 @@ |
|
|
import { request, isMockMode, toExpiresAt } from './http'; |
|
|
import { request, toExpiresAt } from './http'; |
|
|
import type { AppRole } from '../types'; |
|
|
import type { AppRole } from '../types'; |
|
|
|
|
|
|
|
|
/* ===================== 鉴权接口(真实后端) ===================== |
|
|
/* ===================== 鉴权接口(真实后端 · 不走 mock) ===================== |
|
|
* 落实规范第 4、5、6 节。全部走 http 层;匿名接口显式 auth:false。 |
|
|
* 落实规范第 4、5、6 节。全部走 http 层;匿名接口显式 auth:false。 |
|
|
* 客户端不提交 role / userId / verified / passwordHash(后端生成)。 |
|
|
* 客户端不提交 role / userId / verified / passwordHash(后端生成)。 |
|
|
|
|
|
* |
|
|
|
|
|
* 鉴权域已整体切真实后端(2026-09-30):短信网关、/auth/login、/auth/me、 |
|
|
|
|
|
* /auth/refresh、/auth/logout、/auth/identity/select、/auth/company/register |
|
|
|
|
|
* 均已接通。本文件函数不再受全局 isMockMode() 控制,永远走真实接口; |
|
|
|
|
|
* 业务域(api.ts 内未接通的接口)仍按 isMockMode 兜底 mock。 |
|
|
|
|
|
* 故 mockAuthTokens 辅助函数已删除——鉴权域不再有 mock 形态。 |
|
|
*/ |
|
|
*/ |
|
|
|
|
|
|
|
|
/** |
|
|
/** |
|
|
@ -75,12 +81,11 @@ function isValidPhone(phone: string): boolean { |
|
|
return /^1[3-9]\d{9}$/.test(phone); |
|
|
return /^1[3-9]\d{9}$/.test(phone); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
/** 发送短信验证码(§4 步骤1 / §6 步骤1) */ |
|
|
/** 发送短信验证码(§4 步骤1 / §6 步骤1):失败抛出,由 useSmsCode 在页面提示 */ |
|
|
export async function sendSmsCode(payload: SmsSendPayload): Promise<void> { |
|
|
export async function sendSmsCode(payload: SmsSendPayload): Promise<void> { |
|
|
if (!isValidPhone(payload.phone)) { |
|
|
if (!isValidPhone(payload.phone)) { |
|
|
throw new Error('手机号格式不正确'); |
|
|
throw new Error('手机号格式不正确'); |
|
|
} |
|
|
} |
|
|
if (isMockMode()) return; |
|
|
|
|
|
// 后端约束:/auth/sms/send 只接受 Query 参数(body 传参会被当作缺失)
|
|
|
// 后端约束:/auth/sms/send 只接受 Query 参数(body 传参会被当作缺失)
|
|
|
await request('/auth/sms/send', { |
|
|
await request('/auth/sms/send', { |
|
|
method: 'POST', |
|
|
method: 'POST', |
|
|
@ -99,16 +104,6 @@ export async function loginByPassword(payload: PasswordLoginPayload): Promise<Au |
|
|
if (!isValidPhone(payload.phone)) { |
|
|
if (!isValidPhone(payload.phone)) { |
|
|
throw new Error('手机号格式不正确'); |
|
|
throw new Error('手机号格式不正确'); |
|
|
} |
|
|
} |
|
|
if (isMockMode()) { |
|
|
|
|
|
const mock = mockAuthTokens(`pwd_${payload.phone}`); |
|
|
|
|
|
return { |
|
|
|
|
|
...mock, |
|
|
|
|
|
userId: 0, |
|
|
|
|
|
phone: payload.phone, |
|
|
|
|
|
nickname: 'Mock 用户', |
|
|
|
|
|
role: 'STUDENT', |
|
|
|
|
|
}; |
|
|
|
|
|
} |
|
|
|
|
|
const raw = await request<{ |
|
|
const raw = await request<{ |
|
|
userId: number; |
|
|
userId: number; |
|
|
phone: string; |
|
|
phone: string; |
|
|
@ -135,15 +130,6 @@ export async function loginByPassword(payload: PasswordLoginPayload): Promise<Au |
|
|
}; |
|
|
}; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
/** mock 形态下返回的双 Token(开发期不触网) */ |
|
|
|
|
|
function mockAuthTokens(nonce: string): AuthTokens { |
|
|
|
|
|
return { |
|
|
|
|
|
accessToken: `mock_access_${nonce}`, |
|
|
|
|
|
refreshToken: `mock_refresh_${nonce}`, |
|
|
|
|
|
expiresAt: Date.now() + 7 * 24 * 60 * 60 * 1000, |
|
|
|
|
|
}; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
export interface SmsLoginPayload { |
|
|
export interface SmsLoginPayload { |
|
|
phone: string; |
|
|
phone: string; |
|
|
code: string; |
|
|
code: string; |
|
|
@ -163,17 +149,6 @@ export async function loginBySms(payload: SmsLoginPayload): Promise<AuthLoginDat |
|
|
if (!isValidPhone(payload.phone)) { |
|
|
if (!isValidPhone(payload.phone)) { |
|
|
throw new Error('手机号格式不正确'); |
|
|
throw new Error('手机号格式不正确'); |
|
|
} |
|
|
} |
|
|
if (isMockMode()) { |
|
|
|
|
|
const mock = mockAuthTokens(`sms_${payload.phone}`); |
|
|
|
|
|
return { |
|
|
|
|
|
...mock, |
|
|
|
|
|
userId: 0, |
|
|
|
|
|
phone: payload.phone, |
|
|
|
|
|
nickname: 'Mock 用户', |
|
|
|
|
|
role: 'STUDENT', |
|
|
|
|
|
identitySelectionRequired: false, |
|
|
|
|
|
}; |
|
|
|
|
|
} |
|
|
|
|
|
const raw = await request<{ |
|
|
const raw = await request<{ |
|
|
userId: number; |
|
|
userId: number; |
|
|
phone: string; |
|
|
phone: string; |
|
|
@ -227,16 +202,6 @@ export interface CurrentUser { |
|
|
|
|
|
|
|
|
/** 拉取当前用户与角色(§4 步骤3):角色以后端为准并映射 */ |
|
|
/** 拉取当前用户与角色(§4 步骤3):角色以后端为准并映射 */ |
|
|
export async function fetchCurrentUser(): Promise<CurrentUser> { |
|
|
export async function fetchCurrentUser(): Promise<CurrentUser> { |
|
|
if (isMockMode()) { |
|
|
|
|
|
return { |
|
|
|
|
|
id: 'mock-user', |
|
|
|
|
|
role: 'candidate', |
|
|
|
|
|
phone: '', |
|
|
|
|
|
nickname: 'Mock 用户', |
|
|
|
|
|
verified: true, |
|
|
|
|
|
active: true, |
|
|
|
|
|
}; |
|
|
|
|
|
} |
|
|
|
|
|
const raw = await request<{ |
|
|
const raw = await request<{ |
|
|
id: number; |
|
|
id: number; |
|
|
role: BackendRole; |
|
|
role: BackendRole; |
|
|
@ -259,7 +224,6 @@ export async function fetchCurrentUser(): Promise<CurrentUser> { |
|
|
|
|
|
|
|
|
/** 退出登录(§4 步骤5):前端清会话由 AuthContext 负责,这里只通知后端 */ |
|
|
/** 退出登录(§4 步骤5):前端清会话由 AuthContext 负责,这里只通知后端 */ |
|
|
export async function requestLogout(): Promise<void> { |
|
|
export async function requestLogout(): Promise<void> { |
|
|
if (isMockMode()) return; |
|
|
|
|
|
await request('/auth/logout', { method: 'POST' }); |
|
|
await request('/auth/logout', { method: 'POST' }); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
@ -284,16 +248,6 @@ export async function registerCompany(payload: CompanyRegisterPayload): Promise< |
|
|
if (!isValidPhone(payload.phone)) { |
|
|
if (!isValidPhone(payload.phone)) { |
|
|
throw new Error('手机号格式不正确'); |
|
|
throw new Error('手机号格式不正确'); |
|
|
} |
|
|
} |
|
|
if (isMockMode()) { |
|
|
|
|
|
const mock = mockAuthTokens(`company_${payload.phone}`); |
|
|
|
|
|
return { |
|
|
|
|
|
...mock, |
|
|
|
|
|
userId: 0, |
|
|
|
|
|
phone: payload.phone, |
|
|
|
|
|
nickname: '企业用户', |
|
|
|
|
|
role: 'COMPANY', |
|
|
|
|
|
}; |
|
|
|
|
|
} |
|
|
|
|
|
const raw = await request<{ |
|
|
const raw = await request<{ |
|
|
userId: number; |
|
|
userId: number; |
|
|
companyId?: number; |
|
|
companyId?: number; |
|
|
@ -320,7 +274,6 @@ export interface RefreshTokenPayload { |
|
|
|
|
|
|
|
|
/** 用 Refresh Token 换取新凭证(旧 Refresh 立即失效) */ |
|
|
/** 用 Refresh Token 换取新凭证(旧 Refresh 立即失效) */ |
|
|
export async function refreshAuthToken(payload: RefreshTokenPayload): Promise<AuthTokens> { |
|
|
export async function refreshAuthToken(payload: RefreshTokenPayload): Promise<AuthTokens> { |
|
|
if (isMockMode()) return mockAuthTokens('refreshed'); |
|
|
|
|
|
const raw = await request<{ |
|
|
const raw = await request<{ |
|
|
accessToken: string; |
|
|
accessToken: string; |
|
|
refreshToken: string; |
|
|
refreshToken: string; |
|
|
@ -362,17 +315,6 @@ export interface IdentitySelectionResult extends AuthLoginData { |
|
|
* 首次成功撤销全部旧会话并返回新凭证;同身份重复请求只返回状态,不重复颁发凭证。 |
|
|
* 首次成功撤销全部旧会话并返回新凭证;同身份重复请求只返回状态,不重复颁发凭证。 |
|
|
*/ |
|
|
*/ |
|
|
export async function selectIdentity(payload: IdentitySelectionPayload): Promise<IdentitySelectionResult> { |
|
|
export async function selectIdentity(payload: IdentitySelectionPayload): Promise<IdentitySelectionResult> { |
|
|
if (isMockMode()) { |
|
|
|
|
|
const mock = mockAuthTokens('identity'); |
|
|
|
|
|
return { |
|
|
|
|
|
...mock, |
|
|
|
|
|
userId: 0, |
|
|
|
|
|
phone: '', |
|
|
|
|
|
nickname: 'Mock 用户', |
|
|
|
|
|
role: payload.identity, |
|
|
|
|
|
identitySelectionRequired: false, |
|
|
|
|
|
}; |
|
|
|
|
|
} |
|
|
|
|
|
const raw = await request<{ |
|
|
const raw = await request<{ |
|
|
userId: number; |
|
|
userId: number; |
|
|
role: BackendRole; |
|
|
role: BackendRole; |
|
|
|