实现Vue登录和权限控制及注意事项

目录

一、登录方式

1. Cookie + Session

Cookie + Session 实现流程

Cookie + Session 存在的问题

2. Token登录

Token 机制实现流程

Token 机制的特点

二、登录过程

1. 表单验证

2. 调用封装好的接口函数

3. 经过请求拦截器,添加请求头

4. 代理转发(vue.config.js)

5. 保存token到vuex

6. token做持久化

三、权限控制

注意:

1. v-for 和 v-if 的使用问题

2. 可能出现问题:sessionStorage丢失


 

一、登录方式

1. Cookie + Session

HTTP 是一种无状态的协议,客户端每次发送请求时,首先要和服务器端建立一个连接,在请求完成后又会断开这个连接。这种方式可以节省传输时占用的连接资源,但同时也存在一个问题:每次请求都是独立的,服务器端无法判断本次请求和上一次请求是否来自同一个用户,进而也就无法判断用户的登录状态。

为了解决 HTTP 无状态的问题,Lou Montulli 在 1994 年的时候,推出了 Cookie。

Cookie 是服务器端发送给客户端的一段特殊信息,这些信息以文本的方式存放在客户端,客户端每次向服务器端发送请求时都会带上这些特殊信息。

有了 Cookie 之后,服务器端就能够获取到客户端传递过来的信息了,如果需要对信息进行验证,还需要通过 Session。

客户端请求服务端,服务端会为这次请求开辟一块内存空间,这个便是 Session 对象。

有了 Cookie 和 Session 之后,我们就可以进行登录认证了。

Cookie + Session 实现流程

Cookie + Session 的登录方式是最经典的一种登录方式,现在仍然有大量的企业在使用。

用户首次登录时:

img

  1. 用户访问 a.com/pageA,并输入密码登录。

  2. 服务器验证密码无误后,会创建 SessionId,并将它保存起来。

  3. 服务器端响应这个 HTTP 请求,并通过 Set-Cookie 头信息,将 SessionId 写入 Cookie 中。

服务器端的 SessionId 可能存放在很多地方,例如:内存、文件、数据库等。

第一次登录完成之后,后续的访问就可以直接使用 Cookie 进行身份验证了:

img

  1. 用户访问 a.com/pageB 页面时,会自动带上第一次登录时写入的 Cookie。

  2. 服务器端比对 Cookie 中的 SessionId 和保存在服务器端的 SessionId 是否一致。

  3. 如果一致,则身份验证成功。

Cookie + Session 存在的问题

虽然我们使用 Cookie + Session 的方式完成了登录验证,但仍然存在一些问题:

  • 由于服务器端需要对接大量的客户端,也就需要存放大量的 SessionId,这样会导致服务器压力过大。

  • 如果服务器端是一个集群,为了同步登录态,需要将 SessionId 同步到每一台机器上,无形中增加了服务器端维护成本。

  • 由于 SessionId 存放在 Cookie 中,所以无法避免 CSRF 攻击。

2. Token登录

为了解决 Session + Cookie 机制暴露出的诸多问题,我们可以使用 Token 的登录方式。

Token 是服务端生成的一串字符串,以作为客户端请求的一个令牌。当第一次登录后,服务器会生成一个 Token 并返回给客户端,客户端后续访问时,只需带上这个 Token 即可完成身份认证。

Token 机制实现流程

用户首次登录时:

img

  1. 用户输入账号密码,并点击登录。

  2. 服务器端验证账号密码无误,创建 Token。

  3. 服务器端将 Token 返回给客户端,由客户端自由保存

后续页面访问时:

img

  1. 用户访问 a.com/pageB 时,带上第一次登录时获取的 Token。

  2. 服务器端验证 Token ,有效则身份验证成功。

Token 机制的特点

根据上面的案例,我们可以分析出 Token 的优缺点:

  • 服务器端不需要存放 Token,所以不会对服务器端造成压力,即使是服务器集群,也不需要增加维护成本。

  • Token 可以存放在前端任何地方,可以不用保存在 Cookie 中,提升了页面的安全性。

  • Token 下发之后,只要在生效时间之内,就一直有效,如果服务器端想收回此 Token 的权限,并不容易。

