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地址:源碼下載


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM