1.官网
jwt.io/libraries
2.选jose4j
pom
org.bitbucket.b_c
jose4j
0.9.4
3.创建jwt工具
public class JwtUtil {
private static String secret = "e0e775bfcad04ecc94807b028dfca4d5";// "12345678123456781234567812345678"; // 注意密钥长短(最少32个字符)
private static String Issuer = "QiXiao";
private static String Audience = "WangPeng";
public static String CreateToken(UserEntity user) {
try {
JsonWebSignature jws = new JsonWebSignature();
//Claim
JwtClaims claims = new JwtClaims();
claims.setIssuer(Issuer); // who creates the token and signs it
claims.setAudience(Audience); // to whom the token is intended to be sent
claims.setExpirationTimeMinutesInTheFuture(10); // 过期时间
claims.setGeneratedJwtId(); // 为 JWT 设置一个自动生成的唯一 ID
claims.setIssuedAtToNow(); // 设置 Token 发布/创建 时间为当前时间
claims.setNotBeforeMinutesInThePast(2); // 设置生效时间为 2 分钟前
claims.setSubject("Bearer"); // the subject/principal is whom the token is about
claims.setClaim("UserSN", user.getSN());
claims.setClaim("email","[email protected]"); // additional claims/attributes about the subject can be added
jws.setPayload(claims.toJson());
//Header
jws.setAlgorithmHeaderValue(AlgorithmIdentifiers.HMAC_SHA256);
jws.setHeader("typ", "JWT");
//签名
Key hmacKey = CreateKey();
jws.setKey(hmacKey);
jws.setDoKeyValidation(false);
String jwt = jws.getCompactSerialization();
System.out.println(jwt);
return jwt;
}
catch (JoseException ex)
{
throw new RuntimeException(ex.getMessage());
}
}
private static Key CreateKey()
{
Key hmacKey = new HmacKey(secret.getBytes());
return hmacKey;
}
public static JwtClaims ValidateToken(String jwt) throws MalformedClaimException {
String message = "";
Key key = CreateKey();
JwtClaims jwtClaims = new JwtClaims();
// 验证令牌
JwtConsumer jwtConsumer = new JwtConsumerBuilder()
.setAllowedClockSkewInSeconds(30)
.setRequireExpirationTime() // 必须设置过期时间
.setRequireSubject() // 必须设置 Subject
.setExpectedIssuer(Issuer) // 必须设置 Token 签发者
.setExpectedAudience(Audience)// 必须设置 Token 签发给谁
.setVerificationKey(key) // 设置用于验证签名的公钥
// 设置允许的预期签名算法
.setJwsAlgorithmConstraints(
AlgorithmConstraints.ConstraintType.WHITELIST, AlgorithmIdentifiers.HMAC_SHA256)
.build();
try {
jwtClaims = jwtConsumer.processToClaims(jwt);
}
catch(InvalidJwtException e)
{
jwtClaims = new JwtClaims();
message = handleException(e);
jwtClaims.setClaim("error", message);
}
return jwtClaims;
}
private static String handleException(InvalidJwtException e){
String message = "";
try {
JwtClaims jwtClaims = e.getJwtContext().getJwtClaims();
List errorDetails = e.getErrorDetails();
// 异常是否因 JWT 过期触发
if (e.hasExpired())
{
message = "token已经过期, 过期时间在" + jwtClaims.getExpirationTime();
}
// 异常是否因 Audience 无效触发
if(e.hasErrorCode(ErrorCodes.AUDIENCE_INVALID))
{
message = "无效audience:" + jwtClaims.getAudience();
}
// 异常是否因缺少 Audience 触发
if (e.hasErrorCode(ErrorCodes.AUDIENCE_MISSING)) {
message = "Audience丢失";
}
// 异常是否因缺少过期时间触发
if (e.hasErrorCode(ErrorCodes.EXPIRATION_MISSING)) {
message = "缺少过期时间";
}
// 异常是否因过期时间太长触发
if (e.hasErrorCode(ErrorCodes.EXPIRATION_TOO_FAR_IN_FUTURE)) {
message = "过期时间太";
}
// 异常是否因缺乏完整性触发
if (e.hasErrorCode(ErrorCodes.INTEGRITY_MISSING)) {
message = "缺乏完整性";
}
// 异常是否因发布时间无效触发
if (e.hasErrorCode(ErrorCodes.ISSUED_AT_INVALID_FUTURE) || e.hasErrorCode(ErrorCodes.ISSUED_AT_INVALID_PAST)) {
message = "发布时间无效:" + jwtClaims.getIssuedAt();
}
// 异常是否因缺少发布时间触发
if (e.hasErrorCode(ErrorCodes.ISSUED_AT_MISSING)) {
message = "缺少发布时间:";
}
// 异常是否因签发者无效触发
if (e.hasErrorCode(ErrorCodes.ISSUER_INVALID)) {
message = "签发者无效:" + jwtClaims.getIssuer();
}
// 异常是否因缺少签发者触发
if (e.hasErrorCode(ErrorCodes.ISSUER_MISSING)) {
message = "缺少签发者";
}
// 异常是否因 JSON 无效触发
if (e.hasErrorCode(ErrorCodes.JSON_INVALID)) {
message = "JSON 无效";
}
// 异常是否因缺少 JWT ID 触发
if (e.hasErrorCode(ErrorCodes.JWT_ID_MISSING)) {
message = "缺少 JWT ID";
}
// 异常是否因 JwtClaims 格式错误触发
if (e.hasErrorCode(ErrorCodes.MALFORMED_CLAIM)) {
message = "JwtClaims 格式错误";
}
// 异常是否因缺少生效时间触发
if (e.hasErrorCode(ErrorCodes.NOT_BEFORE_MISSING)) {
message = "缺少生效时间";
}
// 异常是否因 Token 尚未生效触发
if (e.hasErrorCode(ErrorCodes.NOT_YET_VALID)) {
message = "Token 尚未生效";
}
// 异常是否因 Token 的 Signature 部分无效触发
if (e.hasErrorCode(ErrorCodes.SIGNATURE_INVALID)) {
message = "Token 的 Signature 部分无效";
}
// 异常是否因 Token 的 Signature 部分缺失触发
if (e.hasErrorCode(ErrorCodes.SIGNATURE_MISSING)) {
message = "Token 的 Signature 部分缺失";
}
// 异常是否因 Subject 无效触发
if (e.hasErrorCode(ErrorCodes.SUBJECT_INVALID)) {
message = "Subject 无效";
}
// 异常是否因 Subject 缺失触发
if (e.hasErrorCode(ErrorCodes.SUBJECT_MISSING)) {
message = "Subject 缺失";
}
// 异常是否因 Type 无效触发
if (e.hasErrorCode(ErrorCodes.TYPE_INVALID)) {
message = "Type 无效";
}
// 异常是否因 Type 缺失触发
if (e.hasErrorCode(ErrorCodes.TYPE_MISSING)) {
message = "Type 缺失";
}
if(message == "")
{
message = e.getMessage();
}
}
catch (MalformedClaimException e1) {
message = e.getMessage();
}
return message;
}
}
4.CreateToken方法在登录时用
5.验证token的方法ValidateToken在拦截器用
public class JwtHandlerInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
boolean bOK = HandlerInterceptor.super.preHandle(request, response, handler);
String header = request.getHeader("Authorization");
// 请求头不为空进行解析
if (StringUtils.isNotBlank(header) && header.startsWith("Bearer ")) {
// 得到令牌
String jwt = header.substring(7);
JwtClaims jwtClaims = JwtUtil.ValidateToken(jwt);
Object msg = jwtClaims.getClaimValue("error");
if(msg != null)
{
response.setContentType("text/html;charset=UTF-8");
response.getWriter().write((String) msg);
}
else
{
Map map = new HashMap<>();
map.put("UserSN", jwtClaims.getClaimValue("UserSN"));
request.setAttribute("UserInfo", map);
}
return msg == null;
}
return false;
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
HandlerInterceptor.super.postHandle(request, response, handler, modelAndView);
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
HandlerInterceptor.super.afterCompletion(request, response, handler, ex);
}
}
6.获取UserSN
Controller里要用到token的UserSN,通过RequestContextHolder可以获取,创建WebUtil
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import javax.servlet.http.HttpServletRequest;
import java.util.Map;
public class WebUtil {
private static HttpServletRequest request;
static
{
if(request == null)
{
request = ((ServletRequestAttributes) RequestContextHolder.currentRequestAttributes()).getRequest();
}
}
public static long getUserSN()
{
Object attribute = request.getAttribute("UserInfo");
if(attribute != null && attribute instanceof Map)
{
Map map = (Map)attribute;
return (long) map.get("UserSN");
}
return 0;
}
}
7.