第一次登录就生成stoken,(根据用户信息和失效时间生成的,所以用户账号密码不改它的stoken还是不一样是因为失效时间不同),之后每次请求时都带stoken来,然后认证拦截器获取stoken,通过解密(只需要一个公钥,这个公钥是整个项目中公共的。)如果stoken过期抛异常或如果解密不出来对象也抛异常,从而达到认证过程
JWT工具类
public class JWT {
private static final String SECRET = "达瓦大V型澄vjbbi32@$@$@$@#"; //公钥,不能泄露
private static final String EXP = "exp";
private static final String PAYLOAD = "payload";
/**
* 加密,传入一个对象和有效期 object一般为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();
//把对象转换成 JSON 格式
String jsonString = mapper.writeValueAsString(object);
//传入对象和设置有效期
claims.put(PAYLOAD, jsonString);
claims.put(EXP, System.currentTimeMillis() + maxAge);
//加密
return signer.sign(claims);
} catch (Exception e) {
return null;
}
}
/**
* 解密,传入一个加密后的token字符串和解密后的类型
*/
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();
//如果过期,则返回 null
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;
}
}
}
对于第三方jar包的代码进行了重写,使得更加安全
public class JwtApiAuth extends AbstractApiAuth {
private Logger LOGGER = = LoggerFactory.getLogger(get(getClass());
/**
* 盐 会话ID生成规则: sid = md5(uid + ets + salt)
*/
private final String SESSION_SALT = "= "dwadhiawdnxc@wdawdawd";
";
/**
* 会话KEY
*/
private final String SESSION_KEY = "xchzca46161dwadwa@dadwwadw";
";
@Override
public String createToken(String uid) {
int ets = createEts();
String sid = createSid(uid, ets);
String stoken = null;
try {
Algorithm algorithm = = Algorithm.HMAC256(256(SESSION_KEY);
stoken = = JWT.create().w().withClaim("uid", uid)
.withClaim("sid", sid)
.withClaim("ets", ets)
.sign(algorithm);
} catch (UnsupportedEncodingException e) {
// UTF-8 encoding not supported
throw new RuntimeException("生成会话token失败: " + + e.getMessage())e());
} catch (JWTCreationException e) {
// Invalid Signing configuration / Couldn't convert Claims.
throw new RuntimeException("生成会话token失败:" + + e.getMessage())e());
}
return stoken;
}
@Override
public AuthSession parseToken(String stoken) {
AuthSession jwtSession = null;
try {
Algorithm algorithm = = Algorithm.HMAC256(256(SESSION_KEY);
JWTVerifier verifier = = JWT.require(alg(algorithm).build(); // Reusable verifier instance
DecodedJWT jwt = = verifier.verify(sto(stoken);
jwtSession = new AuthSession();
jwtSession.setEts(jwt(ts(jwt.getClaim("et("ets").asInt());
jwtSession.setSid(jwt(id(jwt.getClaim("si("sid").asString());
jwtSession.setUid(jwt(id(jwt.getClaim("ui("uid").asString());
} catch (UnsupportedEncodingException e) {
// UTF-8 encoding not supported
throw new AppAuthException("解析会话token失败: " + + e.getMessage())e());
} catch (JWTVerificationException e) {
// Invalid signature/claims
throw new AppAuthException("解析会话token失败: " + + e.getMessage())e());
}