JWT 认证机制

1. Web 开发模式

目前主流的 Web 开发模式有两种

  1.  基于服务端渲染的传统 Web 开发模式
  2.  基于前后端分离的新型 Web 开发模式

1.1 服务端渲染的 Web 开发模式

服务器发送给客户端的 HTML 页面, 是在服务器通过字符串拼接动态生成的.因此,客户端不需要使用 Ajax 这样的奇数额外请求页面的数据.

优点:

  1. 前端耗时少. 因为是服务器负责动态生成 HTML 内容,浏览器只需要直接渲染页面即可
  2. 有利于SEO. 

缺点:

  1. 占用服务器资源.由于服务器动态拼接页面内容,若请求过多,会给服务器造成一定的访问压力
  2. 不利于前后端分离,开发效率低

1.2 前后端分离的 Web 开发模式

后端只负责提供 API 接口,前端使用 Ajax 调用接口的开发模式

优点:

  1. 开发体验好.前端专注于 UI 页面的开发,后端专注于 API 的开发,且前端有更多的选择性
  2. 用户体验好. Ajax 技术的广泛应用,极大的提高了用户的体验,可以轻松实现页面的局部刷新
  3. 减轻了服务器的渲染压力.因为页面最终是在每个用户的浏览器中生成的

缺点:

  1. 不利于SEO.(利用Vue,React等前端框架的 SSR 技术能够很好的解决 SEO 问题!)

1.3 如何选择 Web 开发模式

具体使用何种开发模式并不是绝对的,为了同时兼顾首页的渲染速度和前后端分离的开发效率,一些网站采用了首屏服务器端渲染,其他二面采用前后端分离的开发模式

  • 企业级网站,主要功能是展示而没有复杂的交互,并且需要良好的 SEO ,这时就需要使用服务器端渲染
  • 类似后台管理页面,交互性比较强,不需要 SEO 的考虑,就可以使用前后端分离的开发模式.

2. 身份认证

2.1 什么是身份认证

身份认证(Authentication) 又称"身份验证","鉴权",是指通过一定的手段,完成对用户身份的确认

2.2 为什么需要身份认证

身份认证的目的,是为了确认当前所声称为某种身份的用户,确实是所声称的用户.意思就是确保你的各种信息确实正确显示到你自己的账户里.

2.3 不同开发模式下的身份认证

对于服务端渲染和前后端分录这两种开发模式来说,分别有着不同的身份认证方案:

  1.  服务端渲染推荐使用 Session 认证机制
  2.  前后端分离推荐使用 JWT 认证机制 (我们今天需要了解的)

3. JWT 认证机制

3.1 什么是 JWT

JWT (JSON Web Token) 是目前最流行的跨域认证解决方案

3.2 JWT 的工作原理

JWT 认证机制

 用户的信息通过 Token 字符串的形式,保存在客户端浏览器中,服务器通过还原 Token 字符串的形式来认证用户的身份.

3.3 JWT 的组成部分

JWT 通常由三部分组成,分别是 Header(头部), Payload(有效荷载), Signature(签名).

三者之间使用英文的 "." 分隔

Header.Payload.Signature
  • Payload 部分 是真正的用户信息,他是用户信息经过加密之后产生的字符串
  • Header 和 Signature 是安全性相关的部分,只是为了保证 Token 的安全性

3.4 JWT 的使用方式

客户端收到服务器返回的 JWT 之后,通常会将它储存在 localStorage 或 sessionStorage 中,此后,客户端每次与服务器通信,都要带上这个 JWT . 推荐的做法是把 JWT 放在 HTTP 请求头的 Authorization 字段中

Authorization: Bearer <token> // Bearer 和 token之间需要有个空格

3.5 在 Express 中使用 JWT

  1. 安装 JWT 相关的包
    npm i jsonwebtoken express-jwt 
    
    // jsonwebtoken 用于生成 JWT 字符串
    // express-jwt 用于将 JWT 字符串解析还原成 JSON 对象
  2. 用require()方法,导入 JWT 相关的包
    const jwt = require('jsonwebtoken');
    // 用于生成 JWT 字符串的包
    
    const expressjwt = require('express-jwt');
    // 导入用于将客户端发送过来的 JWT 字符串,解析还原成 JSON 对象的包
  3. 定义 secret 秘钥: 为了保证 JWT 字符串的安全性,防止其在网络传输过程中被破解,需要专门定义一个用于加密和解密的 secret 
    const secretkey = 'you are beautify *__*';
    // 秘钥的本质就是一个字符串,可以随便写
    
    // 当生成 JWT 字符串的时候需要加密,最终得到加密好的字符串
    
    // 把 JWT 字符串解析还原成JSON对象的时候,需要秘钥进行解密
  4. 登录成功后生成 JWT 字符串
    app.post('/login',(req , res) => {
    // ... 省略之前代码
    // 用户登录成功后,生成JWT字符串,通过 token 属性响应给客户端
    res.send({
       status: 200,
       msg: '登陆成功',
       token: jwt.sign({username: user.username},secretkey,{expiresIn: '2h'})
    
     // jwt.sign()生成 JWT 字符串,参数分别是:用户信息对象,秘钥,配置对象(生效时间)
    })
    
    })
  5. 注册将 JWT 字符串还原为 JSON 对象的中间件
    app.use(expressjwt({secret: secretkey}).unless({path:[/^\/api\//]}));
    
    // 用来解析 token 的中间件
    // .unless({path:[/^\/api\//]}) 用来指定哪些接口不需要访问权限
  6.  当express-jwt这个中间件配置成功之后,即可在有权限的接口中通过 req.user 对象,来访问解析出来的用户信息
  7. 捕获解析失败后产生的错误
    app.use((err, req, res, next) => {
      // 捕获身份认证失败的错误
      if (err.name === 'UnauthorizedError') return res.send('身份认证失败!')
      // 未知的错误
      res.send(err)
    })
    
    // 如果客户端发送过来的 token 字符串过期或者不合法,会产生一个解析失败的错误,
    // 影响项目正常运行,所以用express的错误中间件,捕获这个错误并处理

 

上一篇:JWT令牌的工作原理


下一篇:php 微信退款