cookie 和 Session

cookie 做登录校验的过程

  • 前端输入用户名密码,传给后端
  • 后端验证成功,返回信息时set-cookie
  • 接下来所有接口访问,都自动带上cookie(浏览器的默认行为, http协议的规定)

    为何会有 Session?

  • cookie只存储userld ,不去暴露用户信息

  • 用户信息存储在session中

    1. // session:存储用户信息
    2. {
    3. "2019283":{
    4. username:'jack',
    5. age:20
    6. }
    7. }

    Session 优点

  • 原理简单,易于学习

  • 用户信息存储在服务端,可以快速封禁某个登录的用户——有这方强需求的人,一定选择Session

    Session 缺点

  • 占用服务端内存,有硬件成本

  • 多进程、多服务器时,不好同步 —— 一般使用第三方redis存储,成本高
  • 跨域传递cookie ,需要特殊配置

    JWT

    JWT === JSON Web Token

    JWT 的过程

  • 前端输入用户名密码,传给后端

  • 后端验证成功,返回一段 token 字符串 – 将用户信息加密之后得到的
  • 前端获取token之后,存储下来
  • 以后访问接口,都在header中带上这段token

    JWT 的优点

  • 不占用服务器内存

  • 多进程、多服务器,不受影响
  • 不受跨域限制

    JWT 的缺点

  • 无法快速封禁登录的用户

    JWT 和 Sessiong 的重要区别

  • JWT用户信息存储在客户端

  • Session用户信息存储在服务端

    为什么选择JWT ?

  • 没有快速封禁登录用户的需求(或者极少有这种情况)

  • JWT成本低,维护简单
  • 需要考虑跨域的扩展性(虽然目前还没有这个需求)

登录校验 - 图1

使用步骤

  • 安装 npm 插件
    • [koa-jwt](https://www.npmjs.com/package/koa-jwt) :jwt会验证所有的路由的请求头有没有token。
    • [jsonwebtoken](https://www.npmjs.com/package/jsonwebtoken):加密,返回一个token;解密,返回解密后的data
      1. const jwt = require('jsonwebtoken')
      2. /**
      3. * jwt sign
      4. * @param {Object} data data
      5. */
      6. function jwtSign(data) {
      7. const token = jwt.sign(data, JWT_SECRET, { expiresIn: jwtExpiresIn })
      8. return token
      9. }
      ```javascript const util = require(‘util’) const jwt = require(‘jsonwebtoken’) const verify = util.promisify(jwt.verify) /**
      • jwt verify
      • @param {string} token token */ async function jwtVerify(token) { const data = await verify(token.split(‘ ‘)[1], JWT_SECRET) // 去掉前面的 Bearer return data }
  1. - **封装 jwt 中间件**,并在app.js文件使用,这样
  2. ```javascript
  3. const jwt = require('./middlewares/jwt')
  4. // 配置 jwt
  5. app.use(jwt)
  1. const jwtKoa = require('koa-jwt')
  2. const { JWT_SECRET, JWT_IGNORE_PATH } = require('../config/constant')
  3. module.exports = jwtKoa({
  4. secret: JWT_SECRET,
  5. cookie: 'jwt_token', // 使用 cookie 存储 token
  6. }).unless({
  7. // 定义哪些路由忽略 jwt 验证
  8. path: JWT_IGNORE_PATH, // 这里忽略了所有,需要登录验证的,自己用 loginCheck中间件
  9. })
  • 封装 loginCheck 中间件:登录校验,解密用户信息。 ```javascript /**
    • @description 登录校验
    • @author 双越 */

const { jwtVerify } = require(‘../utils/jwt’) const { ErrorRes } = require(‘../res-model/index’) const { loginCheckFailInfo } = require(‘../res-model/failInfo/index’)

/**

  • 登录校验
  • @param {Object} ctx ctx
  • @param {function} next next */ module.exports = async function loginCheck(ctx, next) { // 失败信息 const errRes = new ErrorRes(loginCheckFailInfo)

    // 获取 token const token = ctx.header.authorization if (!token) {

    1. ctx.body = errRes
    2. return

    }

    let flag = true try {

    1. const userInfo = await jwtVerify(token)
    2. delete userInfo.password // 屏蔽密码
    3. // 验证成功,获取 userInfo
    4. ctx.userInfo = userInfo

    } catch (ex) {

    1. flag = false
    2. ctx.body = errRes

    }

    if (flag) {

    1. // 继续下一步
    2. await next()

    } } ```

  • 相关的配置项、构造函数等

SSO 和 OAuth2

  • SSo 单点登录
  • OAuth2 第三方鉴权的常用方式

    使用 Cookie 实现

    简单的,如果业务系统都在同一主域名下,比如 wenku.baidu.com tieba.baidu.com ,就好办了。可以直接把cookie domain 设置为主域名 baidu. com ,百度也就是这么干的。

    SSO单点登录

    复杂一点的,滴滴这么潮的公司,同时拥有didichuxing.com xiaojukeji.com didiglobal.com等域名,种cookie是完全绕不开的。
    image.png
    image.png

    OAuth第三方登录

  • 上述 SSo 是 oauth的实际案例,其他常见的还有微信登录、github登录等。即,当设计到第三方用户登录校验时,都会使用 OAuth2.0 标准。

  • 流程参考 RFC 6749
  • 了解一下大概的流程即可,细节不用太详细看,用到了再说。


    短信验证码登录

  • 用户体验好,无需注册,无需记住密码。

  • 但是,它要花钱。而且还要防止攻击,恶意刷接口的。