参考:https://www.jianshu.com/p/e88d3f8151d
一、 流程图
二、 具体实现
说明: 基于SpringBoot
引用依赖
<dependency>
<groupId>com.auth0</groupId>
<artifactId>java-jwt</artifactId>
<version>2.2.0</version>
</dependency>
关键编码
private UsersDTO getToken(UsersDTO user, Boolean isApp) {UserToken ut = new UserToken();
ut.setId(Long.parseLong(user.getUserId()));
if (isApp) {
ut.setType(BaseConstant.REDIS_PRE_USER_APP_KEY);
} else {
ut.setType(BaseConstant.REDIS_PRE_USER_KEY);
}
// APP的场合,token7天过期,其余场合,保持现有的12小时过期不变
String token = StringUtils.EMPTY;
if (isApp) {
token = JWT.sign(ut, 60L * 1000L * 60L * 24L * 7L);// 7天过期
logger.info("7天过期");
} else {
token = JWT.sign(ut, 60L * 1000L * 60L * 12L);// 12小时过期
logger.info("12小时过期");
}
user.setToken(token);
Map<String, String> map = new HashMap<String, String>();
map.put("url", "m.url");
List<MenuDTO> list = menuBiz.listMenuAndFunctionByUser(Long.parseLong(user.getUserId()), null, map);
List<String> menuList = new ArrayList<String>();
for (MenuDTO menuDTO : list) {
menuList.add(menuDTO.getUrl());
}
ut.setUrl(menuList);
ut.setToken(token);
if (isApp) {
redisUtil.saveRedisForApp(BaseConstant.REDIS_PRE_USER_APP_KEY + Long.toString(ut.getId()), ut);
} else {
redisUtil.saveRedis(BaseConstant.REDIS_PRE_USER_KEY + Long.toString(ut.getId()), ut);
}
return user;
}
UserToken中设置用户信息传入JWT.sign方法返回加密后的token字符串,传入用户之后,便于后续反编译之后获取用户信息 JWT.sign(ut,timeout) package com.yxg.jwt; import com.auth0.jwt.JWTSigner; import com.auth0.jwt.JWTVerifier; import com.auth0.jwt.internal.com.fasterxml.jackson.databind.ObjectMapper; import java.util.HashMap; import java.util.Map; public class JWT { private static final String SECRET = "123456"; private static final String EXP = "exp"; private static final String PAYLOAD = "payload"; /** 加密 * get jwt String of object * @param object * the POJO object * @param maxAge * the milliseconds of life time * @return the jwt token */ public static <T> String sign(T object, long maxAge) { try { final JWTSigner signer = new JWTSigner(SECRET); final Map<String, Object> claims = new HashMap<String, Object>(); ObjectMapper mapper = new ObjectMapper(); String jsonString = mapper.writeValueAsString(object); //存放有效信息 claims.put(PAYLOAD, jsonString); //设置过期时间 claims.put(EXP, System.currentTimeMillis() + maxAge); return signer.sign(claims); } catch(Exception e) { return null; } } /** 解密 * get the object of jwt if not expired * @param jwt * @return POJO object */ public static<T> T unsign(String jwt, Class<T> classT) { final JWTVerifier verifier = new JWTVerifier(SECRET); try { final Map<String,Object> claims= verifier.verify(jwt); if (claims.containsKey(EXP) && claims.containsKey(PAYLOAD)) { long exp = (Long)claims.get(EXP); long currentTimeMillis = System.currentTimeMillis(); if (exp > currentTimeMillis) { String json = (String)claims.get(PAYLOAD); ObjectMapper objectMapper = new ObjectMapper(); return objectMapper.readValue(json, classT); } } return null; } catch (Exception e) { return null; } } }
3. 返回token示例 eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJleHAiOjE2Mzg1ODA0MDI5OTEsInBheWxvYWQiOiJ7XCJpZFwiOjEsXCJ0b2tlblwiOm51bGwsXCJ0eXBlXCI6XCJtYW5hZ2VyX1wiLFwidXJsXCI6bnVsbH0ifQ.za9jMT8GDflhF0is_qim5FZ7spTIQbwAWCqqjeYW_AU
Token是用.分割成三段 Header 头部(标题包含了令牌的元数据,并且包含签名和/或加密算法的类型) Payload 加密的用户相关信息(userId) Signature 签名/签证
三、 使用Iterceptor设置需要验证和放行接口