使用 Vuex 和 Vuex-persistedstate 自动登录

kab*_*ugh 1 local-storage vue.js vuex

我想auto-sign-in在页面刷新时使用。我读过我应该vuex-persistedstate用来坚持tokenin localstorage. 这是我的vuex商店:

store: {
    user: null
},
actions: {
    autoSignIn ({commit}, payload) {
      commit('setUser', { id: payload.token })
    }
},
mutations: {
    setUser (state, payload) {
      state.user = payload;
    }
},
plugins: [ createPersistedState({
  getState: (key) => localStorage.getItem(key),
  setState: (key, state) => localStorage.setItem('user_token', key)
 }) ]
Run Code Online (Sandbox Code Playgroud)

我也有signIn创建newUserwith 的操作token

signUserIn ({commit, getters, state}, payload) {
  let data = {
    _username: payload.email,
    _password: payload.password
  }
  Vue.http.post(
    'url',
      data,
    { channel: 'default' },
    { headers: { 'Content-Type': 'application/x-www-form-urlencoded' } }
  ).then(response => {
      const newUser = {
        id: response.body.token
      }
      localStorage.setItem('user_token', response.body.token)
      commit('setUser', newUser)
  })
}
Run Code Online (Sandbox Code Playgroud)

然后在main.js-created()我想检查令牌是否有效,然后 - 登录用户。

created() {
    let token = localStorage.getItem('user_token')
    if(token) {
      this.$store.dispatch('autoSignIn', token)
    }
}
Run Code Online (Sandbox Code Playgroud)

最后一部分不起作用,我知道我应该使用getState, setStatefromcreatePersistedState但我不知道该怎么做。我如何使它工作?

Geo*_* L. 5

如果使用 vuex-persistedstate 的唯一用例是记住访问令牌,那么您应该首先避免使用它,并从最终构建文件中节省一些 Kb。

如果您要为用户提供离线体验,使用它会更有意义。

如果您所做的只是使用本地存储的令牌设置 state.user,那么您就可以这样做。

// if localStorage contains a serialized object with a 'token' attribute
const userToken = JSON.parse(window.localStorage.getItem('user_token'));

const state = {
    user: userToken ? userToken.token || null : null
};

const mutations = {};
const actions = {};

export default {
   state,
   mutations,
   actions,
}
Run Code Online (Sandbox Code Playgroud)

每当您刷新页面并且商店正在实例化 state.user 时,用户将采用本地存储的令牌作为默认值,如果缺少/未定义,则为 null

但是,如果我是你,我会替换

const state = {
    user: null
};
Run Code Online (Sandbox Code Playgroud)

const state = {
    accessToken: null
};
Run Code Online (Sandbox Code Playgroud)

因为您存储的只是 accessToken 而不是用户本身,因此它具有误导性。

更新以回答评论中的问题“......我需要检查状态是否已更改并使用 setUser 突变,但不知道如何实现它。”

我能想到的有3种方法。

首先将状态更改为

const userToken = JSON.parse(window.localStorage.getItem('user_token'));

const state = {
    accessToken: userToken ? userToken.token || null : null,
    user: null,
};
Run Code Online (Sandbox Code Playgroud)

然后

最简单的

在您的 App.vue 组件上添加如下所示的挂载方法

import { mapState, mapActions } from 'vuex';

export default {
    ...
    computed: {
        ...mapState([
           'accessToken',
           'user',
        ])
    },
    mounted() {
        if (this.accessToken && !this.user)
            this.getAuthUser();
    },
    methods: {
        ...mapActions([
            'getAuthUser',
        ]),
    },
}
Run Code Online (Sandbox Code Playgroud)

因此,在安装应用程序时每次刷新,我们有一个 accessToken 但没有用户,我们调用 getAuthUser() 操作,该操作进行 ajax 调用并使用 setUser 突变存储接收到的用户

路由器保护方式

如果你有一个路由器并且你只需要在某些路由上检查一个经过身份验证的用户,那么你可以使用路由守卫。例如

import store from '@/store';

export default new Router({
    routes: [
        ...
        {
            path: '/admin',
            component: Admin,
            beforeEnter: (to, from, next) => {
                if (!store.state.accessToken) return next('/login');
                if (store.state.accessToken && !store.state.user) {
                    return store.dispatch('getAuthUser')
                        .then(() => {
                            // user was retrieved and stored and
                            // we can proceed
                            next();
                        })
                        .catch(() => {
                            // we couldn't fetch the user maybe because the token
                            // has expired.
                            // We clear the token
                            store.commit('accessToken', null);

                            // And go to login page
                            next('/login');
                        });
                },
                return next();
            },
        },
        ...
    ],
});
Run Code Online (Sandbox Code Playgroud)

使用 Vuex 插件

这是我最近学到的一个方法。

const storeModerator = (store, router) {
    // listen to mutations
    store.subscribe(({ type, payload }, state) => {
        // if commit('setAccessToken') was called dispatch 'getAuthUser'
        if (type === 'setAccessToken') {
            store.dispatch('getAuthUser');
        }
    });
};

export default new Vuex.Store({
    ...,
    plugins: [storeModerator]
});
Run Code Online (Sandbox Code Playgroud)

您可以通过检查了解更多信息:

Vue-router 导航守卫

Vuex 插件

使用 Mediator 模式解耦 Vuex 模块