JWT入门1


参考:https://www.jianshu.com/p/e88d3f8151d

一、    流程图

二、    具体实现

说明: 基于SpringBoot

  1. 引用依赖


    com.auth0
    java-jwt
    2.2.0

  1. 关键编码
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 map = new HashMap();
    map.put("url", "m.url");
    List list = menuBiz.listMenuAndFunctionByUser(Long.parseLong(user.getUserId()), null, map);
    List menuList = new ArrayList();
    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  String sign(T object, long maxAge) {
                                      try {
                                                         final JWTSigner signer = new JWTSigner(SECRET);
                                                         final Map claims = new HashMap();
                                                         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 unsign(String jwt, Class classT) {
                                      final JWTVerifier verifier = new JWTVerifier(SECRET);
                       try {
                                                         final Map 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设置需要验证和放行接口

  1. 自定义Iterceptor实现WebMvcConfigurer重写addInterceptors(InterceptorRegistry)
@Configuration
public class MVCInterceptorConfiguration  implements WebMvcConfigurer {

    @Autowired
    private TokenInterceptor  tokenInterceptor;

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(tokenInterceptor).addPathPatterns("/**")
                .excludePathPatterns(
                        "/api-docs/**",
                        "/user/login",

                );
    }
}

    addInterceptor设置自定义拦截规则

    excludePathPatterns中设置的接口路径直接放行不验证token

  2.定义拦截规则

@Component
public class TokenInterceptor implements HandlerInterceptor {

    @Autowired
    private RedisUtil redisUtil;

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
            throws Exception {

        String token = Optional.ofNullable(request.getHeader("Authorization")).orElse("");
        String client = Optional.ofNullable(request.getHeader("XLClinet")).orElse("");
        System.out.println(client + " " + request.getRequestURI());
        if ("".equals(token)) {
            return true;
        }
        //验证token
        if (redisUtil.verifyTokenRedis(token, request)) {
            return true;
        } else {
            JsonResponse.jsonWriteApp(response, Integer.toString(HttpStatusEnum.UNAUTHORIZED.value()),
                    BaseConstant.MESSAGE_ERROR_TOKEN_MISSING, StrUtil.toString(request.getHeader("deviceFlag")));
            return false;
        }
    }

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,
                           ModelAndView modelAndView) throws Exception {
        // TODO Auto-generated method stub

   
}

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)
            throws Exception {
        // TODO Auto-generated method stub

   
}

}

3.验证token

/**
 * @param
token
 
* @return
 * @Description token
验证
 * @date 2017
1218下午5:21:20
 */
public boolean verifyTokenRedis(String token, HttpServletRequest request) {
    boolean flag = false;

    UserToken user = JWT.unsign(token, UserToken.class);

    if (null == user || null == user.getId()) {
        return flag;
    }
    String userAgent = request.getHeader("deviceFlag");
    logger.info("RedisUtils.verifyTokenRedis获取的user-agent:" + userAgent);
    Boolean isApp = VerifyUtils.isLoginByApp(userAgent);
    logger.info("RedisUtils.verifyTokenRedis的isApp:" + isApp);
    UserToken ut = (UserToken) redisTemplate.opsForValue().get(user.getType() + Long.toString(user.getId()));
    if (null != ut && null != ut.getToken() && ut.getToken().equals(token)) {
        String url = request.getServletPath();
        request.setAttribute(BaseConstant.LOGINPERSONID, user.getId());
        logger.info(BaseConstant.LOGINPERSONID + user.getId());
        logger.info(url);
        if (isApp) {
            this.saveRedisForApp(user.getType() + Long.toString(user.getId()), ut);
        } else {
            saveRedis(user.getType() + Long.toString(user.getId()), ut);
        }
        flag = true;
    }

    return flag;
}