利用vue-router导航守卫实现强制登录

在实际项目中,经常会有要求用户登录才能访问其他页面的场景,当用户在未登录的情况下去访问内容页面的地址时,我们需要强制跳转到登录页面,同样的,当用户登录成功了但又去访问登录页面的地址时,我们应该强制跳转到主页面。

这篇文章和大家一起讨论一下这种业务场景如何用vue去实现。

上面的场景提到了页面之间的跳转,因此我们在项目中引入vue-router,然后通过vue-router的导航守卫来实现上面的需求。

Vue Router 是Vue.js官方的路由管理器。它和 Vue.js 的核心深度集成,让构建单页面应用变得易如反掌。

这里假设我们的页面有两个:

  1. 主页(登录后可见)Home.vue
  2. 登录页 Login.vue

我们的路由配置如下

export default new Router({
  routes: [
    {
      path: '/',
      name: 'home',
      component: Home
    },
    {
      path: '/login',
      name: 'login',
      component: Login
    }
  ]
})

通过路由我们可以看出这两个页面的访问地址分别如下:

  1. 主页 http://localhost:8080/#/
  2. 登录 http://localhost:8080/#/login

在实际情况中,我们通常会把主页的地址和域名进行绑定,也就是说用户不管是否登录,首次访问的肯定是主页的地址。因此我们需要在首页上判断登录状态然后决定是否重定向到登录页。

但是如果把登录状态判断的业务写在首页上,意味着你每添加一个新的页面都要再写一次重复的逻辑,很显然,这不利于维护。好在vue-router具有导航守卫的特性,因此我们为router添加全局前置守卫,在main.js文件中,我们把守卫代码写在Vue实例化的上方,代码如下:

router.beforeEach((to, from, next)=>{
  //
})

这样一来,页面每次发生跳转都会触发这里的钩子函数,如果想让跳转继续,就调用next(),要么就对页面进行重定向。

我们这里讨论的场景是要判断是否登录,登录状态应该是一个全局状态,因为我们可能会在任意页面上访问它,也会在登录页面上改写它。因此我们需要在项目里引入vuex。

Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式。它采用集中式存储管理应用的所有组件的状态,并以相应的规则保证状态以一种可预测的方式发生变化。

我们在store.js里添加登录状态这个state,命名为islogin

export default new Vuex.Store({
  state: {
    islogin: false //是否已登录
  },
  mutations: {
    loginSuccess(state){ //登录成功,改变登录状态为true
      state.islogin = true;
    }
  },
  actions: {

  }
})

我们还添加了一个名为loginSuccess的mutation,当登录成功的时候,我们需要提交这个mutation来改变全局登录状态,这时,凡是引用了state里islogin这个属性的任何页面或者组件,都会同步改变状态,这就是使用vuex的好处。在这里我们不对vuex进行过多讨论。

继续回到我们的业务场景,我们要在全局前置守卫里判断登录状态然后控制导航继续或者重定向,代码如下:

router.beforeEach((to, from, next)=>{
  let logined = store.state.islogin;
  if(to.name=="login"){
    if(!logined){
      next();
    }else{
      router.replace("/");
    }
  }else{
    if(!logined){
      router.replace({path:"login", query:{redirect:to.name}});
    }else{
      next();
    }
  }
})

这段代码的第一行我们从store里获取了登录状态islogin,然后需要判断页面去向(to.name),如果页面前往非登录页(主页或其他页面,代码中的else逻辑),我们判断是否已登录,是就next()继续,否则就把页面重定向到登录页。这里有一个细节,我们用了编程式导航的replace方法,它和push的区别是,页面重定向以后无法返回上一级,我们这里的场景的确不希望用户返回上一级,因此使用了replace。

还有一个需要注意的地方,我们登录成功后肯定希望页面重新跳转到原本的去向,因此我们把to.name作为一个查询参数传递给登录页面 query:{redirect:to.name},在登录页面登录成功后,我们就可以获取这个redirect然后重新跳转。

如果页面前往的是登录页(to.name=="login"),我们判断是否已登录,未登录就next()继续,否则就把页面重定向到主页(或其他),这里我们依然用了replace,因为我们还是不希望用户可以返回这一层。

现在还有一个工作要做,就是在登录页面上改写全局登录状态,实际业务中大多都是调用后台登录接口,然后在登录成功后进行state的改写,以下代码我们用setTimeout模拟接口请求

setTimeout(()=>{
    this.$store.commit("loginSuccess");
    let redirect = this.$route.query.redirect; //获取redirect
    if(redirect != undefined){
        this.$router.replace({name:redirect})
    }else{
        this.$router.replace("/")
    }
}, 1000);

以上代码模拟了登录成功之后的业务,第一行是提交了一个mutation来改写全局登录状态。第二行的redirect就是我们上面说的登录之前原本的目标页面,如果不存在这个参数,那就重定向到一个默认的页面(通常是主页)。现在由于全局登录状态已经为true,因此就可以顺利打开其他页面了。

这个案例到这里就结束了吧?

并没有!如果你已经按我上面的示例写了一个demo,登录成功并打开了主页,那么现在请刷新一下页面,怎么样?是不是又跳回登录页面了?

原因很简单,vuex只保存运行时的状态,它并不能实现数据持久化,刷新页面、重启浏览器、重启电脑这些操作都将导致整个vue单页面应用重新初始化,vuex也不例外。但我们的登录状态实际上肯定是需要保持一定时间的,不能每刷新一次就要登录一次。因此,要想做本地数据持久化,只有一个办法,要么用cookie要么用localStorage,在这里我们用后者,在刚才登录成功的业务里对状态进行本地保存。

localStorage.setItem("islogin", "true");

最后我们在main.js里面获取这个本地状态,如果本地状态是已登录,就提交mutation到store来改变全局登录状态。记得,这部分代码要写在全局前置守卫之前。

let islogin = localStorage.getItem("islogin"); //获取本地登录状态
if(islogin){
  store.commit("loginSuccess")
}

router.beforeEach((to, from, next)=>{
  let logined = store.state.isLogin;
  //......

好了,关于强制登录的一个实现思路就这些了,大家有任何问题或想法请在评论区留言,我会一一回复。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 214,377评论 6 496
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,390评论 3 389
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 159,967评论 0 349
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,344评论 1 288
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,441评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,492评论 1 292
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,497评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,274评论 0 269
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,732评论 1 307
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,008评论 2 328
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,184评论 1 342
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,837评论 4 337
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,520评论 3 322
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,156评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,407评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,056评论 2 365
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,074评论 2 352

推荐阅读更多精彩内容