常规的路由鉴权

在前端的路由鉴权中,简单的鉴权会根据用户的登录状态可以控制路由的访问,比如常见的:

  1. 登录状态可访问的路由
  2. 未登录状态可访问的路由

他们在路由守卫中代码示意如下:

 const routes =  [
  {
    path: '/',
    redirect: '/dashboard',
  },
  {
    path: '/dashboard',
    component: Dashboard,
  },
  {
    path: '/profile',
    component: Profile,
    meta: {
       requiresAuth: true
    },
  }
];

我们定义了一个路由数组,在路由的meta对象中增加了一个requiresAuth表示这个路由必须登录才能访问。

// 添加导航守卫
router.beforeEach((to, from, next) => {
    const isAuthenticated = true; // 假设这里有一个表示用户登录状态的变量

    // 如果路由需要鉴权
    const isRequiresAuth = to.matched.some(r => r.meta.requiresAuth);
    if(isRequiresAuth && !isAuthenticated) {
      next({ path: "/login" });
      return;
    }

    next();
});

这样如果用户没有登录,当他进入到需要登录的路由时会被重定向到登录页进行登录。

但是这个又有一个新的问题,当用户已经登录后,它还是可以直接访问登录页,这显然不合理。

完善的常规路由鉴权

 const routes =  [
  {
    path: '/login',
    component: Login,
    meta: {
      guest: true
    }
  }
];

我们给只能未登录访问的路由增加一个guest属性,然后再去路由守卫中增加一个条件判断:

// 添加导航守卫
router.beforeEach((to, from, next) => {
    const isAuthenticated = true; // 假设这里有一个表示用户登录状态的变量

    // 如果路由需要鉴权
    const isRequiresAuth = to.matched.some(r => r.meta.requiresAuth);
    if(isRequiresAuth && !isAuthenticated) {
      next({ path: "/login" });
      return;
    }

    // 只能访客访问
    const isGuest = to.matched.some(r => r.meta.guest);
    if(isGuest && isAuthenticated) {
      next({ path: "/" });
      return;
    }

    next();
});

这样就更加完善了,当用户访问只能访客访问的路由时,会被重定向到首页。

现在一个基本的路由鉴权就是这样了,相信这也是大多数前端spa项目使用的方式。

新增的鉴权需求

在国内的环境中,常常要求邮箱注册的用户或者第三方账号登录的用户,必须绑定手机号,我们必然会在路由守卫中增加一条新的判断条件。

如果用户没有绑定手机号,可以进入/bind-phone 路由页,如果已经绑定了就不允许进入了。

 const routes =  [
  {
    path: '/bind-phone',
    component: BindPhone,
    meta: {
      bindPhone: true
    }
  }
];
// 添加导航守卫
router.beforeEach((to, from, next) => {
    const isAuthenticated = true; // 假设这里有一个表示用户登录状态的变量
    const isPhone = false;  // 假设这里有一个表示用户是否绑定了手机号的变量

    // 如果路由需要鉴权
    const isRequiresAuth = to.matched.some(r => r.meta.requiresAuth);
    if(isRequiresAuth && !isAuthenticated) {
      next({ path: "/login" });
      return;
    }

    // 只能访客访问
    const isGuest = to.matched.some(r => r.meta.guest);
    if(isGuest && isAuthenticated) {
      next({ path: "/" });
      return;
    }

    // 登录且没有绑定手机号
    const isBindPhone = to.matched.some(r => r.meta.bindPhone);
    if (isBindPhone) {
      if (!isRequiresAuth) {
        next({ path: "/login" });
        return;
      }
      
      if (!isPhone) {
        next({ path: "/bind-phone" });
        return;
      }
      
      next({ path: "/" });
    }

    next();
});

这样写其实也可以满足需求,如果你对代码有要求,你会感觉两个地方非常难受,一个就是meta属性里面塞了一堆新增的属性,然后路由守卫中增加了非常多的条件判断语句,导致整个守卫代码变得非常庞大且复杂,如果再新增几个条件,简直不敢想象。

后面的人维护起来非常痛苦,它要阅读非常多了代码才能了解某个条件的意义。

这时,设计模式就显得非常重要,我们可以通过策略模式来优化守卫中的条件语句。

此处内容已隐藏回复后方可阅读。

分类: vue 项目实战 标签: 策略路由鉴权Context

评论

暂无评论数据

暂无评论数据

目录