1.首先理解jwt是什么
jwt:全称(JSON Web Token),是一个开放标准(RFC 7519),它定义了一种紧凑的、自包含的方式,用于作为JSON对象在各方之间安全地传输信息。是目前最流行的跨域身份验证解决方案。
2.jwt的结构是什么样的
jwt由三部分组成,它们之间用圆点(.)连接。这三部分分别是
1. Header
2. Payload
3. Signature
例如:
aaa.bbb.zzz
具体说明如下:
Header:由两部分组成:token的类型(“JWT”)和算法名称(比如:HMAC SHA256或者RSA等等)。
例如:{
“alg”:”HS256”,
“typ”:“JWT”
}
然后,用Base64对这个JSON编码就得到JWT的第一部分
Payload :是JWT的第二部分,是关于实体(通常是用户)和其他数据的声明
例如:{
“name”:“username”,
“age”:18
}
对payload进行Base64编码就得到JWT的第二部分
注意:不要在JWT的payload或header中放置敏感信息,除非它们是加密的。
Signature:签名部分,你必须有编码过的header、编码过的payload、一个秘钥,签名算法是header中指定的那个,然对它们签名即可,
例如:HMACSHA256(base64UrlEncode(header) + "." + base64UrlEncode(payload), secret)
说明:Signature用于验证消息在传递过程中有没有被更改,并且,对于使用私钥签名的token,它还可以验证JWT的发送方是否为它所称的发送方。
3. JWT与Session的差异
相同点:都是存储用户信息;然而,Session是在服务器端的,而JWT是在客户端的。
不同点:
Session方式存储用户信息的最大问题在于要占用大量服务器内存,增加服务器的开销
JWT方式将用户状态分散到了客户端中,可以明显减轻服务端的内存压力
4.Token授权是如何工作的
流程:
1.用于通过用户名和密码登陆
2.服务器校验用户名和密码
3.服务器端提供一个token给客户端
4.客户端存储token,并在之后的请求中通过header部分携带传入服务器端
5.服务器端校验客户端传入的token是否有效
6.校验通过访问相应的资源
注意:如果是应用请求来自不同的域,当前应用请设置允许跨域。
JJWT(Java JWT):适用于 Java 和 Android 的 JSON Web Token(JWT)库
1.在Springboot项目中引入相关依赖如下:
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt</artifactId>
<version>0.9.1</version>
</dependency>
2.相关类和接口
public class CommonConstants {
public static final String JWT_KEY_USER_ID = "userId";
public static final String JWT_KEY_NAME = "name";
}
public class StringHelper {
public static String getObjectValue(Object obj){
return obj==null?"":obj.toString();
}
}
public interface IJWTInfo {
/**
* 获取用户名
* @return
*/
String getUniqueName();
/**
* 获取用户ID
* @return
*/
String getId();
/**
* 获取名称
* @return
*/
String getName();
}
3.JWT具体操作类
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jws;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import org.joda.time.DateTime;
public class JWTHelper {
private static RsaKeyHelper rsaKeyHelper = new RsaKeyHelper();
/**
* 密钥加密token
*
* @param jwtInfo
* @param priKeyPath
* @param expire
* @return
* @throws Exception
*/
public static String generateToken(IJWTInfo jwtInfo, String priKeyPath, int expire) throws Exception {
String compactJws = Jwts.builder()
.setSubject(jwtInfo.getUniqueName())
.claim(CommonConstants.JWT_KEY_USER_ID, jwtInfo.getId())
.claim(CommonConstants.JWT_KEY_NAME, jwtInfo.getName())
.setExpiration(DateTime.now().plusSeconds(expire).toDate())
.signWith(SignatureAlgorithm.RS256, rsaKeyHelper.getPrivateKey(priKeyPath))
.compact();
return compactJws;
}
/**
* 密钥加密token
*
* @param jwtInfo
* @param priKey
* @param expire
* @return
* @throws Exception
*/
public static String generateToken(IJWTInfo jwtInfo, byte priKey[], int expire) throws Exception {
String compactJws = Jwts.builder()
.setSubject(jwtInfo.getUniqueName())
.claim(CommonConstants.JWT_KEY_USER_ID, jwtInfo.getId())
.claim(CommonConstants.JWT_KEY_NAME, jwtInfo.getName())
.setExpiration(DateTime.now().plusSeconds(expire).toDate())
.signWith(SignatureAlgorithm.RS256, rsaKeyHelper.getPrivateKey(priKey))
.compact();
return compactJws;
}
/**
* 公钥解析token
*
* @param token
* @return
* @throws Exception
*/
public static Jws<Claims> parserToken(String token, String pubKeyPath) throws Exception {
Jws<Claims> claimsJws = Jwts.parser().setSigningKey(rsaKeyHelper.getPublicKey(pubKeyPath)).parseClaimsJws(token);
return claimsJws;
}
/**
* 公钥解析token
*
* @param token
* @return
* @throws Exception
*/
public static Jws<Claims> parserToken(String token, byte[] pubKey) throws Exception {
Jws<Claims> claimsJws = Jwts.parser().setSigningKey(rsaKeyHelper.getPublicKey(pubKey)).parseClaimsJws(token);
return claimsJws;
}
/**
* 获取token中的用户信息
*
* @param token
* @param pubKeyPath
* @return
* @throws Exception
*/
public static IJWTInfo getUserInfoFromToken(String token, String pubKeyPath) throws Exception {
Jws<Claims> claimsJws = parserToken(token, pubKeyPath);
Claims body = claimsJws.getBody();
return new JWTInfo(body.getSubject(), StringHelper.getObjectValue(body.get(CommonConstants.JWT_KEY_USER_ID)), StringHelper.getObjectValue(body.get(CommonConstants.JWT_KEY_NAME)));
}
/**
* 获取token中的用户信息
*
* @param token
* @param pubKey
* @return
* @throws Exception
*/
public static IJWTInfo getUserInfoFromToken(String token, byte[] pubKey) throws Exception {
Jws<Claims> claimsJws = parserToken(token, pubKey);
Claims body = claimsJws.getBody();
return new JWTInfo(body.getSubject(), StringHelper.getObjectValue(body.get(CommonConstants.JWT_KEY_USER_ID)), StringHelper.getObjectValue(body.get(CommonConstants.JWT_KEY_NAME)));
}
}