Java来回顾下JWT知识点,了解一下什么是JWT?

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Java来回顾下JWT知识点,了解一下什么是JWT?相关的知识,希望对你有一定的参考价值。

(回顾下JWT知识点)

1. 什么是JWT

在介绍JWT之前,我们先来回顾一下利用token进行用户身份验证的流程:

这种基于token的认证方式相比传统的session认证方式更节约服务器资源,并且对移动端和分布式更加友好。其优点如下:

而JWT就是上述流程当中token的一种具体实现方式,其全称是JSON Web Token。是基于Json的一个公开规范,这个规范允许我们使用JWT在用户和服务器之间传递安全可靠的信息,他的两大使用场景是:认证和数据交换。

通俗地说,JWT的本质就是一个字符串,它是将用户信息保存到一个Json字符串中,然后进行编码后得到一个JWT token,并且这个JWT token带有签名信息,接收后可以校验是否被篡改,所以可以用于在各方之间安全地将信息作为Json对象传输。

JWT的认证流程如下:

  • 1.首先,前端通过Web表单将自己的用户名和密码发送到后端的接口,这个过程一般是一个POST请求。建议的方式是通过SSL加密的传输(HTTPS),从而避免敏感信息被嗅探。
  • 2.后端核对用户名和密码成功后,将包含用户信息的数据作为JWT的Payload,将其与JWT Header分别进行Base64编码拼接后签名,形成一个JWT Token,形成的JWT Token就是一个如同lll.zzz.xxx的字符串。
  • 3.后端将JWT Token字符串作为登录成功的结果返回给前端。前端可以将返回的结果保存在浏览器中,退出登录时删除保存的JWT Token即可。
  • 4.前端在每次请求时将JWT Token放入HTTP请求头中的Authorization属性中(解决XSS和XSRF问题)。
  • 5.后端检查前端传过来的JWT Token,验证其有效性,比如检查签名是否正确、是否过期、token的接收方是否是自己等等。
  • 6.验证通过后,后端解析出JWT Token中包含的用户信息,进行其他逻辑操作(一般是根据用户信息得到权限等),返回结果。

2. 为什么要用JWT

传统Session认证的弊端 我们知道HTTP本身是一种无状态的协议,这就意味着如果用户向我们的应用提供了用户名和密码来进行用户认证,认证通过后HTTP协议不会记录下认证后的状态,那么下一次请求时,用户还要再一次进行认证,因为根据HTTP协议,我们并不知道是哪个用户发出的请求,所以为了让我们的应用能识别是哪个用户发出的请求,我们只能在用户首次登录成功后,在服务器存储一份用户登录的信息,这份登录信息会在响应时传递给浏览器,告诉其保存为cookie,以便下次请求时发送给我们的应用,这样我们的应用就能识别请求来自哪个用户了,这是传统的基于session认证的过程。

3. JWT认证的优势

对比传统的session认证方式,JWT的优势是:

4. JWT结构有哪些组成呢?

JWT由3部分组成:标头(Header)、有效载荷(Payload)和签名(Signature)。在传输的时候,会将JWT的3部分分别进行Base64编码后用.进行连接形成最终传输的字符串。

JWTString=Base64(Header).Base64(Payload).HMACSHA256(base64UrlEncode(header)+"."+base64UrlEncode(payload),secret);
  • 1.Header

JWT头是一个描述JWT元数据的JSON对象,alg属性表示签名使用的算法,默认为HMAC SHA256(写为HS256);typ属性表示令牌的类型,JWT令牌统一写为JWT。最后,使用Base64 URL算法将上述JSON对象转换为字符串保存。

  • 2.Payload

有效载荷部分,是JWT的主体内容部分,也是一个JSON对象,包含需要传递的数据。 JWT指定七个默认字段供选择。 这些预定义的字段并不要求强制使用。除以上默认字段外,我们还可以自定义私有字段,一般会把包含用户信息的数据放到payload中。

请注意,默认情况下JWT是未加密的,因为只是采用base64算法,拿到JWT字符串后可以转换回原本的JSON数据,任何人都可以解读其内容,因此不要构建隐私信息字段,比如用户的密码一定不能保存到JWT中,以防止信息泄露。

JWT只是适合在网络中传输一些非敏感的信息。

  • 3.签名(Signature)

