登录鉴权session和JWT

Cookie和Session

流程: 浏览器post账号密码,服务端校验成功,将session储存(session是存在于服务端的),
给前端设施cookie值(sessionID),以后每次请求携带sessionID.

安装express-session,自动生成sessionID
npm i express-sission
----------------------------------------------
app.js中引入
const session = require("express-session")
// 注册
app.use(session({
  name: "system", // cookie名字
  secret: "123qwsdqwe", // 密钥 可以随便写
  cookie: {
    maxAge: 1000 * 60 * 60,  // 过期时间,毫秒
    secure: false, // false在http中可以获取, true必须在https中才能获取到
  },
  rolling: true, // 超时前刷新,cookie都会重新计时
  resave: true, // 重新设置session后,会重新设置session时间 
  saveUninitialized: true, // 初始时是否生成cookie, 不影响业务, true时第一次生成的cookie也是无效的
}))
-------------------------------------------------------
登陆接口调用成功时设置session
// 登陆查询
async function selectUser(req, res, next) {
  const {username, password } = req.body
  const data = await loginService.selectUser(username, password)
  if( data.length !== 0 ) {
    // 设置session
    req.session.user = data[0] // 设置session对象,挂载信息,挂在布尔值也行(就是登陆成功存储session这个过程)默认存储在内存中
    res.send({
      success: true,
      msg: "登陆成功",
      data
    })
  } else {
    res.send({success: false, msg: "用户名或密码错误", data})
  }
}
----------------------------------------------------------------------------
渲染页面是判断是否具有有效的session
router.get('/', function(req, res, next) {
  // 跳转页面时判断一下req.session.user是否存在
  if(req.session.user) {
    res.render('index', { title: 'Express' });
  } else {
    res.redirect("/login")
  }
});
此时即使cookie过期,只要没有刷新页面,其他接口都可以正常被访问.需要设置中间件解决该问题
app.js中设置中间件
// 设置应用级中间件,进行session过期校验
app.use((req, res, next) => {
  // 先排除掉login相关的路由接口,不然会陷入死循环
  if(req.url.includes("login")){
    next()
    return
  }
  if(req.session.user){
    // 重新设置session,达到每次访问接口重新计算session过期时间
    req.session.date = Date.now()
    next()
  } else {
    // 判断 是接口,返回错误码, 不是接口 就可以重定向,接口只会返回数据, 重定向是无法生效的
    res.redirect("/login")
  }

})

退出 销毁session

// 退出登陆
async function logout(req, res, next) {
  req.session.destroy(() => {
    res.send({
      success: true,
      msg: "销毁成功"
    })
  })
}

持久化存储session
connect-mongo中间件

安装模块
npm i connect-mongo
----------------------------------
app.js引入中间件
const MongoStore = require("connect-mongo")
----------------------------------------------------
注册session中间件
app.use(session({
  name: "system", // cookie名字
  secret: "123qwsdqwe", // 密钥 可以随便写
  cookie: {
    maxAge: 1000 * 60 * 60,  // 过期时间,毫秒
    secure: false, // false在http中可以获取, true必须在https中才能获取到
  },
  resave: true, // 每次访问接口,cookie都会重新计时, false只会按第一次生成的时间计时 
  saveUninitialized: false, // 初始时是否生成cookie, 不影响业务, true时第一次生成的cookie也是无效的
  store: MongoStore.create({
    mongoUrl: "mongodb://127.0.0.1:27017/Wzx_test_session", // 新创建了一个数据库, 不是表
    ttl: 1000 * 60 * 60 // 过期时间  一定要与上面的保持一致
  })
}))

JWT

安装模块
npm i jsonwebtoken
-------------------------------------------------
app.js中引入
const jwt = require("jsonwebtoken")
----------------------------------------------
加密
let token = jwt.sign({
  data: "需要加密的数据",
  "srcret", // 密钥
  {expiresIn: 60 * 60}, // 过期时间(秒)
})
-----------------------------------------------------
校验
let decoded = jwt.verify(token, "srcret") // 密钥要一致
封装
JWT.js文件中
// 引入模块
const jwt = require("jsonwebtoken")
// 设置密钥
const srcret = "Wzx-anyData" 
const JWT = {
  generate(value, expiresIn){
    return jwt.sign(value, srcret, {expiresIn: expiresIn})
  },

  verify(token){
    try {
      return jwt.verify(token, srcret)
    } catch (error) {
      return false
    }
  },
}

module.exports = JWT
登陆时设置token, 放在header的Authorization// 登陆查询
async function selectUser(req, res, next) {
  const {username, password } = req.body
  const data = await loginService.selectUser(username, password)
  if( data.length !== 0 ) {
    // 设置token
    const token = JWT.generate({
      _id: data[0]._id,
      username: data[0].username
    }, "1h")
    // token返回在header中
    res.header("Authorization", token)
    res.send({
      success: true,
      msg: "登陆成功",
      data,
    })
  } else {
    res.send({success: false, msg: "用户名或密码错误", data})
  }
}
--------------------------------------------------------------------
前端在axios的响应拦截器中存储token
axios.interceptors.response.use((res) => {
  const { authorization } = res.headers
  authorization  && localStorage.setItem("token", authorization )
  return res
}, (err) => {
  // token失效  后端设置的401
  if(err.response.status === 401) {
    // 前端删除token
    localStorage.removeItem("token")
  }
  return Promise.reject(err)
})
------------------------------------------------------------
前端每次请求时携带token
axios.interceptors.request.use((config) => {
  const token = localStorage.getItem("token")
  // 习惯拼接Bearer加空格token
  config.headers.authorization = `Bearer ${token}`
  return config
})
--------------------------------------------------------------------
后端校验token
app.use((req, res, next) => {
  // 先排除掉login相关的路由接口,不然会陷入死循环
  if(req.url.includes("login")){
    next()
    return
  }
  // 可选链 req.headers["authorization"]为true时, 才会执行split
  // 如果是第一次进入,没有token, 此时的req.headers["authorization"]是一个null字符串
  const token = req.headers["authorization"]?.split(" ")[1]
  if(token) {
    const payload = JWT.verify(token)
    if(payload){
      // 重新计算token过期时间
      const newToken = JWT.generate({
        _id: payload._id,
        username: payload.username
      }, "1h")
      res.header("Authorization", newToken)
      next()
    } else {
      res.status(401).send({
        success: false,
        msg: "token过期"
      })
    }
  } else {
    next()
  }
})
  • 8
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值