常见认证机制及JWT介绍
HTTP Basic Auth
HTTP Basic Auth就是每次请求都会提供用户的用户名和密码 , 也就是说它是使用最简单的认证方式,只需要提供密码即可。
由于它每次都需要将密码暴露给第三方,因此他是不安全的,现在使用也越来越少。
Cookie Auth
Cookie认证机制也就是每次请求认证都会在服务端创建一个session对象,同时在浏览器端创建一个Cookie对象。通过客户端上带的Cooke来和服务器端的session对象匹配来实现验证。
OAuth(开放授权)
它属于一个开放的授权标准,允许用户让第三方应用访问该用户在某一web服务上存储私密资源,且不用将用户名和密码提供给第三方。这样说可能不明白,呢你们想一下在使用app时,有没有用到微信登录、qq登录等第三方登录。
Oauth相当于提供给用户一个令牌,来去访问。而不是需要用户名和密码去访问。
类似于这种,就相当于授予令牌 来直接去用第三方账户登录:
请求流程:(图片来源于网络)
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:类型
这里我们对头部的json字符串进行BASE64编码 , eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9
Base64是可以基于64个可打印字符来表示二进制的表示方法。其中每六个比特为一个单元。JDK也为我们提供了相关的方法可以去完成BASE64的编码和解码。
载荷:也就是存放有效信息的地方。
它包含了三种声明方式:
-
标准中注册的声明 -
公共声明 -
私有声明
sub:jwt所面向的用户
iat:jwt的签发时间
无论是哪种方式,都不建议存放隐私信息,因为这部分是明文可以进行解密的。
签名:也就是签证信息。
这个签证信息由三部分组成,header、payload、secret(保密)
其中:
secret:存放在服务器端,它是用来进行jwt的签发和jwt的验证,也就相当于密钥。因此这个不能泄露,如果客户端知道了,也就意味着客户端可以自己签发jwt。
有兴趣的同学可以去官网试一下,每一个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]));
}
运行后我们可以发现,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());
}
解析结果:
原文始发于微信公众号(小艾搞安全):常见认证机制及JWT介绍
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-
评论