#登录鉴权——(cookie&session)&JWT

登录鉴权是业务系统中常见的功能:

​ 当登录系统时,如果不是系统的内置用户,则需要提示并引导用户注册,如果是已经注册过的用户,在登录时要判断其输入的用户名和密码是否匹配,如匹配则跳转至首页,如不匹配,则提示用户名和密码错误重新输入;另一种场景是当登录安全性较高的系统时,假设长时间停在某一个页面未进行其他操作,比如某些银行的移动客户端,停留在某个页面三十分钟未进行操作,再次进入的时候会提示长时间未操作请重新登录,然后引导跳转至登录界面重新登录。

​ 下面概述一下实现原理:

​ 在数据库我们会默认留一个用户,并且分发给每个用户一个令牌,首次登录需要判断输入的用户名和密码是否正确,如不正确,需要提示用户输入正确的用户名和密码;如正确,判断令牌是否在有效时间内,如果有效则正常登录进行操作,如果失效则提示重新登录并生成新的令牌传给后端进行校验。

​ 以上功能需要前后端配合实现,下面分别记录一下利用cookie和session实现校验以及利用JWT(JSONWebToken)来实现

一、cookie和session实现登录鉴权

cookie介绍:

Cookie是一种存储在客户端浏览器中的数据,它的作用是让浏览器记住一些信息,以便在后续的请求中使用。当浏览器访问某个网站时,它会发送一个 请求给服务器,请求的内容会包含一些信息,如用户ID、访问时间等。服务器在收到请求后会生成一个Cookie,并将它存储在客户端浏览器中。在后续的 请求中**,浏览器会将生成的Cookie再次发送给服务器**,服务器在接收到Cookie后,可以识别出它是之前发送过的请求,从而简化后续请求的处理流程,提 高网站的性能。

​ cookie是有大小限制的,它的大小取决于服务器和浏览器设置的具体限制,当cookie过大时会造成浏览器缓存过多,影响服务器的性能。

​ 总的来说,Cookie的作用是提高网站的性能和用户体验,它可以让服务器更好地理解用户的行为,从而生成更个性化的内容,或提供更好的搜索和登录体 验。

总结:大小受限,存储在浏览器的客户端,可手动设置,会随每次请求传到服务端

session介绍:

Session是一种在Web应用程序中实现用户状态的方法。通过Session,Web应用程序可以在用户登录后将用户状态保存在客户端的浏览器中,以便在后续的请求中使用。具体来说,Session可以用于以下场景:

用户登录时保存用户信息:用户在登录时,服务器将用户信息保存到Session中,然后在后续的请求中使用这些信息。

保存用户信息:用户在浏览某个页面时,可以将一些信息(如登录状态、购物车内容等)保存在Session中,以便在后续的页面中使用。

记住用户的搜索历史:当用户在搜索框中输入关键字并点击搜索时,服务器会将用户的搜索历史保存在Session中,以便在用户后续的搜索请求中使用。
总的来说,Session可以提高Web应用程序的用户体验和性能,因为它可以让服务器记住用户的特定信息,并在后续的请求中使用这些信息,从而简化服务器端的工作流程。

在Web应用程序中,Session的大小限制通常取决于服务器端和客户端的具体设置。
服务器端:在服务器端,我们可以通过在Session中设置过期时间来限制其大小。通过设置过期时间,服务器可以确保在一定的时间内使用完保存的信息,从而避免过大的Session对服务器性能造成影响。
客户端:**在客户端,我们可以通过在浏览器设置Cookie大小时限来限制其大小。**通过设置Cookie大小时限,用户可以确保浏览器不会保存过多的信息,从而避免影响后续请求的性能。

​ 总结:存储在客户端,方便存取,大小需要限制

实现流程

​ 将每次用户登录的相关信息(用户名,id等)都存储在cookie中,随着请求传递到服务端,然后后端将这些信息单独存储在数据库中生成一个id, 将这个id返回给客户端,客户端将接收到的sessionID存储在localStorage或者sessionStorage中,随后在每次向服务端的请求中客户端都将读取并将该值写入cookie传递给服务端,服务端判断max-age和cookie对应关系的算法来判断传入的cookie是否是有效的,如果是则返回正确的数据,如果不是则返回401,提示重新登录。

由于暂时写的不是前后端分离的,我们依然利用ejs模板来写前端,后端采用插件:express-session

首先安装express-session: npm i express-session

1.在app.js中进行配置:
1.在app.js中进行配置:
// express-session引入
const expressSession = require('express-session')

//注册session中间件
// [注]:配置一定要放在路由和api文件之前
app.use(expressSession({
      name: 'cjSystem', //名称
      secret: 'secret',//密钥
      cookie: {
        maxAge: 1000 * 60 * 60 //一个小时
      },
      resave: true, //表示重新设置session之后,cookie的过期时间会重新计算,必须设置
      saveUninitialized: true, //表示一开始就设置cookie,但是此时cookie是无效的,除非登录之后设置
      secure: false,//值为true时表示只能在https中访问cookie,为false时表示可以在http中访问cookie
      store:MongoStore.create({
          mongoUrl:'mongodb://10.45.126.221:27017/cj_session',//新创建一个数据库 存储session
          ttl: 1000 * 60 *60 //与上述cookie的时间保持一致
      })
    }
))

