常见认证机制及JWT介绍

常见认证机制

HTTP Basic Auth

​ HTTP Basic Auth就是每次请求都会提供用户的用户名和密码 , 也就是说它是使用最简单的认证方式,只需要提供密码即可。

​ 由于它每次都需要将密码暴露给第三方,因此他是不安全的,现在使用也越来越少。

Cookie Auth

​ Cookie认证机制也就是每次请求认证都会在服务端创建一个session对象,同时在浏览器端创建一个Cookie对象。 通过客户端上带的Cooke来和服务器端的session对象匹配来实现验证。

OAuth(开放授权)

​ 它属于一个开放的授权标准,允许用户让第三方应用访问该用户在某一web服务上存储私密资源,且不用将用户名和密码提供给第三方。 这样说可能不明白,呢你们想一下在使用app时,有没有用到微信登录、qq登录等第三方登录。

​ Oauth相当于提供给用户一个令牌,来去访问。而不是需要用户名和密码去访问。

类似于这种,就相当于授予令牌 来直接去用第三方账户登录:

常见认证机制及JWT介绍_第1张图片

​ 请求流程:(图片来源于网络)

常见认证机制及JWT介绍_第2张图片

Token Auth和 Cookie机制的优点

  • 支持跨域访问 ,cookie是不允许的 (跨域访问:在当前网站上向另一个网站发送请求获取数据的过程就是跨域。)
  • 无状态:token不需要存储session信息,Token自身包含了所有登录用户的信息。
  • 去耦:不需要绑定一个特定的身份验证方案。
  • 有效避免了CSRF攻击(跨站请求伪造)
  • 标准化:API可以采用标准化的JWT。 这个标准已经存在了多个后端库。(.NET,Java,Python,PHP)

JWT介绍

​ jwt (JSON Web Token) 属于一个规范,它定义了一种简洁的、自身包含协议的格式,用于在通信双方传递json对象。适合使用在分布式站点的单点登录(SSO)场景。

官网:https://jwt.io/

JWT优点:

  • 基于json,方便解析。
  • 在令牌中自定义内容,方便拓展。
  • 安全性高
  • 资源服务可以不依赖认证服务就能完成授权。

缺点: 字符串过长,占用存储空间过大。

JWT由三部分组成,分别是:头部,载荷和签名。 JWT实际上是一个字符串,以 . 来分割开。

头部:用于描述关于该JWT的最基本的信息。 (官方示例)

alg:采用的算法; typ:类型

常见认证机制及JWT介绍_第3张图片

​ 这里我们对头部的json字符串进行BASE64编码 ,eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9Base64是可以基于64个可打印字符来表示二进制的表示方法。 其中每六个比特为一个单元。 JDK也为我们提供了相关的方法可以去完成BASE64的编码和解码。

载荷:也就是存放有效信息的地方。

​ 它包含了三种声明方式:

  • 标准中注册的声明
  • 公共声明
  • 私有声明

常见认证机制及JWT介绍_第4张图片

​ sub:jwt所面向的用户

​ iat:jwt的签发时间

无论是哪种方式,都不建议存放隐私信息,因为这部分是明文可以进行解密的。

签名:也就是签证信息。

这个签证信息由三部分组成,header、payload、secret(保密)

其中:

secret:存放在服务器端,它是用来进行jwt的签发和jwt的验证,也就相当于密钥。 因此这个不能泄露,如果客户端知道了,也就意味着客户端可以自己签发jwt。

常见认证机制及JWT介绍_第5张图片

有兴趣的同学可以去官网试一下,每一个secret不一样对应的token也不相同。

JWTDemo

导入相关依赖

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

创建token:

    public void testCreateToken(){
//        创建Jwtbuilder对象
        JwtBuilder jwtBuilder = Jwts.builder()
//                声明标识:{jwt:8888}
                .setId("1111")
//                主体,用户 {sub:1234567890}
                .setSubject("1234567890")
//                创建日期 {ita:"xxxx"}
                .setIssuedAt(new Date())
//                采用编码算法:hs256
                .signWith(SignatureAlgorithm.HS256,"xxxx");

获取token:

​ 前面介绍过 ,JWT由三部分组成,是一个字符串且由 . 进行分割。 因此这里我们直接进行字符串分割,然后调用Base64Codec.BASE64进行解密即可。

//获取token       
		String token = jwtBuilder.compact();
        System.out.println(token);
        String[] split = token.split("\\.");
        System.out.println(Base64Codec.BASE64.decodeToString(split[0]));
        System.out.println(Base64Codec.BASE64.decodeToString(split[1]));
        //        无法解密secret
        System.out.println(Base64Codec.BASE64.decodeToString(split[2]));
    }

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-81tZfqY7-1648962122510)(D:\桌面\笔记Typora\SpringBoot\新建文件夹\image-20220403114653613.png)]

运行后我们可以发现,secret也就是签名部分是乱码。 其他部分正常显示。 能进行编码,当然也能解析

解析token(这里使用上面加密出的token):

    public void  ParseToken(){
        String token = "eeyJhbGciOiJIUzI1NiJ9.eyJqdGkiOiIxMTExIiwic3ViIjoiMTIzNDU2Nzg5MCIsImlhdCI6MTY0ODk1NzM1MH0.VzT6kEyf71MtUyUdy1lUMCys5hUCJPWy_782A19OX3Y";
//        解析token获取负载中的声明对象
        Claims claims = Jwts.parser()
                .setSigningKey("xxxx")
                .parseClaimsJws(token)
                .getBody();
        System.out.println("id : "+claims.getId());
        System.out.println("subject: "+ claims.getSubject());
        System.out.println("issueAt : "+claims.getIssuedAt());
    }

解析结果:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-EW4u7fge-1648962122511)(D:\桌面\笔记Typora\SpringBoot\新建文件夹\image-20220403114800292.png)]

你可能感兴趣的:(java,spring)