@ithinkdt/core
Version:
iThinkDT Core
100 lines (90 loc) • 2.94 kB
JavaScript
import { watch } from 'vue'
import { HttpError } from '@ithinkdt/common'
import { Route } from './router'
export function jwt(
router,
getToken,
setToken,
{
headerField,
cookieField,
cookieDomain,
cookiePath = '/',
tokenParser,
tokenFormatter,
unauthCodes,
sameSite = 'Lax',
},
) {
let _token, resolve
const setted = new Promise((_resolve) => (resolve = _resolve))
const interceptor = async (req, next) => {
if (_token) {
req.headers.set(headerField, tokenFormatter(_token))
} else if (req.url.includes('/cli/') || req.url.includes('/cer/')) {
await setted
}
try {
return await next({
...req,
credentials: 'omit',
})
} catch (error) {
if (
error instanceof HttpError &&
error.code &&
unauthCodes.includes(error.code) &&
![Route.NOT_FOUND, Route.LOGOUT, Route.LOGIN].includes(router.currentRoute.value.name)
) {
console.debug('[auth] token expired')
setToken()
}
throw error
}
}
interceptor.setCookieByToken = (token) => {
if (cookieField) {
// eslint-disable-next-line unicorn/no-document-cookie
document.cookie = `${cookieField}=${_token ? encodeURIComponent(tokenFormatter(token)) : ''}; ${
cookieDomain ? `domain=${cookieDomain}; ` : ''
}path=${cookiePath}; ${sameSite}`
}
}
const readPathCookie = (path, field) => {
try {
const url = location.href.slice(location.origin.length)
// eslint-disable-next-line unicorn/no-null
history.replaceState(null, '', path)
const reg = new RegExp(`(^| )${field}=([^;]*)(;|$)`)
const v = reg.exec(document.cookie)?.[2]
// eslint-disable-next-line unicorn/no-null
history.replaceState(null, '', url)
return v
} catch {
return ''
}
}
interceptor.getTokenFromCookie = () => {
const str = readPathCookie(cookiePath, cookieField)
return str && tokenParser(decodeURIComponent(str))
}
const str = interceptor.getTokenFromCookie()
interceptor._init = () => {
setted.then((token) => {
if (str && str !== token) {
console.debug('[jwt]: 从 cookie 读取到的 token 不同于当前值,将替换')
setToken(str)
}
})
watch(
getToken,
(token) => {
_token = token
interceptor.setCookieByToken(token)
token && resolve(token)
},
{ immediate: true, flush: 'sync' },
)
}
return interceptor
}