我没有使用 @nuxtjs/auth
,只是简单的代码...
我有一个客户端插件,用于在页面刷新时自动登录用户。
// FILE ./plugins/auth.client.js
export default async function ({ $axios, store, redirect, route }) {
console.log('[PLUGIN] Auth (Client)')
try {
const token = localStorage.getItem('sc-token')
store.commit('auth/setAuth', token)
if (!token) {
console.log('redirecting... 1')
return redirect(401, '/auth/login?1')
}
const user = await $axios.$post('/api/auth/verify', token)
console.log('USER', user)
if (!user) {
console.log('redirecting... 2')
return redirect(401, '/auth/login?2')
}
} catch (e) {
return redirect(401, '/auth/login')
}
}
并且正确设置为 plugins: [{ src: '~/plugins/auth.client' }]
在 nuxt.config.js
我的问题是 redirect()
只有当它在服务器端运行时才会工作,而且如果我只能访问 localStorage
在客户端模式下,加上,服务器总是先运行,但我试图在知道是否需要重定向之前附加令牌。
你们是怎么做的?
终于让所有的工作如愿以偿,不得不有一个 ./plugins/auth.js
结合 ./middleware/authenticated.js
一模一样的代码
./middleware/authenticated.js
将在每次路由变更时运行(用于检查令牌验证)。
./plugins.js
在客户端和服务器上运行,因为当用户刷新页面时,它就会运行。
为了使所有工作与这2个文件,我不得不。
cookie-universal-nuxt
包裹this.$cookies
并将在中间件上工作,无论是在客户端模式还是服务器模式下运行。对于每次路由的改变,中间件都会验证token(用于回火、过期等),当年龄刷新时,插件会检查同样的内容。
编码 ./plugins/auth.js
export default async function ({ $axios, store, redirect, app }) {
console.log('[PLUGIN] Auth (Server/Client)', process.client)
const path = app && app.router && app.router.currentRoute ? app.router.currentRoute.fullPath : ''
try {
const token = app.$cookies.get('sc-token')
const isLoggedIn = store.getters['auth/isLoggedIn']
// console.log('[PLUGIN] Auth: token', token)
// console.log('[PLUGIN] Auth: isLoggedIn', isLoggedIn)
// token exists?
if (!token) {
store.commit('auth/clearAuth')
return redirect(`/auth/login?path=${path}&err=no_token`)
}
// verify token
try {
// $axios.defaults.headers.common.Authorization = `Bearer ${token}`
const user = await $axios.$post('/api/auth/verify', { token })
// console.log('[PLUGIN] Auth RES OK', user.verified, isLoggedIn)
// all OK
if (user.verified && !isLoggedIn) {
console.log('SETTING AUTH', token)
store.commit('auth/setAuth', token)
// return redirect(path)
}
} catch (err1) {
console.log('[PLUGIN] Auth ERROR (1)', err1.message)
// console.log('redirecting... 2', err1.response.data)
let message = err1.message
if (
err1.response &&
err1.response.data &&
err1.response.data.error &&
err1.response.data.error === 'jwt expired'
)
message = 'token_expired'
store.commit('auth/clearAuth')
return redirect(`/auth/login?path=${path}&err=${message}`)
}
// console.log('COOKIES END')
} catch (err2) {
console.log('[PLUGIN] Auth ERROR (2)', err2.message)
return redirect(401, `/auth/login?err=${err2.message}`)
}
}
我的 /auth/verify
API路由。
const verifyToken = (req, res) => {
const token = req.body.token || req.headers.authorization.replace('Bearer ', '')
try {
const verified = jwt.verify(token, SECRET_SIGN, { issuer: 'https://auth.domain.com/the-editor' })
res.json({ verified })
} catch (err) {
res.status(401).json({ error: err.message })
}
}
然后,我的ExpressJs中间件为每次调用验证令牌,并将令牌的有效载荷附加到请求中(这样我就可以在以后的调用中接收到)。
const authentication = (req, res, next) => {
// authentication
const url = req.url
let token = req.body.token || req.headers.authorization || req.headers.cookie
// console.log('[Authentication Express Middleware] headers', JSON.stringify(req.headers))
// console.log('[Authentication Express Middleware] cookie', JSON.stringify(req.headers.cookie))
// console.log('[Authentication Express Middleware] body', JSON.stringify(req.body))
// console.log('[Authentication Express Middleware]', url, !!token)
// bypass URL as there's no token yet...
if (['/auth/login'].includes(url)) return next()
// not the login path, we should validate token
if (token) {
if (token.includes('sc-token=')) token = token.replace('sc-token=', '')
// check and validate token
token = token.indexOf('Bearer ') === 0 ? token.substring(7) : token // "Bearer ..."
return jwt.verify(token, SECRET_SIGN, (err, payload) => {
// attach payload to user (will be null if not verified)
req.user = payload
// if verified, err is null and will continue to the next middleware
return next(err)
})
}
return next(new Error('No valid token was passed'))
}