// 设置中间件: session过期校验
app.use((req,res,next) => {
    //排除login相关的路由
    if(req.url.includes('login')){
        next()
    }else if(req.session.user){
        // 重新设置session,刷新cookie的有效时间
        req.session.date = Date()
        next()
    }else{
        //api是接口 返回500
        //是路由
        req.url.includes('api') ? res.status(401).send({ok: 1}):res.redirect('/login')
    }
})

2.登录接口处理
 loginUser:async (req,res) =>{
        const data = await userService.loginUser(req,res)
        if(data.length){
            // 登录成功,设置session,req.session会自动匹配cookie生成的一个对象,挂载一些字段方便后来判断
            // 默认存储在内存中: 当服务器重启之后内存被释放,导致session丢失
             req.session.user = data[0]
             res.send({data: 0})

        }else{
            res.send({data: 1})
        }
    },
3.绘制首页时进行判断:
var express = require('express');
var router = express.Router();

const JWT = require('../utils/jwt')
/* GET home page. */
router.get('/', function(req, res, next) {
  // 判断req.session
  if(req.session.user){
    res.render('index', { title: 'Express' });
  }else{
    // res.render('login', { title: 'Express' });
    res.redirect('/login')
  }
  res.render('index', { title: 'Express' });
  // console.log(res.header)
  // if(res.header.Authorization){
  //
  //
  // }else{
  //   res.redirect('/login')
  // }

});

最后在前端进行配合设置即可。

二、JWT实现鉴权

1.JWT简介:

​ JWT是一种用于在分布式系统中跟踪用户身份和授权的开放标准。JWT是由国际数据公司(IDC)制定的,旨在为用户提供安全、可靠的在线身份认证和授权服务。在实际应用中,JWT可用于多种场景,如用户登录、注册、访问API、支付等。JWT的使用可以提高系统的安全性和可扩展性,同时降低开发者的负担。

核心概念:
  • Access Token:访问令牌是JWT的核心概念。它是一种数字身份证明,用于证明用户有权访问某个应用程序或系统的数据和功能。访问令牌包含有关用户身份和权限的信息,以及用于验证用户身份的令牌类型。
  • Claims:声明是JWT中另一个重要的概念。它是指描述用户身份和访问权限的声明。声明包括用户ID、用户角色、权限等信息,用于验证访问令牌的有效性。
  • Expiration Time:到期时间是JWT的一个重要属性。它指定了访问令牌的寿命,即在多长时间内该令牌将被认为是失效的。
  • Signature:签名是JWT中的一个重要概念。它是指对数据进行签名,以验证数据的完整性和真实性。
  • Token Generation Model:令牌生成模型是JWT中的另一个重要概念。它是指用于生成访问令牌的两种方法,即预先分配令牌和基于用户身份生成令牌。
  • Subject:主体是JWT中的一个重要概念。它是指持有访问令牌的用户,也就是可以访问令牌所包含数据的用户。
  • Role-Based Access Control:基于角色的访问控制是JWT中的一种访问控制方法。它是指根据用户角色来控制访问权限的方法。
  • Protocol:协议是JWT中必不可少的一部分。它是指用于在JWT和应用程序之间传递数据的协议,如HTTP。
加密之后的token组成:
  • 用户ID:这是JWT中非常重要的一个部分,用于标识用户身份。

  • 令牌类型:这是一种标识符,用于指示该令牌用于什么用途。例如,表示该令牌用于访问某个数据。

  • 有效期限:这是一种指示符,用于指示该令牌的有效期限。

  • 签名:这是一种数字签名,用于验证该令牌的真实性和完整性。

  • 数据:这是令牌中包含的数据,通常是一个JSON格式的字符串。

  • 其他信息:包括令牌的序列号、创建时间等。

这些组成部分通常包括在JWT的加密过程中,以确保JWT的安全性和可靠性。

JWT的检验步骤:

  1. 检查JWT的有效期:在获取JWT时,需要检查JWT中是否包含有效期限。如果JWT中包含有效期限,则需要在使用JWT时检查JWT的有效期。

  2. 比较JWT的有效期和当前时间:检查JWT的有效期是否已经过期,如果已经过期,则需要重新生成JWT。

  3. 检查JWT的状态:在生成JWT时,通常会设置一个状态字段,用于指示JWT是否有效。在JWT使用过程中,需要检查JWT的状态,如果状态为无效,则需要重新生成JWT

    通过以上步骤,可以确保JWT始终有效,从而提高JWT的安全性和可靠性。

JWT的简单使用:

//测试token的加密与验证
const jwt  = require('jsonwebtoken')
const token = jwt.sign({
  data:'foobar' //要加密的数据
},'secret',{expiresIn: '10s'}) //'secret'是加密的密钥
console.log(token)
//eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJkYXRhIjoiZm9vYmFyIiwiaWF0IjoxNjkzMjkyODM2LCJleHAiOjE2OTMyOTI4NDZ9
// .70S7HLfs42OLASGP5b-dL3yeE7h0hxrIq0_lUZzYFiA

