zoukankan      html  css  js  c++  java
  • jwt

    JWT作用
    跨域身份验证
    生成令牌Token签名,认证
    接口安全
    非对称加密(加密和解密时不一致)和对称加密(加密和解密时密码一致)

    JWT工作流程
    只需要服务端生成token,客户端保存这个token,每次请求携带这个token,服务端认证解析就可。

    总结
    密钥secret是保存在服务端的,服务端会根据这个密钥进行生成token和验证,所以需要保护好
    因为json的通用性,所以JWT是可以进行跨语言支持的
    payload部分,JWT可以在自身存储一些其他业务逻辑所必要的非敏感信息
    它不需要在服务端保存会话信息, 所以它易于应用的扩展

    背景知识:

    Authentication和Authorization的区别:

    Authentication:用户认证,指的是验证用户的身份,例如你希望以小A的身份登录,那么应用程序需要通过用户名和密码确认你真的是小A。

    Authorization:授权,指的是确认你的身份之后提供给你权限,例如用户小A可以修改数据,而用户小B只能阅读数据。

    由于http协议是无状态的,每一次请求都无状态。当一个用户通过用户名和密码登录了之后,他的下一个请求不会携带任何状态,应用程序无法知道他的身份,那就必须重新认证。因此我们希望用户登录成功之后的每一次http请求,都能够保存他的登录状态。

    目前主流的用户认证方法有基于token和基于session两种方式。

    基于session的用户认证

    基于session的认证流程如下:

    1. 用户输入其登录信息

    2. 服务器验证信息是否正确,并创建一个session,然后将其存储在数据库中

    3. 服务器为用户生成一个sessionId,将具有sesssionId的Cookie将放置在用户浏览器中

    4. 在后续请求中,会根据数据库验证sessionID,如果有效,则接受请求

    5. 一旦用户注销应用程序,会话将在客户端和服务器端都被销毁

    基于token(令牌)的用户认证

    最常用的是JSON Web Token(jwt):

    header中通常来说由token的生成算法和类型组成。如:

    {
        "alg":"HS256",
        "typ":"JWT"
    }
    

    payload中则用来保存相关的状态信息。如用户id,role,name等。

    {
        "id": 10111000,
        "role": "admin",
        "name": "Leo"
    }
    

    signature部分由header,payload,secret_key三部分生成,其生成公式为:

    HMACSHA256(
      base64UrlEncode(header) + "." +
      base64UrlEncode(payload),
      secret_key)
    

    再将这三个部分组合成header.payload.signature的形式。

    JWT如何工作

    首先用户发出登录请求,服务端根据用户的登录请求进行匹配,如果匹配成功,将相关的信息放入payload中,利用上述算法,加上服务端的密钥生成token,这里需要注意的是secret_key很重要,如果这个泄露的话,客户端就可以随意篡改发送的额外信息,它是信息完整性的保证。生成token后服务端将其返回给客户端,客户端可以在下次请求时,将token一起交给服务端,

    一般来说我们可以将其放在Authorization首部中,这样也就可以避免跨域问题。接下来,服务端根据token进行信息解析,再根据用户信息作出相应的操作。

    1. 用户输入其登录信息

    2. 服务器验证信息是否正确,加密生成并返回已签名的token包含用户基本信息

    3. token储在客户端,例如存在local storage或cookie中

    4. 之后的HTTP请求都将token添加到请求头里

    5. 服务器解码JWT,并且如果令牌有效,则接受请求

    6. 一旦用户注销,令牌将在客户端被销毁,不需要与服务器进行交互一个关键是,令牌是无状态的。后端服务器不需要保存令牌或当前session的记录。

    JWT中token和OAuth的acces_token的区别:参考:https://blog.csdn.net/yutianxu1986/article/details/86510149

    JWT的token是包含用户基本信息的,然后通过加密的方式生成的字符串,服务器端拿到这个token之后不需要再去查询用户基本信息,解析完token之后就能拿到。而access_token则仅仅只是一个token字符串,客户端需要拿着token去获取用户的信息

     Oauth2和jwt是完全不同的两种东西,一个是授权认证的框架,另一种则是认证验证的方式方法(轻量级概念)

     JWT是用在前后端分离, 需要简单的对后台API进行保护时使用.(前后端分离无session, 频繁传用户密码不安全)不能用于社交登录

    jwt的组成

    jwt的认证原理:

    一个jwt实际上就是一个字符串,它由三部分组成,头部载荷签名,这三个部分都是json格式。

    头部(Header)

    头部用于描述关于该JWT的最基本的信息,例如其类型以及签名所用的算法等。

    {
      "typ": "JWT",
      "alg": "HS256"
    }

    在这里,我们说明了这是一个JWT,并且我们所用的签名算法是HS256算法。

    载荷(Payload)

    载荷可以用来放一些不敏感的信息。

    复制代码
    {
        "iss": "John Wu JWT",
        "iat": 1441593502,
        "exp": 1441594722,
        "aud": "www.example.com",
        "sub": "jrocket@example.com",
        "from_user": "B",
        "target_user": "A"
    }
    复制代码

    这里面的前五个字段都是由JWT的标准所定义的。

    • iss: 该JWT的签发者
    • sub: 该JWT所面向的用户
    • aud: 接收该JWT的一方
    • exp(expires): 什么时候过期,这里是一个Unix时间戳
    • iat(issued at): 在什么时候签发的

    把头部和载荷分别进行Base64编码之后得到两个字符串,然后再将这两个编码后的字符串用英文句号.连接在一起(头部在前),形成新的字符串:

    eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJmcm9tX3VzZXIiOiJCIiwidGFyZ2V0X3VzZXIiOiJBIn0

     

    签名(signature)

    最后,我们将上面拼接完的字符串用HS256算法进行加密。在加密的时候,我们还需要提供一个密钥(secret)。加密后的内容也是一个字符串,最后这个字符串就是签名,把这个签名拼接在刚才的字符串后面就能得到完整的jwt。header部分和payload部分如果被篡改,由于篡改者不知道密钥是什么,也无法生成新的signature部分,服务端也就无法通过,在jwt中,消息体是透明的,使用签名可以保证消息不被篡改。

    eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJmcm9tX3VzZXIiOiJCIiwidGFyZ2V0X3VzZXIiOiJBIn0.rSWamyAYwuHCo7IFAgd1oRpSP7nzL7BF5t7ItqpKViM

    区别和优缺点:

    基于session和基于jwt的方式的主要区别就是用户的状态保存的位置,session是保存在服务端的,而jwt是保存在客户端的。

     

    jwt的优点:

    1. 可扩展性好

    应用程序分布式部署的情况下,session需要做多机数据共享,通常可以存在数据库或者redis里面。而jwt不需要。

    2. 无状态

    jwt不在服务端存储任何状态。RESTful API的原则之一是无状态,发出请求时,总会返回带有参数的响应,不会产生附加影响。用户的认证状态引入这种附加影响,这破坏了这一原则。另外jwt的载荷中可以存储一些常用信息,用于交换信息,有效地使用 JWT,可以降低服务器查询数据库的次数。

     

    jwt的缺点:

    1. 安全性

    由于jwt的payload是使用base64编码的,并没有加密,因此jwt中不能存储敏感数据。而session的信息是存在服务端的,相对来说更安全。

    2. 性能

    jwt太长。由于是无状态使用JWT,所有的数据都被放到JWT里,如果还要进行一些数据交换,那载荷会更大,经过编码之后导致jwt非常长,cookie的限制大小一般是4k,cookie很可能放不下,所以jwt一般放在local storage里面。并且用户在系统中的每一次http请求都会把jwt携带在Header里面,http请求的Header可能比Body还要大。而sessionId只是很短的一个字符串,因此使用jwt的http请求比使用session的开销大得多。

    3. 一次性

    无状态是jwt的特点,但也导致了这个问题,jwt是一次性的。想修改里面的内容,就必须签发一个新的jwt。

    (1)无法废弃

    通过上面jwt的验证机制可以看出来,一旦签发一个jwt,在到期之前就会始终有效,无法中途废弃。例如你在payload中存储了一些信息,当信息需要更新时,则重新签发一个jwt,但是由于旧的jwt还没过期,拿着这个旧的jwt依旧可以登录,那登录后服务端从jwt中拿到的信息就是过时的。为了解决这个问题,我们就需要在服务端部署额外的逻辑,例如设置一个黑名单,一旦签发了新的jwt,那么旧的就加入黑名单(比如存到redis里面),避免被再次使用。

    (2)续签

    如果你使用jwt做会话管理,传统的cookie续签方案一般都是框架自带的,session有效期30分钟,30分钟内如果有访问,有效期被刷新至30分钟。一样的道理,要改变jwt的有效时间,就要签发新的jwt。最简单的一种方式是每次请求刷新jwt,即每个http请求都返回一个新的jwt。这个方法不仅暴力不优雅,而且每次请求都要做jwt的加密解密,会带来性能问题。另一种方法是在redis中单独为每个jwt设置过期时间,每次访问时刷新jwt的过期时间。

    可以看出想要破解jwt一次性的特性,就需要在服务端存储jwt的状态。但是引入 redis 之后,就把无状态的jwt硬生生变成了有状态了,违背了jwt的初衷。而且这个方案和session都差不多了。

    总结

    适合使用jwt的场景:

    • 有效期短
    • 只希望被使用一次

    比如,用户注册后发一封邮件让其激活账户,通常邮件中需要有一个链接,这个链接需要具备以下的特性:能够标识用户,该链接具有时效性(通常只允许几小时之内激活),不能被篡改以激活其他可能的账户,一次性的。这种场景就适合使用jwt。

    而由于jwt具有一次性的特性。单点登录和会话管理非常不适合用jwt,如果在服务端部署额外的逻辑存储jwt的状态,那还不如使用session。基于session有很多成熟的框架可以开箱即用,但是用jwt还要自己实现逻辑。

  • 相关阅读:
    测试管理工具
    测试用例--zy
    测试计划和测试用例
    测试用例
    软件测试基础
    异步任务 ---- django-celery
    图片验证码接口
    测试作业
    数据库原理
    HTTPS原理
  • 原文地址:https://www.cnblogs.com/Bkxk/p/10691411.html
Copyright © 2011-2022 走看看