• JWT入门1


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

    一、    流程图

    二、    具体实现

    说明: 基于SpringBoot

    1. 引用依赖

    <dependency>
        <groupId>com.auth0</groupId>
        <artifactId>java-jwt</artifactId>
        <version>2.2.0</version>
    </dependency>

    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<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设置需要验证和放行接口

    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;
    }
  • 相关阅读:
    GC算法 垃圾收集器
    Distinct
    生产者消费者实现
    单例模式(七种实现方法)
    【JUC】JDK1.8源码分析之AbstractQueuedSynchronizer
    【JUC】JDK1.8源码分析之ConcurrentHashMap
    【集合框架】JDK1.8源码分析之HashMap
    一个整数,它加上100后是一个完全平方数, 再加上168又是一个完全平方数,请问该数是多少?
    猴子吃桃问题:猴子第一天摘下若干个桃子, 当即吃了一半,还不过瘾,又多吃了一个; 第二天早上又将剩下的桃子吃掉一半,又多吃了一个。 * 以后每天早上都吃了前一天剩下的一半零一个。 到第10天早上想再吃时,见只剩下一个桃子了。 求第一天共摘了多少。 * 1.程序分析:采取逆向思维的方法,从后往前推断。
    输出9*9口诀 输出9*9乘法表
  • 原文地址:https://www.cnblogs.com/yxgmagic/p/15629920.html
Copyright © 2020-2023  润新知