码农在囧途
可惜我是一个念旧的人 陪我走过任何一条路的人我都记得,以至于我不知道想的是他们,还是曾经那个满怀真心的自己。
介绍
JWT是JSON Web Token 的简写,Json web token (JWT), 是为了在网络应用环境间传递声明而执行的一种基于JSON的开放标准((RFC 7519).该token被设计为紧凑且安全的,特别适用于分布式站点的单点登录(SSO)场景。JWT的声明一般被用来在身份提供者和服务提供者间传递被认证的用户身份信息,以便于从资源服务器获取资源,也可以增加一些额外的其它业务逻辑所必须的声明信息,该token也可直接被用于认证,也可被加密
为什么要用JWT
随着互联网技术的不断革新以及人们使用互联网的频率越来越高,网站人数日趋增长,这样给服务器带来了巨大的压力,在传统的互联网架构中,使用session(会话)来作为标识用户的凭证,当用户登录系统后,一般将用户的账号,角色等信息存在session会话中,然后返回客户端,将session存在客户端的Cookie中,这样用户再次请求的时候就带上Cookie里的session_id,与之前的校验,但是这样有很大的弊端,我们知道session它存在服务器端(试想一下如果百万上千万的session同时存在于服务器,那服务器所承受的压力是很大的,当然,没有那个公司到达这个规模还用session,这东西过时了),使用session的弊端还在于它无法满足分布式系统的需求,当然也可以通过Redis这种缓存技术对分布式session进行管理,但是这样工作量比较大,如果持久层挂了,那么单点登录就失败,所有就引入了JWT
JWT原理
服务器认证以后,生成一个 JSON 对象(我们一般称为token),发回给用户,此后每次请求都会在请求头带上它,然后可以从这个token中解析出关键信息,用作鉴权和认证等操作。
{
"username":"steak",
"role" :"管理员",
"expireTime":"2019.12.2"
}
用JWT认证后,服务端就变成无状态了,更加容易扩展(分布式)
JWT的组成部分
1.Header:头部
2.payload:负载
3.Signature:签名
三部分连起来就类似这个样子
Header 部分是一个 JSON 对象,描述 JWT 的元数据,通常是下面的样子。
{
"alg": "HS256", //签名算法
"typ": "JWT" //令牌(token)的类型
}
Payload 部分也是一个 JSON 对象,用来存放实际需要传递的数据。JWT 规定了7个官方字段,也可以自定义字段
iss (issuer):签发人
exp (expiration time):过期时间
sub (subject):主题
aud (audience):受众
nbf (Not Before):生效时间
iat (Issued At):签发时间
jti (JWT ID):编号
{
"sub": "1234567890",
"name": "John Doe",
"iat": 1516239022
}
Signature 部分是对Header,payload两部分的签名,防止数据篡改,需要指定一个密钥(secret),这个密钥只有服务器才知道,不能泄露给用户,然后,使用 Header 里面指定的签名算法(默认是 HMAC SHA256),按照下面的公式产生签名。
HMACSHA256(
base64UrlEncode(header) + "." +
base64UrlEncode(payload),
your-256-bit-secret
)
Header和payload都是使用Base64URL进行加密
使用
当用户登录后,会将用户的信息进行加密,然后返回客户端一个加密后的字符串,可以存储在客户端的Cookie里,此后每一次请求都会带上它(放在请求头),如果此字符串和服务端的一致,则认证成功,否则失败
最好放在请求头里面,否则跨域带不过去,
Java jjwt
下面使用jjwt来实现token的生成,验证,
pom.xml
<dependency>
<groupId>com.auth0</groupId>
<artifactId>java-jwt</artifactId>
<version>3.8.3</version>
</dependency>
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt</artifactId>
<version>0.9.1</version>
</dependency>
JwtUtil
package com.gxuwz.jwt.util;
import com.gxuwz.jwt.entity.User;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.JwtBuilder;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import org.springframework.context.annotation.Bean;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
public class JwtUtil {
//创建jwt
public static String createJWT(long expirationDate , User user){
//签名算法
SignatureAlgorithm signatureAlgorithm = SignatureAlgorithm.HS256;
//生成Jwt时间
long jwtTime = System.currentTimeMillis();
Date date = new Date(jwtTime);
//创建payload私有声明
Map<String,Object> map = new HashMap<>();
map.put("userId",user.getUserId());
map.put("userName",user.getUserName());
map.put("password",user.getPassword());
map.put("role",user.getRole());
//生成签名的时候使用的密钥secret
String key = user.getPassword();
//签发人
String subject = user.getUserName();
//为payload添加各种标准
JwtBuilder jwtBuilder = Jwts.builder().setClaims(map)
.setId(UUID.randomUUID().toString()
.replace("_",""))
.setIssuedAt(date)
.setSubject(subject)
.signWith(signatureAlgorithm,key);
if (expirationDate >= 0){
long expDate = jwtTime + expirationDate;
Date exp = new Date(expDate);
jwtBuilder.setExpiration(exp);
}
return jwtBuilder.compact();
}
//Token解密
public static Claims decryptJWT(String token , User user){
//签名密钥
String key = user.getPassword();
Claims claims = Jwts
.parser()
.setSigningKey(key)
//需要解析的jwt
.parseClaimsJws(token).getBody();
return claims;
}
//验证token
public static Boolean checkJWT(String token , User user){
//签名密钥
String key = user.getPassword();
try {
Claims claims = Jwts.parser().setSigningKey(key)
.parseClaimsJws(token).getBody();
if (claims.get("password").equals(user.getPassword())){
return true;
}
}catch (RuntimeException e){
e.printStackTrace();
}
return false;
}
}
获取jwt中的用户信息
String userId = JWT.decode(token).getClaim("userId").asString();
今天的分享就到这里,感谢你的观看,下期见。
原文始发于微信公众号(刘牌):JWT认证就是这么简单
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/150768.html