做统一认证登录
This commit is contained in:
+47
-1
@@ -3,7 +3,7 @@
|
||||
*/
|
||||
import { request, requestRaw } from '@/api/request.js'
|
||||
|
||||
/** 账号密码登录 */
|
||||
/** 账号密码登录(旧:租户端直登) */
|
||||
export function login(data) {
|
||||
return request({
|
||||
url: '/app/login',
|
||||
@@ -12,6 +12,52 @@ export function login(data) {
|
||||
})
|
||||
}
|
||||
|
||||
/* ==================== 统一认证中心(UAC) ====================
|
||||
* APP 不走浏览器跳转,直接用密码直连模式:
|
||||
* POST /auth/login 拿 access + refresh,多企业时再调 switch-tenant。
|
||||
* 开关:VITE_AUTH_MODE=sso 时启用(见 utils/auth.js 的 isSSOEnabled)
|
||||
* ============================================================ */
|
||||
|
||||
/** 统一认证:账号密码登录 */
|
||||
export function loginUAC(data) {
|
||||
return request({
|
||||
url: '/auth/login',
|
||||
method: 'POST',
|
||||
data: Object.assign({ client_id: 'yz-uniapp' }, data)
|
||||
})
|
||||
}
|
||||
|
||||
/** 统一认证:选择/切换企业(一人多企业) */
|
||||
export function switchTenant(data) {
|
||||
return request({
|
||||
url: '/auth/switch-tenant',
|
||||
method: 'POST',
|
||||
data: Object.assign({ client_id: 'yz-uniapp' }, data)
|
||||
})
|
||||
}
|
||||
|
||||
/** 统一认证:刷新访问令牌 */
|
||||
export function refreshTokenUAC(data) {
|
||||
return request({
|
||||
url: '/auth/token',
|
||||
method: 'POST',
|
||||
header: { 'Content-Type': 'application/x-www-form-urlencoded' },
|
||||
data: Object.assign({ grant_type: 'refresh_token', client_id: 'yz-uniapp' }, data),
|
||||
silent: true
|
||||
})
|
||||
}
|
||||
|
||||
/** 统一认证:吊销令牌(登出) */
|
||||
export function revokeUAC(data = {}) {
|
||||
return request({
|
||||
url: '/auth/revoke',
|
||||
method: 'POST',
|
||||
data,
|
||||
silent: true,
|
||||
timeout: 5000
|
||||
})
|
||||
}
|
||||
|
||||
/** 发送登录验证码(账号二次校验用,需后台开启验证) */
|
||||
export function sendLoginCode(data) {
|
||||
return request({
|
||||
|
||||
+69
-2
@@ -2,7 +2,7 @@
|
||||
* 统一请求封装:baseURL、Bearer Token、业务 code 处理。
|
||||
* 接口地址统一从 .env 的 VITE_API_BASE_URL 读取(见 api/config.js)。
|
||||
*/
|
||||
import { getToken, logout } from '@/utils/auth.js'
|
||||
import { getToken, logout, isSSOEnabled, getRefreshToken, setAuthTokens } from '@/utils/auth.js'
|
||||
import { resolveBaseURL, getBaseURL } from '@/api/config.js'
|
||||
|
||||
export { getBaseURL }
|
||||
@@ -11,6 +11,63 @@ function buildFullUrl(url) {
|
||||
return resolveBaseURL().replace(/\/$/, '') + url
|
||||
}
|
||||
|
||||
/**
|
||||
* 用 refresh_token 换取新的访问令牌(独立封装,避免与 request 递归调用)。
|
||||
* 仅在统一认证模式(VITE_AUTH_MODE=sso)下使用。
|
||||
*/
|
||||
function refreshAccessToken() {
|
||||
return new Promise((resolve, reject) => {
|
||||
const refresh = getRefreshToken()
|
||||
if (!refresh) {
|
||||
reject(new Error('无刷新令牌'))
|
||||
return
|
||||
}
|
||||
uni.request({
|
||||
url: buildFullUrl('/auth/token'),
|
||||
method: 'POST',
|
||||
header: { 'Content-Type': 'application/x-www-form-urlencoded' },
|
||||
data: `grant_type=refresh_token&refresh_token=${encodeURIComponent(refresh)}&client_id=yz-uniapp`,
|
||||
timeout: 10000,
|
||||
success(res) {
|
||||
const body = res.data || {}
|
||||
if (res.statusCode === 200 && body.access_token) {
|
||||
setAuthTokens(body)
|
||||
resolve(body.access_token)
|
||||
} else {
|
||||
reject(new Error((body && (body.error || body.msg)) || '刷新失败'))
|
||||
}
|
||||
},
|
||||
fail: reject
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
/** 续期后重放原请求,返回与 request 一致的 data 解包结果 */
|
||||
async function replayRequest(options) {
|
||||
const token = await refreshAccessToken()
|
||||
const res = await new Promise((resolve, reject) => {
|
||||
uni.request({
|
||||
url: buildFullUrl(options.url),
|
||||
method: (options.method || 'GET').toUpperCase(),
|
||||
data: options.data || {},
|
||||
header: Object.assign(
|
||||
{ 'Content-Type': 'application/json', Authorization: `Bearer ${token}` },
|
||||
options.header || {}
|
||||
),
|
||||
timeout: options.timeout || 30000,
|
||||
success: (r) => resolve(r.data || {}),
|
||||
fail: reject
|
||||
})
|
||||
})
|
||||
if (typeof res.code !== 'undefined' && res.code !== 200) {
|
||||
const err = new Error(res.msg || '操作失败')
|
||||
err.code = res.code
|
||||
err.response = res
|
||||
throw err
|
||||
}
|
||||
return typeof res.data !== 'undefined' ? res.data : res
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {{ url: string, method?: string, data?: object, header?: object, silent?: boolean }} options
|
||||
* @returns {Promise<any>} 业务 data 字段(若无 data 则返回整包)
|
||||
@@ -35,11 +92,21 @@ export function request(options = {}) {
|
||||
data: data || {},
|
||||
header: headers,
|
||||
timeout,
|
||||
success(res) {
|
||||
async success(res) {
|
||||
const status = res.statusCode
|
||||
const body = res.data || {}
|
||||
|
||||
if (status === 401 || body.code === 401) {
|
||||
// 统一认证模式:先用 refresh_token 静默续期并重放请求,
|
||||
// 续期失败(令牌过期/被吊销/被踢下线)才真正登出。
|
||||
if (isSSOEnabled()) {
|
||||
try {
|
||||
resolve(await replayRequest(options))
|
||||
return
|
||||
} catch (e) {
|
||||
// 续期失败,继续走下面的登出流程
|
||||
}
|
||||
}
|
||||
logout()
|
||||
if (!silent) {
|
||||
uni.showToast({ title: body.msg || '请重新登录', icon: 'none' })
|
||||
|
||||
Reference in New Issue
Block a user