签名哈希部分是对上面两部分数据签名,需要使用base64编码后的header和payload数据,通过指定的算法生成哈希,以确保数据不会被篡改。首先,需要指定一个密钥(secret)。该密码仅仅为保存在服务器中,并且不能向用户公开。然后,使用header中指定的签名算法(默认情况下为HMAC SHA256)根据以下公式生成签名。

注意JWT每部分的作用,在服务端接收到客户端发送过来的JWT token之后:

header和payload可以直接利用base64解码出原文,从header中获取哈希签名的算法,从payload中获取有效数据 signature由于使用了不可逆的加密算法,无法解码出原文,它的作用是校验token有没有被篡改。服务端获取header中的加密算法之后,利用该算法加上secretKey对header、payload进行加密,比对加密后的数据和客户端发送过来的是否一致。注意secretKey只能保存在服务端,而且对于不同的加密算法其含义有所不同,一般对于MD5类型的摘要加密算法,secretKey实际上代表的是盐值。

#3. JWT的种类有哪些呢? 其实JWT(JSON Web Token)指的是一种规范,这种规范允许我们使用JWT在两个组织之间传递安全可靠的信息,JWT的具体实现可以分为以下几种:

nonsecure JWT 未经过签名,不安全的JWT。其header部分没有指定签名算法,并且也没有Signature部分。

JWS 也就是JWT Signature,其结构就是在之前nonsecure JWT的基础上,在头部声明签名算法,并在最后添加上签名。创建签名,是保证jwt不能被他人随意篡改。我们通常使用的JWT一般都是JWS

为了完成签名,除了用到header信息和payload信息外,还需要算法的密钥,也就是secretKey。加密的算法一般有2类:

对称加密: secretKey指加密密钥,可以生成签名与验签 非对称加密: secretKey指私钥,只用来生成签名,不能用来验签(验签用的是公钥)

JWT的密钥或者密钥对,一般统一称为JSON Web Key,也就是JWK。 到目前为止,jwt的签名算法有三种:

5. Java中使用JWT

官网推荐了6个Java使用JWT的开源库,其中比较推荐使用的是java-jwt和jjwt-root Java-jwt
使用到: 对称签名 首先引入依赖

   <dependency>
       <groupId>io.jsonwebtoken</groupId>
       <artifactId>jjwt</artifactId>
       <version>0.9.0</version>
   </dependency>

生成JWT的token

@Value("$auth.secret-key")
 private String secretKey;
 
 public String generateJwtToken(String userId, String userName, List<Long> roleIds) 
        Date now = new Date();
        return JWT.create().withSubject(userId)
                .withIssuedAt(now)
                .withClaim("userName", userName)
                .withClaim("userId", userId)
                .withClaim("roleIds", roleIds)
                .sign(HMACSM3Algorithm.getInstance(secretKey));
    

解析JWT字符串

 @Override
    public BasePrincipal getUserDetailsFromJwt(String token) 
        DecodedJWT decodedJWT = JWT.decode(token);
        return new BasePrincipal(decodedJWT.getClaim("userId").asString(),
                decodedJWT.getClaim("userName").asString(),
                null, null, null, Collections.emptyList());
    

实际开发中的应用

在实际的SpringBoot项目中,一般我们可以用如下流程做登录:

第一步:在登录验证通过后,给用户生成一个对应的随机token(注意这个token不是指jwt,可以用uuid等算法生成), 第二步:然后将这个token作为key的一部分,用户信息作为value存入Redis,并设置过期时间,这个过期时间就是登录失效的时间 将第1步中生成的随机token作为JWT的payload生成JWT字符串返回给前端 前端之后每次请求都在请求头中的Authorization字段中携带JWT字符串 后端定义一个拦截器,每次收到前端请求时,都先从请求头中的Authorization字段中取出JWT字符串并进行验证,验证通过后解析出payload中的随机token,然后再用这个随机token得到key,从Redis中获取用户信息,如果能获取到就说明用户已经登录。

在实际开发中需要用下列手段来增加JWT的安全性:

以上是关于Java来回顾下JWT知识点,了解一下什么是JWT?的主要内容,如果未能解决你的问题,请参考以下文章

Java实现Token登录验证(基于JWT的token认证实现)

Spring Boot集成JSON Web Token(JWT)

鉴权必须了解的5个知识点:cookie,session,token,jwt,单点登录

spring cloud实战与思考 JWT之Token主动失效

JWT了解一下

玩转 SpringBoot 2 之整合 JWT 上篇