在前后端分离的场景中,前后台主要用jwt交互,比如说前端发一个提交信息的请求,后台必须知道这个提交者的信息吧(提交者id),但为了使传输更安全,jwt包含了需要的用户信息以加密的方式传输以达到这个目的。
先看看jwt的定义,网上随处可见的:jwt全称Json Web Token,由三部分构成:头部(header)、载荷(payload, )、签证(signature).
传输信息用到的就是载荷:就是存放有效信息的地方,就是这样的键值对构成的Map对象:
iss: jwt签发者
sub: jwt所面向的用户
aud: 接收jwt的一方
exp: jwt的过期时间,这个过期时间必须要大于签发时间
nbf: 定义在什么时间之前,该jwt都是不可用的.
iat: jwt的签发时间
jti: jwt的唯一身份标识,主要用来作为一次性token,从而回避重放攻击。
jwt用Claims对象来存自定义的信息(也是一个键值对的Map对象):当登录的时候,就把当前的用户的信息存进去,这里模拟一下(假如从数据库中获取了用户信息)
@ResponseBody
@RequestMapping("login.do")
public JsonAndModel sayHello(HttpServletRequest request, HttpServletResponse response) {
Map<String,Object> claims = new HashMap<>();
claims.put("username","wang");
claims.put("userid",12);
System.out.println(new Date().getTime() + "---start---");
return JsonAndModel.builder(TokenUtil.tokens(claims)).build();
}
然后把信息存到一个map里面,通过工具生成token字符串返回给前台,当前台再次请求的时候就带上这个token,然后取参数验证。
package cn.wzy.util;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.JwtBuilder;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import java.util.*;
/**
* @author wzy
* @Date 2018/4/6 14:00
*/
public class TokenUtil {
private static Properties properties = new Properties();
private static ResourceBundle resource = ResourceBundle.getBundle("database");
public static Object getValue(String key) {
return resource.getString(key);
}
public static String tokens(Map<String,Object> claims) {
String SecretKey = (String) getValue("secretkey");
//获取当前的时间
Calendar calendar = Calendar.getInstance();
Date date = new Date(System.currentTimeMillis());
calendar.setTime(date);
//向后退后的秒数
int time = Integer.parseInt((String) getValue("millisecond"));
calendar.add(Calendar.MILLISECOND, time);
Date endTime = calendar.getTime();
String issuer = (String) getValue("JWT_ISSUER");
String aud = (String) getValue("JWT_AUD");
JwtBuilder builder = Jwts.builder().setClaims(claims)
.signWith(SignatureAlgorithm.HS256,SecretKey)
.setClaims(claims)
.setSubject((String)claims.get("username"))
.setIssuedAt(new Date())
.setExpiration(endTime)
.setIssuer(issuer)
.setAudience(aud);
return builder.compact();
}
/**
* 从jwt中获取用户信息
* @param jsonWebToken
* @return
*/
public static Claims parseJWT(String jsonWebToken) {
String secretKey = (String) getValue("secretkey");
try {
Claims claims = Jwts.parser()
.setSigningKey(secretKey)
.parseClaimsJws(jsonWebToken).getBody();
return claims;
} catch (Exception ex) {
return null;
}
}
}
验证过程:把前端存到header里面的token解析成一个Claims对象获取参数验证(当时间过了设置的token失效时间,这个对象就失效为null,也就未登录)
@ResponseBody
@RequestMapping("checkOnlie.do")
public JsonAndModel check(HttpServletRequest request, HttpServletResponse response) {
String claims = request.getHeader("claims");
Claims info = null;
if (claims != null) {
info = TokenUtil.parseJWT(claims);
System.out.println(info == null);
System.out.println(new Date().getTime());
}
return JsonAndModel.builder(info).build();
}