setTimeout(() => {
  var decode = jwt.verify(token,'secret')
  console.log(decode)
},11000)

const token = JWT.generate({data:'footbar'},10000)
const register = JWT.verify(token)
console.log(register) //true

实现流程

1.封装JWT
const jwt = require('jsonwebtoken')
const secret = 'secret'
const JWT = {
    generate(value,expires){
       return jwt.sign(value,secret,{expiresIn: expires}) //参数:加密数据,密钥,过期时间
    },
    verify(token){
        try {
            return !!jwt.verify(token,secret)
        }catch {js
            return false
        }
    }
}
module.exports = JWT
2.配置和使用

1.app.js中设置中间件进行配置

const JWT = require('./utils/jwt')
// 校验token
app.use((req, res, next) => {
    if (req.url.includes('login')) {
        next()
        return
    }
    console.log(req.headers['authorization'])
    const token = req.headers['authorization']?.split(' ')[1]
    if (token) {
        console.log(token)
        const payload = JWT.verify(token)
        if (payload) {
            const newToken = JWT.generate({payload}, "10h")
            next()
        } else {
            res.status(401).send({errorCode: -1})
        }
        // next()
    } else {
        next()
    }


})

2.登录接口进行设置

// 登录校验
router.post('/login', (req, res) => {
    const {username, password} = req.body
    let temp = []
    UserModel.find({username, password}).then(data => {
        if (data.length > 0) {
            //设置token
            const token = JWT.generate({data: data[0]}, '10s')
            // token放在header中
            res.header('Authorization', token)
            res.send({
                data: 1
            })
        } else {
            res.send({
                data: 0
            })
        }
    })

})

【注】:JWT只适用于前后端分离的开发场景中,当每个请求传递至服务端时,都会使用JWT重新校验并更新token,对应的前端每个接口都应获取并将token存储至session中,在每次请求中重新读取并携带传递给服务端。为方便起见,建议使用axios的拦截器功能,在请求拦截和响应拦截中都添加判断token的功能。简单实现如下:

  <!--        拦截器配置-->
        // 添加请求拦截器: 请求之前所作的处理
        axios.interceptors.request.use(function (config) {
            // 在发送请求之前做些什么
            const token = localStorage.getItem('token')
            config.headers.Authorization = `Bearer ${token}`

            return config;
        }, function (error) {
            // 对请求错误做些什么
            console.log(error)
            if (error.response.status === 401) {
                localStorage.removeItem('token')
                location.href('/')
            }
            return Promise.reject(error);
        });

        // 添加响应拦截器:请求成功后第一个调用的方法
        axios.interceptors.response.use(function (response) {
            // 2xx 范围内的状态码都会触发该函数。
            // 对响应数据做点什么
            const {authorization} = response.headers
            authorization && localStorage.setItem('token', authorization)
            return response;
        }, function (error) {
            // 超出 2xx 范围的状态码都会触发该函数。
            // 对响应错误做点什么
            return Promise.reject(error);
        });

别忘了安装axios库哦!

三、两种实现方式对比

cookie-session: cookie容易被伪造,形成CSRF(相关链接:https://blog.csdn.net/nnmmbb/article/details/106137473)
JWT: token比较安全,但是由于加密算法生成的token字段较长,传输更消耗流量一些,并且只适用于前后端分离的项目,对于服务端模板渲染的就无能为力了。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
CookieSessionJWT都是用于在Web应用程序中存储和验证用户身份的机制。 Cookie是在服务器生成后发送给浏览器存储的一小段文本信息。它可以包含用户身份验证信息或其他需要在不同请求之间保持状态的数据。Cookie有一个有效期,一般会设置为较长的时间,比如一周或两周左右。这样可以在用户下次访问网站时继续使用该CookieSession是服务器上的一种机制,用于跟踪和存储用户的会话状态。它在服务器端存储用户的身份验证信息和其他会话数据。与Cookie不同,Session数据存储在服务器上,而不是浏览器中。Session的有效期一般设置较短,比如24分钟或0.5小时,用于提高安全性。 JWT(JSON Web Token)是一种用于身份验证和授权的开放标准。它是一种基于JSON的数据格式,包含了用户的身份验证信息和其他元数据,并使用数字签名进行验证。JWT通常用于通过令牌的方式来验证用户身份。它的优点是无需在服务器上存储会话信息,只需通过数字签名即可验证令牌的真实性。因此,JWT适用于分布式系统和无状态应用程序。 总结起来,Cookie是将信息存储在浏览器端,Session是将信息存储在服务器端,而JWT则是通过令牌的方式进行身份验证和授权。每种机制都有其适用的场景和优缺点,需要根据具体的应用需求选择合适的方案。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *3* [Cookie,Session,JWT](https://blog.csdn.net/m0_70273331/article/details/124551071)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 50%"] - *2* [CookieSessionJWT的详解](https://blog.csdn.net/weixin_35695511/article/details/105040183)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值