springboot之jwt验证

简介

什么是JWT(Json Web Token)

jwt是为了在网络应用环境间传递声明而执行的一种基于json的开放标准。该token被设计紧凑且安全的,特别适用于SSO场景。
jwt的声明一般被用来在身份提供者和服务提供者之间传递被认证的用户身份信息。

JWT长什么样

eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiJ0ZXN0MDAyIiwiZXhwIjoxNTEwOTcwMjU4fQ._FOqy5l44hODu3DjXh762LNUTLNQH15fdCUerdseDpmSKgkVSCjOyxQNTBKDSh3N-c83_pdEw5t6BdorgRU_kw

JWT的构成

JWT通常由三部分组成,头信息(header)、消息体(body)、签名(signature)
头信息指定了JWT使用的签名算法

header={alg=HS512}

消息体包含了JWT的意图,exp为令牌过期时间

body={sub=testUsername, exp=1510886546}

签名通过私钥生成

signature=kwq8a_B6WMqHOrEi-gFR5rRPmPL7qoShZJn0VFfXpXc1Yfw6BfVrliAP9C4UnXlqD3wRXO3mw_DDIdglN5lH9Q

使用springboot集成jwt

jwt官网

springboot官网

引用依赖

  <dependency>
  	<groupId>org.springframework.boot</groupId>
  	<artifactId>spring-boot-starter-web</artifactId>
  </dependency>

  <dependency>
  	<groupId>org.springframework.boot</groupId>
  	<artifactId>spring-boot-starter-security</artifactId>
  </dependency>

  <dependency>
  	<groupId>org.springframework.boot</groupId>
  	<artifactId>spring-boot-actuator</artifactId>
  </dependency>

  <dependency>
  	<groupId>org.springframework.boot</groupId>
  	<artifactId>spring-boot-devtools</artifactId>
  </dependency>

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

构建普通rest接口

  @RestController
  @RequestMapping("/employee")
  public class EmployeeController {

      @GetMapping("/greeting")
       public String greeting() {
           return "Hello,World!";
       }
   }

JwtLoginFilter

public class JwtLoginFilter extends UsernamePasswordAuthenticationFilter {

   private AuthenticationManager authenticationManager;

   public JwtLoginFilter(AuthenticationManager authenticationManager) {
       this.authenticationManager = authenticationManager;
   }

  @Override
  public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response)
        throws AuthenticationException {
      Employee employee = new Employee();
       return authenticationManager.authenticate(
               new UsernamePasswordAuthenticationToken(
                   employee.getUsername(),
                   employee.getPassword(),
                   new ArrayList<>()
              )
       );
   }

  @Override
  protected void successfulAuthentication(HttpServletRequest request, HttpServletResponse response, 
   FilterChain chain, Authentication authResult) throws IOException, ServletException {
      String token = Jwts.builder()
           .setSubject(((User) authResult.getPrincipal()).getUsername())
           .setExpiration(new Date(System.currentTimeMillis() + 30 * 60 * 1000))
           .signWith(SignatureAlgorithm.HS512, "JWTSecret")
           .compact();

       response.addHeader("Authorization", JwtUtils.getTokenHeader(token));
  }

}

JwtAuthenticationFilter

  public class JwtAuthenticationFilter extends BasicAuthenticationFilter {

  public JwtAuthenticationFilter(AuthenticationManager authenticationManager) {
      super(authenticationManager);
  }

  @Override
  protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws IOException, ServletException {
      String header = request.getHeader("Authorization");

      if (header == null || !header.startsWith(JwtUtils.getAuthorizationHeaderPrefix())) {
          chain.doFilter(request, response);
         return;
      }

      UsernamePasswordAuthenticationToken authenticationToken = getUsernamePasswordAuthenticationToken(header);

      SecurityContextHolder.getContext().setAuthentication(authenticationToken);
      chain.doFilter(request, response);
  }

  private UsernamePasswordAuthenticationToken getUsernamePasswordAuthenticationToken(String token) {
      String user = Jwts.parser()
              .setSigningKey("PrivateSecret")
              .parseClaimsJws(token.replace(JwtUtils.getAuthorizationHeaderPrefix(), ""))
              .getBody()
              .getSubject();

      if (null != user) {
          return new UsernamePasswordAuthenticationToken(user, null, new ArrayList<>());
      }

      return null;
  }
  }

SecurityConfiguration

  @Configuration
  @Order(SecurityProperties.ACCESS_OVERRIDE_ORDER)
  public class SecurityConfiguration extends WebSecurityConfigurerAdapter {


    @Override
    public void configure(WebSecurity web) throws Exception {
          super.configure(web);
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
      http.cors().and().csrf().disable().authorizeRequests()
              .anyRequest().authenticated()
              .and()
              .addFilter(new JwtLoginFilter(authenticationManager()))
              .addFilter(new JwtAuthenticationFilter(authenticationManager()));
    }

  }

使用postman测试

首先我们先测试/employee/greeting 响应如下:

{
"timestamp": 1510887634904,
"status": 403,
"error": "Forbidden",
"message": "Access Denied",
"path": "/employee/greeting"
}

很明显,状态码为403,此刻我们如果先登录拿到token后再测试呢,测试如下

postman-test1

登录成功后,我们可以看到headers中已经带有jwt

authorization →Bearer eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiJ0ZXN0VXNlcm5hbWUiLCJleHAiOjE1MTA4ODkxMDd9.FtdEM0p84ff5CzDcoiQhtm1MF_NfDH2Ij1jspxlTQhuCISIzYdoU40OsFoxam9F1EXeVw2GZdQmArVwMk6HO1A

由于postman在一般情况下不支持自定义header 这个时候我们需要下载一个插件开启interceptor 开启后将authorization 放入header继续测试:
postman-test3

postman-test2

这时我们发现已经成功返回hello,world!

最后附上代码GitHub地址:源码下载

原文地址:https://www.cnblogs.com/huyunfan/p/7850680.html