springboot之jwt驗證

簡介

什麼是JWT(Json Web Token)

jwt是爲了在網絡應用環境間傳遞聲明而執行的一種基於json的開放標準。該token被設計緊湊且安全的,特別適用於SSO場景。
jwt的聲明通常被用來在身份提供者和服務提供者之間傳遞被認證的用戶身份信息。git

JWT長什麼樣

eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiJ0ZXN0MDAyIiwiZXhwIjoxNTEwOTcwMjU4fQ._FOqy5l44hODu3DjXh762LNUTLNQH15fdCUerdseDpmSKgkVSCjOyxQNTBKDSh3N-c83_pdEw5t6BdorgRU_kwgithub

JWT的構成

JWT一般由三部分組成,頭信息(header)、消息體(body)、簽名(signature)
頭信息指定了JWT使用的簽名算法web

header={alg=HS512}算法

消息體包含了JWT的意圖,exp爲令牌過時時間spring

body={sub=testUsername, exp=1510886546}json

簽名經過私鑰生成安全

signature=kwq8a_B6WMqHOrEi-gFR5rRPmPL7qoShZJn0VFfXpXc1Yfw6BfVrliAP9C4UnXlqD3wRXO3mw_DDIdglN5lH9Qspringboot

使用springboot集成jwt

jwt官網網絡

springboot官網app

引用依賴

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

相關文章
相關標籤/搜索