二、登录过程

1. 表单验证

  1. 完整的表单校验需要三个组件完成配合 分别是el-formel-form-item,表单项,如:el-input el-form负责绑定model 和 rules el-form-item负责绑定prop el-input 负责双向绑定具体的表单数据

  2. 简单的校验例如非空,长度等可以直接使用内置的校验配置,如果校验规则复杂建议使用校验函数进行校验。 比如:我们的手机号比较复杂就使用更加灵活的校验函数 比如:密码比较简单我们直接使用内置的校验配置即可

  3. 手动兜底校验

2. 调用封装好的接口函数

3. 经过请求拦截器,添加请求头

设置请求拦截器

// 响应拦截器
axios.interceptors.response.use(response => {
  if (response.data.success) {
    // 操作成功
  } else {
    // 如果success为false 业务出错,直接触发reject 
    // 被catch分支捕获
    return Promise.reject(new Error(response.data.message))
  }
}, error => {
  return Promise.reject(error) // 返回执行错误 让当前的执行链跳出成功 直接进入 catch
})
 

4. 代理转发(vue.config.js)

为解决跨域问题

module.exports = {
  devServer: {
    // 代理配置
    proxy: {
        '/api': {
          target: 'http://localhost:3000' // 我们要代理的真实接口地址
        }
      }
    }
  }

5. 保存token到vuex

使用vuex的基本逻辑:数据放在state中,要修改数据则调用mutations

  1. 先在state中补充定义token

  2. 同时,要提供对应的用来修改token的mutation,以方便在用户登陆成功之后,去设置token

6. token做持久化

  1. 在对token进行初始化的时候先从本地取一下,优先使用本地取到的值

  2. 在设置token的时候除了在vuex中存一份,在本地也同步存一份

  3. 在删除token的时候除了把vuex中的删除掉,把本地的也一并删除

// 1. 获取token   token存储在返回值的session中
window.sessionStorage.setItem("token",res.session)
// 2. 获取cookie
getCookie  = function(NameOfCookie) {
  ...
    ...
      ...
}
// 使用
let userId = getCookie("userId");
// unescape: 解密。已废除,可以使用 decodeURI 或 decodeURIComponent 代替

三、权限控制

需求:不同登陆人下显示不同菜单

  1.  调用 /login 接口成功后,调取后端提供的权限接口,获取节点id
        // 登录
        login(){
          let {username,password} = this;
          this.axios.post('/user/login',{
            username,
            password
          }).then(async (res)=>{
            if(res.status == 200) {
              // 设置cookie
              this.$cookie.set('userId',res.id,{expires:'Session'})
              this.saveUserName(res.username);
              await this.axios.get('/user/getNewBarList').then(result => {
                // 根据result 获取 节点id
                ...
                ...
              })
              this.$router.push({
                name:'index',
                params:{
                  from:'login'
                }
                });
            }else {
              this.change();   // 重新获取验证码
            }
          })
        }
  2.  根据节点id显示对应菜单

注意:

1. v-for 和 v-if 的使用问题

v-for 和 v-if 不能同时使用

  • 在vue2中,v-for的优先级更高
  • 在vue3中,v-if的优先级更高

使用场景
通常有两种情况导致需要 v-if 和 v-for 同时使用:

  • 为了过滤列表中的项目,例如 v-for = "item in content"  v-if = "user.funCode"。此时可以定义出一个计算属性,例如contentComp 让其返回过滤后的列表即可,contentComp.filter( item => item.funCode)
  • 为了避免渲染本应该被隐藏的列表,例如 v-for = "user in users"   v-if = "shouldShowUsers"。此时可以把 v-if 绑定在容器元素上,例如ul, ol或在外包一层template。

2. 可能出现问题:sessionStorage丢失

关于sessionStorage 的详细理解以及在移动端出现的bug

关于sessionStorage的移动端兼容问题

  • 1
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值