181 lines
4.6 KiB
JavaScript
181 lines
4.6 KiB
JavaScript
import { validateCredentials } from './validate-credentials.js'
|
|
import { buildEncryptedLoginBody } from './login-rsa.js'
|
|
import { get, post } from './request.js'
|
|
import {
|
|
getToken,
|
|
getRefreshToken,
|
|
isLoggedIn,
|
|
getUser,
|
|
clearSession,
|
|
saveSession,
|
|
updateStoredUser,
|
|
forceRelogin,
|
|
setReturnUrl,
|
|
takeReturnUrl
|
|
} from './auth-session.js'
|
|
|
|
export { validateCredentials }
|
|
export {
|
|
getToken,
|
|
getRefreshToken,
|
|
isLoggedIn,
|
|
getUser,
|
|
clearSession,
|
|
updateStoredUser,
|
|
forceRelogin,
|
|
setReturnUrl,
|
|
takeReturnUrl
|
|
}
|
|
|
|
/**
|
|
* 拉取当前用户资料并写回本地(含职位、部门)。
|
|
* @returns {Promise<object|null>}
|
|
*/
|
|
export async function fetchCurrentUser() {
|
|
const token = getToken()
|
|
if (!token) return null
|
|
const data = await get('/web/auth/current-user', {
|
|
Authorization: 'Bearer ' + token
|
|
})
|
|
if (data) {
|
|
const prev = getUser() || {}
|
|
const merged = Object.assign({}, prev, data)
|
|
updateStoredUser(merged)
|
|
return merged
|
|
}
|
|
return null
|
|
}
|
|
|
|
/**
|
|
* 可选:清除历史 mock_ 前缀假会话,避免误判已登录。
|
|
*/
|
|
export function clearLegacyMockSessionIfNeeded() {
|
|
const token = getToken()
|
|
if (typeof token === 'string' && token.indexOf('mock_') === 0) {
|
|
clearSession()
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 真实账号密码登录。
|
|
* @param {{ username: string, password: string }} params
|
|
*/
|
|
export async function passwordLogin({ username, password }) {
|
|
const v = validateCredentials(username, password)
|
|
if (!v.ok) {
|
|
const err = new Error(v.message)
|
|
err.code = v.code
|
|
throw err
|
|
}
|
|
const body = await buildEncryptedLoginBody(
|
|
(username || '').trim(),
|
|
password || ''
|
|
)
|
|
const data = await post('/web/auth/login', body)
|
|
if (!data || !data.token) {
|
|
throw new Error('登录失败')
|
|
}
|
|
saveSession({
|
|
token: data.token,
|
|
refreshToken: data.refreshToken,
|
|
userInfo: data.userInfo
|
|
})
|
|
// 密码登录成功后静默绑定微信(失败不影响登录)
|
|
bindWechatQuietly()
|
|
return data
|
|
}
|
|
|
|
/**
|
|
* 微信授权登录(openid 优先;未绑定需 phoneCode)。
|
|
*/
|
|
export async function wechatLogin({ loginCode, phoneCode }) {
|
|
const payload = { loginCode }
|
|
if (phoneCode) {
|
|
payload.phoneCode = phoneCode
|
|
}
|
|
const data = await post('/mini/auth/wechat-login', payload)
|
|
if (!data || !data.token) {
|
|
throw new Error('登录失败')
|
|
}
|
|
saveSession({
|
|
token: data.token,
|
|
refreshToken: data.refreshToken,
|
|
userInfo: data.userInfo
|
|
})
|
|
return data
|
|
}
|
|
|
|
/**
|
|
* 网页扫码登录:标记会话已扫码(供 PC 端轮询展示「已扫码」)。
|
|
* @param {string} sessionId 完整 sessionId 或小程序码 scene(短码)
|
|
*/
|
|
export async function webQrScanned(sessionId) {
|
|
return post('/mini/auth/web-qr-scanned', { sessionId })
|
|
}
|
|
|
|
/**
|
|
* 网页扫码登录:授权手机号并确认(不写本地会话,仅完成 PC 端登录)。
|
|
* @param {{ sessionId: string, loginCode: string, phoneCode: string }} params
|
|
*/
|
|
export async function webQrConfirm({ sessionId, loginCode, phoneCode }) {
|
|
return post('/mini/auth/web-qr-confirm', {
|
|
sessionId,
|
|
loginCode,
|
|
phoneCode
|
|
})
|
|
}
|
|
|
|
/**
|
|
* 深链无 JWT 时静默换票(仅 loginCode,后端按已绑 openid 签发)。
|
|
*/
|
|
export async function silentWechatLogin() {
|
|
const loginRes = await new Promise((resolve, reject) => {
|
|
uni.login({ provider: 'weixin', success: resolve, fail: reject })
|
|
})
|
|
const loginCode = loginRes && loginRes.code
|
|
if (!loginCode) throw new Error('静默登录失败')
|
|
const data = await post('/mini/auth/wechat-login', { loginCode })
|
|
if (!data || !data.token) throw new Error('静默登录失败')
|
|
saveSession({
|
|
token: data.token,
|
|
refreshToken: data.refreshToken,
|
|
userInfo: data.userInfo
|
|
})
|
|
return data
|
|
}
|
|
|
|
/**
|
|
* 已登录态下用 wx.login code 绑定 openid;失败静默。
|
|
*/
|
|
export async function bindWechatQuietly() {
|
|
try {
|
|
const loginRes = await new Promise((resolve, reject) => {
|
|
uni.login({ provider: 'weixin', success: resolve, fail: reject })
|
|
})
|
|
const loginCode = loginRes && loginRes.code
|
|
if (!loginCode) return
|
|
const token = getToken()
|
|
if (!token) return
|
|
await post(
|
|
'/mini/auth/wechat-bind',
|
|
{ loginCode },
|
|
{ Authorization: 'Bearer ' + token }
|
|
)
|
|
} catch (e) {
|
|
console.warn('wechat bind skipped', e && e.message)
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 查询当前用户是否已绑定服务号(用于微信审批通知)。
|
|
* @returns {Promise<{ bound: boolean }>}
|
|
*/
|
|
export async function fetchMpBindStatus() {
|
|
const token = getToken()
|
|
if (!token) return { bound: false }
|
|
const data = await get('/mini/auth/mp-bind-status', {
|
|
Authorization: 'Bearer ' + token
|
|
})
|
|
return { bound: !!(data && data.bound) }
|
|
}
|