实现Token的方式有很多,本篇介绍的是利用Json Web Token(JWT)生成的Token.JWT生成的Token有什么好处呢?
本篇分3部分进行讲解。
如果原理很难懂,没关系。可以直接看JWT的代码实现。代码已经上传github。已经对代码进行封装成工具类。可以直接使用。
JSON Web Token 简称JWT。
一个JWT实际上就是一个字符串,它由三部分组成,头部
、载荷
与签名
。
JWT生成的token是这样的
eyJpc3MiOiJKb2huI.eyJpc3MiOiJ.Kb2huIFd1IEp
生成的token,是3段,用
.
连接。下面有解释。
用于描述关于该JWT的最基本的信息,例如其类型以及签名所用的算法等。这也可以被表示成一个JSON对象。
例如:
{
"typ": "JWT",
"alg": "HS256"
}
其实就是自定义的数据,一般存储用户Id,过期时间等信息。也就是JWT的核心所在,因为这些数据就是使后端知道此token是哪个用户已经登录的凭证。而且这些数据是存在token里面的,由前端携带,所以后端几乎不需要保存任何数据。
例如:
{
"uid": "xxxxidid", //用户id
"exp": "12121212" //过期时间
}
签名其实就是:
1.头部和载荷各自base64加密后用.连接起来
,然后就形成了xxx.xx的前两段token。
2.最后一段token的形成是,前两段加入一个密匙用HS256算法或者其他算法加密形成。
JWT的原理参考文章
1.看代码前一定要知道JWT是由头部
、载荷
与签名
组成。
2.代码已上传github,希望点个赞
com.nimbusds
nimbus-jose-jwt
6.0
生成token
/**
* 1.创建一个32-byte的密匙
*/
private static final byte[] secret = "geiwodiangasfdjsikolkjikolkijswe".getBytes();
//生成一个token
public static String creatToken(Map payloadMap) throws JOSEException {
//3.先建立一个头部Header
/**
* JWSHeader参数:1.加密算法法则,2.类型,3.。。。。。。。
* 一般只需要传入加密算法法则就可以。
* 这里则采用HS256
*
* JWSAlgorithm类里面有所有的加密算法法则,直接调用。
*/
JWSHeader jwsHeader = new JWSHeader(JWSAlgorithm.HS256);
//建立一个载荷Payload
Payload payload = new Payload(new JSONObject(payloadMap));
//将头部和载荷结合在一起
JWSObject jwsObject = new JWSObject(jwsHeader, payload);
//建立一个密匙
JWSSigner jwsSigner = new MACSigner(secret);
//签名
jwsObject.sign(jwsSigner);
//生成token
return jwsObject.serialize();
}
验证token
//解析一个token
public static Map valid(String token) throws ParseException, JOSEException {
// 解析token
JWSObject jwsObject = JWSObject.parse(token);
//获取到载荷
Payload payload=jwsObject.getPayload();
//建立一个解锁密匙
JWSVerifier jwsVerifier = new MACVerifier(secret);
Map resultMap = new HashMap<>();
//判断token
if (jwsObject.verify(jwsVerifier)) {
resultMap.put("Result", 0);
//载荷的数据解析成json对象。
JSONObject jsonObject = payload.toJSONObject();
resultMap.put("data", jsonObject);
//判断token是否过期
if (jsonObject.containsKey("exp")) {
Long expTime = Long.valueOf(jsonObject.get("exp").toString());
Long nowTime = new Date().getTime();
//判断是否过期
if (nowTime > expTime) {
//已经过期
resultMap.clear();
resultMap.put("Result", 2);
}
}
}else {
resultMap.put("Result", 1);
}
return resultMap;
}
调用的业务逻辑
//生成token的业务逻辑
public static String TokenTest(String uid) {
//获取生成token
Map map = new HashMap<>();
//建立载荷,这些数据根据业务,自己定义。
map.put("uid", uid);
//生成时间
map.put("sta", new Date().getTime());
//过期时间
map.put("exp", new Date().getTime()+6);
try {
String token = TokenUtils.creatToken(map);
System.out.println("token="+token);
return token;
} catch (JOSEException e) {
System.out.println("生成token失败");
e.printStackTrace();
}
return null;
}
//处理解析的业务逻辑
public static void ValidToken(String token) {
//解析token
try {
if (token != null) {
Map validMap = TokenUtils.valid(token);
int i = (int) validMap.get("Result");
if (i == 0) {
System.out.println("token解析成功");
JSONObject jsonObject = (JSONObject) validMap.get("data");
System.out.println("uid是" + jsonObject.get("uid"));
System.out.println("sta是"+jsonObject.get("sta"));
System.out.println("exp是"+jsonObject.get("exp"));
} else if (i == 2) {
System.out.println("token已经过期");
}
}
} catch (ParseException e) {
e.printStackTrace();
} catch (JOSEException e) {
e.printStackTrace();
}
}
public static void main(String[] ages) {
//获取token
String uid = "kkksuejrmf";
String token = TokenTest(uid);
//解析token
ValidToken(token);
}
生成加密密钥
/**
* 创建加密key
*/
public static RSAKey getKey() throws JOSEException {
RSAKeyGenerator rsaKeyGenerator = new RSAKeyGenerator(2048);
RSAKey rsaJWK = rsaKeyGenerator.generate();
return rsaJWK;
}
生成token
public static String creatTokenRS256(Map payloadMap,RSAKey rsaJWK) throws JOSEException {
//私密钥匙
JWSSigner signer = new RSASSASigner(rsaJWK);
JWSObject jwsObject = new JWSObject(
new JWSHeader.Builder(JWSAlgorithm.RS256).keyID(rsaJWK.getKeyID()).build(),
new Payload(new JSONObject(payloadMap))
);
//进行加密
jwsObject.sign(signer);
String token= jwsObject.serialize();
return token;
}
解析token
//验证token
public static Map validRS256(String token,RSAKey rsaJWK) throws ParseException, JOSEException {
//获取到公钥
RSAKey rsaKey = rsaJWK.toPublicJWK();
JWSObject jwsObject = JWSObject.parse(token);
JWSVerifier jwsVerifier = new RSASSAVerifier(rsaKey);
//验证数据
return verify(jwsObject, jwsVerifier);
}
JWT 的实践其实还是挺简单。安全性也是得到了保证,后端只需要保存着密匙,其他数据可以保存在token,由前端携带,这样可以减低后端的内存消耗。
虽然token是加密的,但是携带的验证数据还是不要是敏感数据