以目前的方法,我们将永远失败。
实际问题是Vuex Store无法与服务器端的Vuex Store同步。
事实上,我们只需要数据字符串与客户端和服务器同步(令牌)。
我们可以通过Cookies实现此同步。因为Cookies会自动传递给浏览器的每个请求。所以我们不需要设置任何请求。您只需从浏览器地址栏或导航中访问URL即可。
我建议使用模块'cookie-universal-nuxt'来设置和删除Cookies。
用于登录后设置Cookie
this.$cookies.set('token', 'Bearer '+response.tokens.access_token, { path: '/', maxAge: 60 * 60 * 12 })
在注销时删除cookie
this.$cookies.remove('token')
请仔细阅读文档以获得更好的理解。
此外,我正在使用@nuxt/http模块进行API请求。
现在,Nuxt在Vuex存储索引文件中有一个名为nuxtServerInit()的函数。您应该使用它从请求中检索令牌并将其设置为http模块标头。
async nuxtServerInit ({dispatch, commit}, {app, $http, req}) {
return new Promise((resolve, reject) => {
let token = app.$cookies.get('token')
if(!!token) {
$http.setToken(token, 'Bearer')
}
return resolve(true)
})
},
以下是我的Nuxt页面级别中间件。
export default function ({app, req, store, redirect, route, context }) {
if(process.server) {
let token = app.$cookies.get('token')
if(!token) {
return redirect({path: '/auth/login', query: {redirect: route.fullPath, message: 'Token Not Provided'}})
} else if(!isTokenValid(token.slice(7))) { // slice(7) used to trim Bearer(space)
return redirect({path: '/auth/login', query: {redirect: route.fullPath, message: 'Token Expired'}})
}
return Promise.resolve()
}
else {
const userIsLoggedIn = !!store.state.auth.user
if (!userIsLoggedIn) {
return redirect({path: '/auth/login', query: {redirect: route.fullPath}})
// return redirect(`/auth/login?redirect=${route.fullPath}`)
} else if (!isTokenValid(store.state.auth.tokens.access_token)) {
return redirect({path: '/auth/login', query: {redirect: route.fullPath, message: 'Token Expired'}})
// return redirect(`/auth/login?redirect=${route.fullPath}&message=Token Expired`)
} else if (isTokenValid(store.state.auth.tokens.refresh_token)) {
return redirect(`/auth/refresh`)
} else if (store.state.auth.user.role !== 'admin')
return redirect(`/403?message=Not having sufficient permission`)
return Promise.resolve()
}
}
我已经为不同的令牌来源编写了不同的条件,就像代码中一样。在服务器处理中,我从 cookie 中获取令牌,在客户端获取令牌存储。(这里我们也可以从 cookie 中获取)
之后,由于布局中存储数据绑定的原因,您可能会遇到一些水合问题。为了解决这个问题,请使用 <no-ssr></no-ssr> 包装此类模板代码。