在从本地存储恢复 Vuex Store 之前执行的中间件

Posted

技术标签:

【中文标题】在从本地存储恢复 Vuex Store 之前执行的中间件【英文标题】:Middleware executing before Vuex Store restore from localstorage 【发布时间】:2019-07-14 08:21:45 【问题描述】:

在 nuxtjs 项目中,我创建了一个身份验证中间件来保护页面。 并使用 vuex-persistedstate(也尝试过 vuex-persist 和 nuxt-vuex-persist)来持久化 vuex 存储。

从一个页面导航到另一个页面时一切正常,但是当我刷新页面或直接登陆到受保护的路线时,它会将我重定向到登录页面。

本地存储插件

import createPersistedState from 'vuex-persistedstate'

export default ( store ) => 
  createPersistedState(
      key: 'store-key'
  )(store)

身份验证中间件

export default function ( req, store, redirect, route ) 
    const userIsLoggedIn = !!store.state.auth.user
    if (!userIsLoggedIn) 
        return redirect(`/auth/login?redirect=$route.fullPath`)
    
    return Promise.resolve()

【问题讨论】:

也遇到过这种情况。你有进步吗? @SeanRussell 我未能解决问题,但通过创建重定向页面找到了绕过此问题的方法。在我的案例中,存储数据位于客户端的本地存储中。因此,每当我们执行刷新时,服务器都会尝试在服务器上找到存储数据,这就是它。所以我创建了一个重定向页面。并相应地更改上述功能。发送邮件至 yashdeep.rajput019@gmail.com 获取代码。 @auedbaki 你能在这里发布解决方案吗?谢谢 【参考方案1】:

我通过使用这个插件 vuex-persistedstate 而不是 vuex-persist 插件解决了这个问题。似乎 vuex-persist 中存在一些错误(或可能是设计架构)导致它。

【讨论】:

这无法通过客户端解决方案来解决。这是因为服务器端没有 Vuex Store 值。这些库是不可能的。您将体验到使用在服务器端运行的 asyncData 函数。 哦。这可能是非常真实的。但是我在客户端使用 vuex-persist 遇到了这个问题。在搜索谷歌时,这个页面是我能找到的最好的结果,所以也许其他人在使用 vuex-persist 时遇到问题(在插件中解决问题之前)可以看到我的评论,这会有所帮助。此外,问题中的服务器上没有任何内容,所以我不知道。【参考方案2】:

使用当前的方法,我们总是会失败。

实际问题是 Vuex 存储永远无法与服务器端 Vuex 存储同步。

事实上,我们只需要数据字符串与客户端和服务器(令牌)同步。

我们可以通过 Cookies 实现这种同步。因为 cookie 会自动传递给来自浏览器的每个请求。所以我们不需要设置任何请求。您可以直接从浏览器地址栏或导航中点击 URL。

我建议使用模块 'cookie-universal-nuxt' 来设置和删除 cookie。

登录后设置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 获取令牌,在客户端获取令牌存储。 (这里我们也可以从cookies中获取)

在此之后,由于布局中的存储数据绑定,您可能会遇到一些水合问题。为解决此问题,请使用 <no-s-s-r></no-s-s-r> 包装此类模板代码。

【讨论】:

以上是关于在从本地存储恢复 Vuex Store 之前执行的中间件的主要内容,如果未能解决你的问题,请参考以下文章

解决vue单页面刷新后vuex中数据恢复初始值的问题

Vue开发中使用vuex-数据持久化插件store-案例

Vuex 刷新页面后数据就消失了,怎么保存数据持久化?

解决vuex刷新页面数据丢失

vuex实现原理

vue项目数据本地存储