jwt方式token验证流程及基于java的JJWT的无状态的身份验证实现详解

标签: jwt

1.Token认证流程

使用基于 Token的身份验证方法,在服务端不需要存储用户的登录记录。大概的流程是这样的。
1.客户端使用用户名跟密码请求登录
2.服务端收到请求,去验证用户名与密码
3.验证成功后,服务端会签发一个 Token,再把这个 Token发送给客户端
4.客户端收到 Token以后可以把它存储起来,比如放在 Cookie里
5.客户端每次向服务端请求资源的时候需要带着服务端签发的 Token
6.服务端收到请求,然后去验证客户端请求里面带着的 Token,如果验证成功,就向客户端返回请求的数据
在这里插入图片描述

2.Token Auth的优势

1.支持跨域访问: Cookie是不允许垮域访问的,这一点对 Token机制是不存在的,前提是传输的用户认证信息通过HTTP头传输.
2.无状态(也称:服务端可扩展行) :Token机制在服务端不需要存储 session信息,因为Token自身包含了所有登录用户的信息,只需要在客户端的 Cookie或本地介质存储状态信息
3.更适用CDN:可以通过内容分发网络请求你服务端的所有资料(如: Javascript,HTML,图片等),而你的服务端只要提供API即可
4.去耦:不需要绑定到一个特定的身份验证方案。 Token可以在任何地方生成,只要在你的API被调用的时候,你可以进行 Token生成调用即可
5.更适用于移动应用:当你的客户端是一个原生平台(iOS, Android, Windows8等)时, Cookie是不被支持的(你需要通过 Cookie容器进行处理),这时采用 Token认证机制就会简单得多。
6.CSRF:因为不再依赖于 Cookie,所以你就不需要考虑对CSRF(跨站请求伪造)的防范。
7.性能:一次网络往返时间(通过数据库查询 session信息.)总比做一次 HMACSHA256计算的 Token验证和解析要费时得多。
8.不需要为登录页面做特殊处理:如果你使用 Protractor做功能测试的时候,不再需要为登录页面做特殊处理
9.基于标准化:你的API可以采用标海化的 JSON Web Token(WT.这个标准已经存在多个后端库(NET, Ruby, Java. Python,PHP)和多家公司的支持(如Firebase. Google, Microsoft)

3.JWT简介

JSON Web Token(JWT)是一个非常轻巧的规范。这个规范允许我们使用T在用户和服务器之间传递安全可靠的信息.。

4.JWT组成

一个JWT实际上就是一个字符串,它由三部分组成,头部、载荷与签名。
头部:存放声明信息,加密、编码方式等。可以被表示成一个JSON对象。
在这里插入图片描述
载荷:存放一些有效信息。
包含三部分:
(1)标准中注册的声名(建议但不强制使用)
在这里插入图片描述
(2)公共的声明
公共的声明可以添加任何的信息,一般添加用户的相关信息或其他业务需要的必要信息但不建议添加敏感信息,因为该部分在客户端可解密。
(3)私有的声明
私有声明是提供者和消费者所共同定义的声明,一般不建议存放敏感信息,因为base64是对称解密的,意味着该部分信息可以归类为明文信息。

这个指的就是自定义的claim。比如前面那个结构举例中的 admin和name都属于自定的Claim。这些claim跟JWT标准规定的 claim区别在于:JWMT规定的 claim,JWT的接收方在拿到WT之后,都知道怎么对这些标准的dam进行验证(还不知道是否能够验证:而private claims不会验证,除非明确告诉接收方要对这些aim进行验证以及规则才行。

载荷示例:
在这里插入图片描述
签证
jwt的第三部分是一个签证信息,这个签证信息由三部分组成:
header ( base64编码后的 )
payload ( base64 89编码后的 )
secret
这个部分需要base64加密后的 header和base64加密后的 payload使用连接组成的字符串,然后通过 header中声明的加密方式进行加盐 secret组合加密,然后就构成了JWT的第三部分。

这三部分base64编码后的字符串用”.“连接,最终构成一个完整的jwt。
示例:在这里插入图片描述
注意: secret是保存在服务器端的,jwt的签发生成也是在服务器端的, secret就是用来进行jwt的签发和jwt的验证,所以,它就是你服务端的私钥,在任何场景都不应该流露出去。一旦客户端得知这个 secret,那就意味着客户端是可以自我签发jwt了。

5.java的JJWT实现JWT

5.1jjwt简介

JJWT是一个提供端到端的JWT创建和验证的Java库。永远免费和开源(Apache License,版本2.0),JJWT很容易使用和理解。它被设计成一个以建筑为中心的流畅界面,隐藏了它的大部分复杂性。

5.1jjwt快速上手

(1)导入依赖

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

(2)生成jwt的token(由于设置了身份的日期,每次生成的token不相同)


public class CreatJwtTest {
    public static void main(String[] args) {
        JwtBuilder jwtBuilder = Jwts.builder()
                .setId("1001")
                .setSubject("老王")//用户名(相当于标准标签中的sub,这个toen面向的用户)
                .setIssuedAt(new Date())//身份日期
                .signWith(SignatureAlgorithm.HS256, "test")//设置编码和盐(密钥)
                .setExpiration(new Date(new Date().getTime()+60000))//设置过期时间(可省)
                .claim("role","admin");//添加自定义的属性(角色)
        System.out.println(jwtBuilder.compact());
    }
}

生成的token:
eyJhbGciOiJIUzI1NiJ9.eyJqdGkiOiIxMDAxIiwic3ViIjoi6ICB546LIiwiaWF0IjoxNTgzOTI1Mzc2LCJleHAiOjE1ODM5MjU0MzZ9.vEypGkkvGAukfZ1e8qP6xIdojvfq-rkkOLZNtaFvh5c
(3)解析jwt的token

public class ParseJwTest {
    public static void main(String[] args) {
        Claims claims = Jwts.parser()
                .setSigningKey("test")
                .parseClaimsJws("eyJhbGciOiJIUzI1NiJ9.eyJqdGkiOiIxMDAxIiwic3ViIjoi6ICB546LIiwiaWF0IjoxNTgzOTI1ODUyLCJleHAiOjE1ODM5MjU5MTIsInJvbGUiOiJhZG1pbiJ9.w1RdNZnZddbai45DwVTPrxBP7d_BKmZBvv796XX1Was")
                .getBody();
        System.out.println("用户id="+claims.getId());
        System.out.println("用户名="+claims.getSubject());
        System.out.println("登陆时间"+new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(claims.getIssuedAt()));
        System.out.println("过期时间"+new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(claims.getExpiration()));
        System.out.println("用户角色"+claims.get("role"));
    }
}

过期时间内结果:

用户id=1001
用户名=老王
登陆时间2020-03-11 19:16:16
过期时间2020-03-11 19:17:16
用户角色admin

超过过期时间结果:

Exception in thread "main" io.jsonwebtoken.ExpiredJwtException: JWT expired at 2020-03-11T19:17:16+0800. Current time: 2020-03-11T19:18:19+0800
	at io.jsonwebtoken.impl.DefaultJwtParser.parse(DefaultJwtParser.java:365)
	at io.jsonwebtoken.impl.DefaultJwtParser.parse(DefaultJwtParser.java:458)
	at io.jsonwebtoken.impl.DefaultJwtParser.parseClaimsJws(DefaultJwtParser.java:518)
	at com.diplomaproject.jwt.ParseJwTest.main(ParseJwTest.java:12)

版权声明:本文为qq_37356556原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/qq_37356556/article/details/104798560