• Java 的 JJWT 实现 JWT


    JJWT是一个提供端到端的JWT创建和验证的Java库

    依赖

            <dependency>
                <groupId>io.jsonwebtoken</groupId>
                <artifactId>jjwt</artifactId>
                <version>RELEASE</version>
            </dependency>
    

    token的创建

    setIssuedAt用于设置签发时间
    signWith用于设置签名秘钥
    
            JwtBuilder builder = Jwts.builder().setId("111")
                    .setSubject("小明")
                    .setIssuedAt(newDate())
                    .signWith(SignatureAlgorithm.HS256, "ld");
    
            String token = builder.compact();
    

    token的解析

            String token = "~~~";
            Claims claims = Jwts.parser().setSigningKey("ld").parseClaimsJws(token).getBody();
            System.out.println("id:" + claims.getId());
            System.out.println("subject:" + claims.getSubject());
            System.out.println("IssuedAt:" + claims.getIssuedAt());
    

    token过期校验

            long now = System.currentTimeMillis();  //当前时间
            long exp = now + 1000 * 60; //过期时间为1分钟
            JwtBuilder builder = Jwts.builder().setId("111")
                    .setSubject("小明")
                    .setIssuedAt(new Date())
                    .signWith(SignatureAlgorithm.HS256, "ld")
                    .setExpiration(new Date(exp));
    
    当未过期时可以正常读取
    当过期时会引发 io.jsonwebtoken.ExpiredJwtException 异常
    

    自定义claims

            long now = System.currentTimeMillis();  //当前时间
            long exp = now + 1000 * 60; //过期时间为1分钟
            JwtBuilder builder = Jwts.builder().setId("111")
                    .setSubject("小明")
                    .setIssuedAt(new Date())
                    .signWith(SignatureAlgorithm.HS256, "ld")
                    .setExpiration(new Date(exp))
                    .claim("role", "admin");
    
    获取:
        claims.get("role")
    

    示例

    JWT工具类
    
    @Data
    public class JwtUtil {
    
        private String key; //密钥加盐
    
        private long ttl;   //过期时间
    
        /**
         * 生成JWT
         */
        public String createJWT(String id, String subject, String role) {
            long nowMillis = System.currentTimeMillis();
            Date now = new Date(nowMillis);
            JwtBuilder builder = Jwts.builder().setId(id)
                    .setSubject(subject)
                    .setIssuedAt(now)
                    .signWith(SignatureAlgorithm.HS256, key).claim("role", role);
            if (ttl > 0) {
                builder.setExpiration(new Date(nowMillis + ttl));
            }
            return builder.compact();
        }
    
        /**
         * 解析JWT
         */
        public Claims parseJWT(String jwtStr) {
            return Jwts.parser()
                    .setSigningKey(key)
                    .parseClaimsJws(jwtStr)
                    .getBody();
        }
    }
    
    
    添加配置
    
    jwt:
      config:
        key: littledonkey
        ttl: 3600000
    
    
    签发token
    
            //判断是否密码是否正确
            Admin loginAdmin = adminService.login(admin);
            if (loginAdmin == null) {
                return new Result(false, StatusCode.LOGINERROR, "登陆失败");
            }
            //签发token
            String token = jwtUtil.createJWT(admin.getId(), admin.getLoginname(), "admin");
            HashMap<String, String> map = new HashMap<>();
            map.put("token", token);
            map.put("role", "admin");
            return new Result(true, StatusCode.OK, "登陆成功", map);
    

    使用拦截器方式实现token鉴权

    org.springframework.web.servlet.handler.HandlerInterceptorAdapter这个适配器,
    继承此类,可以非常方便的实现自己的拦截器。
    三个方法分别实现预处理、后处理(调用了Service并返回ModelAndView,但未进行页面渲染)、返回处理(已经渲染了页面):

    1. 在preHandle中,可以进行编码、安全控制等处理
    2. 在postHandle中,有机会修改ModelAndView
    3. 在afterCompletion中,可以根据ex是否为null判断是否发生了异常,进行日志记录
    添加拦截器
    
    @Component
    public class TokenInterceptor implements HandlerInterceptor {
        @Autowired
        private JwtUtil jwtUtil;
    
        @Override
        public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
            //获取请求头(如果有此请求头,表示token已经签发)
            String header = request.getHeader("tokenHeader");
            if (header != null || !"".equals(header)) {
                //解析请求头(防止伪造token,token内容以"token "作为开头)
                if (header.startsWith("token ")) {
                    try {
                        Claims claims = jwtUtil.parseJWT(header.substring(6));
                        String role = (String) claims.get("role");
                        //为具有相关权限的用户添加权限到request域中
                        if ("admin".equals(role)) {
                            //拿到"admin_token"头信息,表示当前角色是admin
                            request.setAttribute("admin_token", header.substring(6));
                        }
                        if ("user".equals(role)) {
                            //拿到"user_token"头信息,表示当前角色是user
                            request.setAttribute("user_token", header.substring(6));
                        }
                    } catch (Exception e) {
                        throw new RuntimeException("令牌不正确");
                    }
                }
            }
            //所有请求都通过,具体权限在service层判断
            return true;
        }
    }
    
    
    注册拦截器
    
    @Configuration
    public class InterceptorConfig extends WebMvcConfigurationSupport {
        @Autowired
        private TokenInterceptor tokenInterceptor;
    
        @Override
        protected void addInterceptors(InterceptorRegistry registry) {
            registry.addInterceptor(tokenInterceptor)
                    .addPathPatterns("/**")
                    .excludePathPatterns("/login/**");
        }
    }
    
    
    service层验证
    
        public void deleteById(String id) {
            String admin_token = (String) request.getAttribute("admin_token");
            if(admin_token == null || "".equals(admin_token)){
                throw new RuntimeException("权限不足");
            }
            adminDao.deleteById(id);
        }
    
  • 相关阅读:
    一种复杂的情感--“外戚”
    追~
    神受的孩子
    不好的习惯
    思杨改编的朝代歌
    siyang入厕
    小思趣事
    今天周三啦~~时光啊
    Python(6)——装饰器
    Python(5)——关于描述符的三种操作方法
  • 原文地址:https://www.cnblogs.com/loveer/p/11429111.html
Copyright © 2020-2023  润新知