1 基于传统的session认证
http本身是一种无状态的协议,而这就意味着如果用户向我们的应用提供了用户名和密码来进行用户认证,那么下一次请求时,用户还再一次进行用户认证。因为根据http协议,我们不知道是哪个用户发出的请求,所以为了能让我们应用识别是哪一个用户发出的请求,我们只能在服务器端存储一份用户登录的信息,这份登录信息会在响应时传递给浏览器。告诉其保存为cookie,以便下次请求时发送给我们的应用,这样我们的用户就能识别是哪一个用户了,这就是传统的基于session认证。
当用户发送一个认证之后,认证通过,会向session中存储一个用户信息,然后会将sessionId以响应的形式写入客户端,cookie里面进了一个sessionId。cookie的键叫JSESSIONID。日后客户端再去访问应用时,会自动携带JSESSIONID进行登录。
2 session认证暴露的问题
1 每个应用经过我们的应用认证之后,我们的应用都要在服务端做一次记录,以方便用户下次请求的鉴别,通常而言session都是保存在内存中,而随着用户认证的增多,服务端的开销会明显增多。
2 用户认证之后,如果认证记录被保存在内存中,这意味着用户下次请求还必须请求在这台服务器上,这样才能后拿到授权的资源,这样在分布式应用上,相应的限制了负载均衡的能力,这也意味着限制的用户的扩展能力
3 因为是基于cookie来进行用户识别的,cookie如果被截获,用户就会很容易受到跨站请求伪造的攻击
4 增加了部署的复杂性,sessionId是一个特征值,表达信息不够丰富,不容易扩展,而且如果你后端应用时多节点部署,那么就需要实现session共享机制,不方便集群应用。
3 JWT认证流程
首先,前端通过表单将用户名和密码发送到后端的接口。这一过程一般是一个HTTP POST请求。建议的方式是通过https加密的传输,从而避免敏感信息被嗅探
然后,后端核对用户名和密码成功后,将用户的id等其他信息作为JWT Payload(负载),将其与头部进行Base64编码拼接后进行签名,形成一个JWT(token)。形成的jwt是一个lll.yyy.zzz的字符串,即是token.head.payload.singurater
然后,后端将JWT字符串作为登录成功的返回结果返回给前端,前端可以将返回的结果保存在localStorage或者sessionStorage上,退出登录时,前端删除保存的jwt即可。
前端在每次请求时将JWT放入Header中的Authorization位。解决XSS和XSRF
然后,后端检查是否存在,如存在验证JWT的有效性,例如,检查签名是否正确,检查token是否过期,
检查通过后,后端通过使用JWT中包含的用户信息进行其他的用户操作
4 JWT优势
简洁:可以通过URL,POST参数或者在HTTP header发送,因为数据量小,所以传输速度也快
自包含:负载中包含了所有用户需要的信息(在jwt的payload中),避免了多次查询数据库
因为token是以JSON加密的形式保存在客户端的,所以jwt是跨语言的。原则上任何web形式都支持
不需要在服务端保存会话信息,特别适用于分布式微服务
5 JWT结构(令牌组成)
5.1 标头(Header)
标头通常由两部分组成:令牌的类型(即JWT)和所使用的签名算法,例如NMAC,SHA256或RSA。它会使用Base64编码组成JWT结构的第一部分
注意:Base64是一种编码,是可以被翻译回原来样子的,它并不是一种加密过程。
{
"alg":HS256,
"type":"JWT"
}
5.2 Payload
令牌的第二部分是有效负载,其中包含声明。声明是有关实体(通常是用户User)和其他用户的声明。同样,他会使用Base64编码组成JWT结构的第二部分
{
“userId”:123456,
"userType": "0",
"name" : "张三"
}
5.3 Signature
前面两部分都是使用Base64进行编码的,即前端可以解开知道里面的信息。Signature需要使用编码后的header和payload以及我们提供的一个秘钥。然后使用header中指定的签名算法(hs256)进行签名。签名的目的是保证token没有被篡改过
6 代码验证
6.1 生成token
生成token:eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJleHAiOjE2Mzc0OTEzMjgsInVzZXJJZCI6IjEyMzQ1NiIsInVzZXJuYW1lIjoi5byg5LiJIn0.OqKhQ-0zRXSEC2IgWlN-pKD__P8M73IsohMU2zahUKc
6.2 验证
@Test
public void test(){
JWTVerifier jwtVerifier = JWT.require(Algorithm.HMAC256("safdd4h21ft4u")).build();
DecodedJWT decodedJWT = jwtVerifier.verify("eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJleHAiOjE2Mzc0OTEyMTMsInVzZXJJZCI6IjEyMzQ1NiIsInVzZXJuYW1lIjoi5byg5LiJIn0.7rQeddIkMiiSXTxirQ5BsQ_gTkk17qA2sGwpcf3svAA\n");
System.out.println(decodedJWT.getClaim("userId").asString());
System.out.println(decodedJWT.getClaim("username").asString());
}
验证结果:
原文链接: jwt生成token_jjwt生成token_IT盛夏的果实的博客-CSDN博客