使用Vuex和Vuex-persistedstate自动登录

时间:2018-08-17 14:48:29

标签: vue.js local-storage vuex

刷新页面后,我想auto-sign-in用户。我已经读过我应该使用vuex-persistedstatetoken保留在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)
 }) ]

我还有signIn动作,其中我用newUser创建了一个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)
  })
}

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

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

最后一部分不起作用,我知道我应该使用getState, setState中的createPersistedState,但是我不知道该怎么做。我该如何运作?

1 个答案:

答案 0 :(得分:1)

如果使用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,
}

每当刷新页面且商店处于实例化状态时,用户将使用本地存储的令牌作为默认值,如果缺少/未定义,则将其为空

但是如果我是你,我会取代

const state = {
    user: null
};

const state = {
    accessToken: null
};

由于您存储的只是accessToken而不是用户本身,因此其类型具有误导性。

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

我可以想到3种方式。

首先将状态更改为

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

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

然后

最简单的

在App.vue组件上,添加如下所示的已安装方法

import { mapState, mapActions } from 'vuex';

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

因此,在每次刷新时,安装了App时,我们都有一个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();
            },
        },
        ...
    ],
});

使用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]
});

您可以通过以下方法了解更多信息:

Vue-router navigation guards

Vuex Plugins

Decouple Vuex modules with the Mediator pattern