请求与认证
XYGo Admin 2026-04-01 29 次阅读
tenantRequest 封装、API 命名空间与 JWT 鉴权机制
请求与认证
API 命名空间
租户端与平台端使用不同的 API 命名空间,互不干扰:
| 请求实例 | URL 前缀 | Token 方式 | 项目 |
|---|---|---|---|
adminRequest |
/admin |
Bearer Token(平台管理员) | web |
memberRequest |
/member |
Xy-User-Token(前台会员) | web |
siteRequest |
/site |
无 | web / web-tenant |
adminRequest(租户版) |
/tenant |
Bearer Token(租户管理员) | web-tenant |
租户前端中的 adminRequest 实际前缀为 /tenant(在 utils/http/index.ts 中配置),请求形如:
POST /tenant/auth/login
GET /tenant/menu/routes
GET /tenant/user/list
请求封装
租户端的 HTTP 封装位于 src/utils/http/,与主项目结构一致,但有以下差异:
1. 无 member 用户态
拦截器中不使用 useMemberStore,不注入 Xy-User-Token。租户端是纯管理后台,不处理前台会员登录状态。
2. 统一 Bearer Token
所有 /tenant/* 请求通过请求拦截器自动注入:
Authorization: Bearer <token>
Token 存储在 useUserStore 中,由 Pinia 持久化插件自动保存到 localStorage。
3. baseURL 配置
typescript
const { VITE_API_URL } = import.meta.env
const axiosInstance = axios.create({
timeout: 15000,
baseURL: VITE_API_URL // 开发环境: "/" 生产环境: "https://xxx.com"
})
站点信息接口
src/api/site.ts 用于获取站点基本信息(名称、Logo、主题等),使用公开的 /site/index 接口,无需 Token:
typescript
import { siteRequest } from '@/utils/http'
export function fetchSiteIndex() {
return siteRequest.get<SiteInfo>({ url: '/index' })
}
注意:
site.ts必须使用siteRequest(带/site前缀),不能用裸axios.get('/site/index'),否则生产环境中baseURL不会生效,请求会发到前端域名而非后端。
响应处理
响应拦截器的业务码处理与主项目一致:
| 业务码 | 含义 | 处理 |
|---|---|---|
| 0 | 成功 | 返回 data 字段 |
| -1 | 业务错误 | ElMessage 提示 |
| 61 | 未授权 | 清除 Token,跳转登录页(3 秒防抖) |
| 10010 | 被踢下线 | 弹窗提示 |
登录流程
用户访问 /tenant/login
→ 输入账号密码
→ POST /tenant/auth/login
→ 后端校验 xy_tenant_admin + 租户状态
→ 签发租户 JWT(含 TenantId + AdminId)
→ 前端存储 Token 到 useUserStore
→ 获取菜单 GET /tenant/menu/routes
→ 动态注册路由
→ 跳转到 /tenant/dashboard
请求示例
typescript
// api/backend/system/user.ts
import { adminRequest } from '@/utils/http'
export function fetchUserList(params: any) {
return adminRequest.get({ url: '/user/list', params })
// 实际请求: GET /tenant/user/list
}
export function fetchSaveUser(data: any) {
return adminRequest.post({ url: '/user/edit', params: data })
// 实际请求: POST /tenant/user/edit
}