nuxt.js - 如何自动登录或重定向?
问题描述
我没有使用@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
在用户刷新页面时运行在客户端和服务器上
为了使所有使用这两个文件的工作,我必须:
- 停止使用 localStorage 并改用 cookie
- 使用
cookie-universal-nuxt
包 - 它将为您提供
this.$cookies
并且可以在中间件上运行,无论是在客户端模式还是服务器模式下运行
对于每个路由更改,中间件在年龄刷新时验证令牌(用于回火、过期等),插件检查相同
代码./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'))
}
推荐阅读
- substr - 使用 parse 命令截断 AWS 日志
- neo4j - 如何在 .Net 客户端中使用 ForEach
- python - 如何使用 Python 和图像处理删除掩码中的条目?
- java - 如何将 Apache Ignite 瘦客户端连接到 Apache Ignite 集群?
- python - 如何将元素添加到另一个列表中的 Python 列表中
- reactjs - React-select 选项显示默认的蓝色背景
- python - 即使我安装了 Statsmodels 也不起作用
- abap - 键入接口方法参数泛型以使接口更易于访问的优点和缺点是什么?
- c++ - 当我尝试传递链表的头指针时,我不断收到错误消息
- javascript - 如何在 vue 中使用 raw-loader,在 scss 中使用 file-loader