| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165 |
- import JSEncrypt from 'jsencrypt/bin/jsencrypt.min'
- import { getScreenPublicKey, screenAutoLogin } from '@/api/login'
- import { getToken, setToken } from '@/utils/auth'
- /** URL 密文登录失败时展示给用户的提示 */
- export const SCREEN_LOGIN_CIPHER_ERROR = '公钥不对'
- /** URL uuid 免密登录失败时展示给用户的提示 */
- export const SCREEN_LOGIN_UUID_ERROR = '免密失败,请联系管理员获取免登ID'
- /** 同一会话内仅尝试一次免密登录,避免反复请求 */
- let autoLoginState = null
- let autoLoginPromise = null
- let autoLoginUuid = null
- export function isScreenAutoLoginEnabled() {
- return import.meta.env.VITE_SCREEN_AUTO_LOGIN === 'true'
- }
- export function resetScreenAutoLoginState() {
- autoLoginState = null
- autoLoginPromise = null
- autoLoginUuid = null
- }
- /** 从路由 query 读取 RSA 密文(?token=xxxx) */
- export function getUrlScreenLoginCipher(query) {
- const raw = query?.token
- if (typeof raw !== 'string' || !raw.trim()) {
- return ''
- }
- try {
- return decodeURIComponent(raw.trim())
- } catch {
- return raw.trim()
- }
- }
- /** 从路由 query 读取免登 UUID(?uuid=xxxx) */
- export function getUrlScreenLoginUuid(query) {
- const raw = query?.uuid
- if (typeof raw !== 'string' || !raw.trim()) {
- return ''
- }
- try {
- return decodeURIComponent(raw.trim())
- } catch {
- return raw.trim()
- }
- }
- /** 去掉 URL 中的 token,避免密文残留在地址栏 */
- export function stripScreenLoginTokenQuery(query = {}) {
- const next = { ...query }
- delete next.token
- return next
- }
- /** 去掉 URL 中的 uuid */
- export function stripScreenLoginUuidQuery(query = {}) {
- const next = { ...query }
- delete next.uuid
- return next
- }
- /**
- * 使用 URL 传入的 RSA 密文换取 JWT
- * @param {string} cipher
- * @returns {Promise<string>} JWT
- */
- export async function tryScreenLoginWithCipher(cipher) {
- if (!cipher) {
- throw new Error(SCREEN_LOGIN_CIPHER_ERROR)
- }
- try {
- const loginRes = await screenAutoLogin(cipher)
- if (!loginRes?.token) {
- throw new Error(SCREEN_LOGIN_CIPHER_ERROR)
- }
- setToken(loginRes.token)
- autoLoginState = 'ok'
- return loginRes.token
- } catch {
- throw new Error(SCREEN_LOGIN_CIPHER_ERROR)
- }
- }
- /**
- * 获取公钥 → RSA 加密 URL 中的 UUID → 换取 JWT
- * @param {string} uuid
- * @returns {Promise<string>} JWT
- */
- export async function tryScreenAutoLogin(uuid) {
- if (!uuid) {
- throw new Error(SCREEN_LOGIN_UUID_ERROR)
- }
- try {
- const keyRes = await getScreenPublicKey()
- const publicKey = keyRes.data?.publicKey
- if (!publicKey) {
- throw new Error(SCREEN_LOGIN_UUID_ERROR)
- }
- const encryptor = new JSEncrypt()
- encryptor.setPublicKey(publicKey)
- const cipher = encryptor.encrypt(uuid)
- if (!cipher) {
- throw new Error(SCREEN_LOGIN_UUID_ERROR)
- }
- const loginRes = await screenAutoLogin(cipher)
- if (!loginRes?.token) {
- throw new Error(SCREEN_LOGIN_UUID_ERROR)
- }
- setToken(loginRes.token)
- return loginRes.token
- } catch {
- throw new Error(SCREEN_LOGIN_UUID_ERROR)
- }
- }
- /**
- * 路由守卫用:URL 含 uuid 时尝试免密登录
- * @returns {Promise<{ attempted: boolean, ok: boolean }>}
- */
- export async function ensureScreenAutoLogin(query) {
- if (getToken()) {
- return { attempted: false, ok: true }
- }
- if (!isScreenAutoLoginEnabled()) {
- return { attempted: false, ok: false }
- }
- const uuid = getUrlScreenLoginUuid(query)
- if (!uuid) {
- return { attempted: false, ok: false }
- }
- if (autoLoginState === 'fail' && autoLoginUuid === uuid) {
- return { attempted: true, ok: false }
- }
- if (autoLoginState === 'ok' && getToken()) {
- return { attempted: false, ok: true }
- }
- if (autoLoginState === 'pending' && autoLoginPromise && autoLoginUuid === uuid) {
- const ok = await autoLoginPromise
- return { attempted: true, ok }
- }
- autoLoginUuid = uuid
- autoLoginState = 'pending'
- autoLoginPromise = tryScreenAutoLogin(uuid)
- .then(() => {
- autoLoginState = 'ok'
- return true
- })
- .catch(() => {
- autoLoginState = 'fail'
- return false
- })
- const ok = await autoLoginPromise
- return { attempted: true, ok }
- }
|