• 基于JWT的Token身份验证


    ​ 身份验证,是指通过一定的手段,完成对用户身份的确认。为了及时的识别发送请求的用户身份,我们调研了常见的几种认证方式,cookie、session和token。

    1.Cookie

    ​ cookie是指浏览器里能够永久存储的一种数据,仅仅是浏览器实现的一种数据存储功能。

    ​ 在用户第一次登陆成功后,服务端就将用户的个人信息等写入cookie对象中,然后将此cookie对象发送给对应的客户端,客户端就存储下这个cookie。此后每次客户端向服务端发送请求时,就带上这个cookie对象,便于服务端进行用户认证和分辨,以决定是否提供服务。

    ​ 由于cookie是存储在客户端的,服务端的仅仅存储一份信息,不会占据太多的磁盘空间,服务端的压力很小。

    ​ 但是由于cookie对象中会存储大量的用户相关信息,而且每个请求都会携带该对象,因此存在传输效率的问题,同时一旦cookie被有心人截获,那么用户信息就被完全暴露,极易导致用户信息的泄露和伪装身份的恶意访问,给软件安全带来一定的隐患。

    2.Session

    ​ session是对cookie的进一步优化。cookie会存储用户的大部分相关信息,从而导致效率低下和安全不能保障等问题,因此session的基本逻辑是将用户信息存储在服务器端,生成一个唯一字符串来对应每一个用户,然后仅将此唯一的字符串返回给客户端。

    ​ 不用传输大量的用户相关数据,保证了传输效率和传输的安全性。一般情况,session存储于cookie中,利用cookie对象来传输session数据。

    ​ 但是此种操作下,每次认证用户发起请求时,服务器需要去创建一个记录来存储信息。当越来越多的用户发请求时,内存的开销也会不断增加。同时如果服务器做了负载均衡,那么下一个操作请求到了另一台服务器的时候session会丢失。

    3.Token

    ​ Token的身份验证是无状态的,客户端登陆成功后,服务端会生成一个token并把它返还给客户端,服务端不再保存该Token。客户端每次发送请求时也会携带Token。由于这里的Token是服务端用自己的密钥签名的,当它接受到客户的Token时,只需要用自己的密钥去验证,就可以判断这个Token是不是自己签发的。

    ​ Token验证的具体流程如下:

    • 客户端使用用户名和密码等向服务端请求登录
    • 服务端通过验证,返回Token给客户端
    • 客户端将Token写入本地缓存,并且后续请求均携带该Token
    • 服务端接受到服务请求,验证Token,验证通过则提供服务,否则拒绝响应。

    ​ 基于Token的身份验证方式,使我们不用将用户信息存在服务器或Session中,此种方式既解决了传输效率和安全问题,同时也解决了服务器内存压力过大的问题。同时由于Token无状态和不存储Session信息,一次,即使对于负载均衡问题,也能够将用户请求传递到任何一台服务器上,并进行解析和验证,而不需要担心请求必须发送到某一特定机器上的问题。

    4.基于JWT的Token身份验证

    ​ 经过以上的调研和分析,我们发现基于Token的身份验证相较于其他的身份验证方式有着更好的适用性和安全性。因此,我们最终选择Token进行身份验证。

    ​ 实施Token的验证方法很多,其中比较常用的便是JWT验证。JWT全称JSON Web Token。JWT标准的Token包括header、payload、signature三部分,中间用点分开,并且使用Base64编码。

    eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c3VyaWQiOjQ0LCJpYXQiOjE7MTk5NjcyMDZ9.UPcMrinrYLr5ZtcWLDqeuxRlUpEQEwk-im8EGyjXTiJk_f0j1bIJWhe34akHfvo0fjbUDK4lo9ADXbUy3a2wmYL_A
    

    ​ 第一部分header,放入token的类型(“JWT”)和算法名称(RS256等);第二部分payload,放入用户的不敏感信息(用户id等);第三部分signature,根据不公开的秘钥加上header中声明的算法,生成特定的签名。最终三部分组合起来即形成了token,发送给客户端。

    ​ Token认证部分,对Token使用不公开的秘钥和声明的算法进行解密分析,若成功解密即通过认证,若解密错误即认证失败。

    5.以Node.js为例的JWT验证

    ​ 此处以RS256加密算法为例进行举例分析。

    ​ 首先生成秘钥文件,以便后续加密使用:

    ssh-keygen -t rsa -b 2048 -f private.key
    

    ​ 随后根据秘钥,创建对应的公钥:

    openssl rsa -in private.key -pubout -outform PEM -out public.key
    

    ​ 秘钥创建完成之后,即可进行Token的签发与认证。

    JWT的签发
    const jwt = require('jsonwebtoken')
    const fs = require('fs')
    const path = require('path')
    
    async function generateToken(data) {
        let creatTime = Math.floor(Date.now() / 1000);
        const privateKey = await fs.readFileSync(path.join(__dirname, 'xxxx.key'));
        let obj = {
            data,
            expire: creatTime + 60 * 30
        }
        const token = jwt.sign(obj, privateKey, {algorithm: 'RS256'});
        return token;
    }
    
    

    以RS256算法和不公开的私钥,以及待存储数据和过期时间进行加密和签证,以生成最终可用的token返回给客户端。

    JWT的验证
    const jwt = require('jsonwebtoken')
    const fs = require('fs')
    const path = require('path')
    
    async function verifyToken(token) {
        const publicKey = fs.readFileSync(path.join(__dirname, 'xxx.key'));
        let result;
        try {
            result = jwt.verify(token, publicKey)
            let {exp = 0} = result, current = Math.floor(Date.now() / 1000);
            if (current <= exp) {
                res = result;
            }
        } catch (e) {
            result = 'err';
        }
        return result;
    }
    

    对Token进行解密验证,并验证Token是否过期。

    Token拦截器
    app.use(function (req, res, next) {
        if (req._parsedUrl.pathname != '/login') {
            let tk = req.headers.authorization;
            if (tk.substr(0, 5) == 'test-') {
                tk = tk.substring(5);
            }
            token.verifyToken(tk).then( function (result) {
                if (result == 'err') {
                    res.send({
                        "data": {},
                        "code": 0,
                        "msg": "Token is wrong!"
                    })
                } 
                else {
                    next();
                }
            });
        }
        else {
          next();
        }
    }) 
    

    在所有请求到来时,首先进行Token认证,认证通过则提供服务,否则直接拒绝服务。

  • 相关阅读:
    带提示范围的猜数小游戏--python
    python中字符串的常见操作
    html表单相关标签及属性
    CSS常用属性
    python装饰器
    python闭包的概念及使用
    nuxt.js实战踩坑记录
    vuex填坑记录
    prerender-spa-plugin预处理vue项目实践
    node+express第一次实战踩坑记录
  • 原文地址:https://www.cnblogs.com/cyy---336699/p/14745471.html
Copyright © 2020-2023  润新知