SpringBoot使用JWT实现登录拦截验证

一、定义

  • JSON Web Token(JWT)是一个开放的标准(RFC 7519)
  • 定义了一个紧凑且自包含的方式,用于在各方之间以JSON对象安全地传输信息
  • 信息可以通过数字签名进行验证和信任
  • 可以使用秘密(使用HMAC算法)或使用RSA的公钥/私钥对来对JWT进行签名

二、请求流程

SpringBoot使用JWT实现登录拦截验证_第1张图片

  • 1、用户在浏览器中输入用户名、密码进行登录验证
  • 2、服务端登录验证
  • 3、成功则返回生成的JWT,失败则抛出异常报错
  • 4、用户以后每次请求服务端时,请求头携带JWT
  • 5、服务端进行JWT验证
  • 6、成功则返回接口调用信息,失败则抛出异常报错

三、组成

1、头部(header)

  • 声明类型
  • 声明加密的算法(通常使用HMAC SHA256)
{
   "typ":"JWT",
   "alg":"HS256"
}

2、载荷(payload)

  • 存放一些有效的信息(自定义数据)
  • iss:该JWT的签发者
  • sub: 该JWT所面向的用户
  • aud: 接收该JWT的一方
  • exp(expires): 什么时候过期,这里是一个Unix时间戳
  • iat(issued at): 在什么时候签发的

3、签证(signature)

使用了HS256加密后的数据,包含三个部分:

  • header (base64后的)
  • payload (base64后的)
  • secret 私钥

四、SpringBoot应用JWT

1、添加依赖

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

2、配置信息

#jwt
audience.clientId=098f6bcd4621d373cade4e832627b4f6
audience.base64Secret=MDk4ZjZiY2Q0NjIxZDM3M2NhZGU0ZTgzMjYyN2I0ZjY=
audience.name=restapiuser
#24小时
audience.expiresSecond=86400000

3、书写JWT工具类

  • User为系统中用户的实体类
  /**
     * @Author thailandking
     * @Date 2019/8/22 16:20
     * @LastEditors thailandking
     * @LastEditTime 2019/8/22 16:20
     * @Description JWT工具类
     */
    @Component
    public class JwtUtil {
        @Value("${audience.clientId}")
        private String clientId;
        @Value("${audience.base64Secret}")
        private String base64Secret;
        @Value("${audience.name}")
        private String name;
        @Value("${audience.expiresSecond}")
        private Long expiresSecond;
    
        //解析jwt
        public User parseJWT(String jsonWebToken) {
            try {
                Claims claims = Jwts.parser()
                        .setSigningKey(DatatypeConverter.parseBase64Binary(base64Secret))
                        .parseClaimsJws(jsonWebToken).getBody();
                if (claims == null) {
                    return null;
                }
                Long id = (Long) claims.get("id");
                String name = (String) claims.get("name");
                User user = new User();
                user.setId(id);
                user.setName(name);
                return user;
            } catch (Exception e) {
                return null;
            }
        }
    
        //构建jwt
        public String createJWT(User user) {
            SignatureAlgorithm signatureAlgorithm = SignatureAlgorithm.HS256;
            //生成签名密钥
            byte[] apiKeySecretBytes = DatatypeConverter.parseBase64Binary(base64Secret);
            Key signingKey = new SecretKeySpec(apiKeySecretBytes, signatureAlgorithm.getJcaName());
            //添加构成JWT的参数
            JwtBuilder builder = Jwts.builder().setHeaderParam("typ", "JWT")
                    .claim("id", user.getId())
                    .claim("name", user.getName())
                    .setIssuer(clientId)
                    .setAudience(name)
                    .signWith(signatureAlgorithm, signingKey);
            //添加Token过期时间
            long nowMillis = System.currentTimeMillis();
            Date now = new Date(nowMillis);
            long expMillis = nowMillis + expiresSecond;
            Date exp = new Date(expMillis);
            builder.setExpiration(exp).setNotBefore(now);
            //生成JWT
            return builder.compact();
        }
    }

4、书写拦截器

 public class LoginIntercepter implements HandlerInterceptor {
    
        @Autowired
        private JwtUtil jwtUtil;
    
        @Override
        public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
            String token = request.getHeader("token");
            //401
            if (StringUtils.isEmpty(token)) {
                response.setStatus(HttpStatus.UNAUTHORIZED.value());
                return false;
            }
            //403
            // 注入工具类
            if (jwtUtil == null) {
                BeanFactory factory = WebApplicationContextUtils.getRequiredWebApplicationContext(request.getServletContext());
                jwtUtil = (JwtUtil) factory.getBean("jwtUtil");
            }
            User user = jwtUtil.parseJWT(token);
            if (user == null) {
                response.setStatus(HttpStatus.FORBIDDEN.value());
                return false;
            }
            return true;
        }
    }

5、配置拦截器

@Configuration
public class IntercepterConfig implements WebMvcConfigurer {

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(new LoginIntercepter()).addPathPatterns("/user/**");
        WebMvcConfigurer.super.addInterceptors(registry);
    }
}

6、书写登录代码

 @Autowired
    private JwtUtil jwtUtil;
    /**
         * @Author thailandking
         * @Date 2019/8/22 14:13
         * @LastEditors thailandking
         * @LastEditTime 2019/8/22 14:13
         * @Description jwt示例 用户登录
         */
    @RequestMapping(value = "/login", method = RequestMethod.POST)
    public Response login(@RequestParam(value = "name") String name,
                          @RequestParam(value = "pass") String pass) {
        // 登录判定
        User user = userService.getLoginUserService(name, pass);
        // 生成token
        String token = jwtUtil.createJWT(user);
        return Response.ok().data(token);
    }

7、跨域配置

@Configuration
public class CrossConfig {

    @Bean
    public FilterRegistrationBean corsFilter() {
        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
        CorsConfiguration config = new CorsConfiguration();
        config.setAllowCredentials(true);
        config.addAllowedOrigin("*");
        config.addAllowedHeader("*");
        config.addAllowedMethod("OPTIONS");
        config.addAllowedMethod("HEAD");
        config.addAllowedMethod("GET");
        config.addAllowedMethod("PUT");
        config.addAllowedMethod("POST");
        config.addAllowedMethod("DELETE");
        config.addAllowedMethod("PATCH");
        source.registerCorsConfiguration("/**", config);
        final FilterRegistrationBean bean = new FilterRegistrationBean(new CorsFilter(source));
        bean.setOrder(0);
        return bean;
    }

    @Bean
    public WebMvcConfigurer mvcConfigurer() {
        return new WebMvcConfigurer() {
            @Override
            public void addCorsMappings(CorsRegistry registry) {
                registry.addMapping("/**").allowedMethods("GET", "PUT", "POST", "GET", "OPTIONS");
            }
        };
    }
}

你可能感兴趣的:(springboot)