2017-04-23 50 views
4

我爲我的Spring啓動應用程序實現了JWT認證。總體而言,其工作原理如下:智威湯遜認證:如何實現註銷?

  1. 客戶端向登錄端點發送用戶名,密碼。
  2. 服務器檢查所提供的憑證是有效的。
  3. 如果沒有,它會返回一個錯誤
  4. 如果是的話,它會返回一個令牌,該令牌實際上包括
  5. 客戶端發送一個令牌與將來每一個請求

的問題是,應該如何我們實施註銷?

import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; 
import org.springframework.security.core.Authentication; 
import org.springframework.security.core.userdetails.UserDetails; 
import org.springframework.security.core.userdetails.UserDetailsService; 

import javax.servlet.http.HttpServletRequest; 
import javax.servlet.http.HttpServletResponse; 

import java.util.Date; 

class TokenAuthenticationService { 
    static final long EXPIRATIONTIME = 864_000_000; // 10 days 
    static final String SECRET = "ThisIsASecret"; 
    static final String TOKEN_PREFIX = "Bearer"; 
    static final String HEADER_STRING = "Authorization"; 

    static void addAuthentication(HttpServletResponse res, String username) { 
     String JWT = Jwts 
       .builder() 
       .setSubject(username) 
       .setExpiration(
         new Date(System.currentTimeMillis() + EXPIRATIONTIME)) 
       .signWith(SignatureAlgorithm.HS512, SECRET).compact(); 
     res.addHeader(HEADER_STRING, TOKEN_PREFIX + " " + JWT); 
    } 

    static Authentication getAuthentication(HttpServletRequest request, UserDetailsService customUserDetailsService) { 
     String token = request.getHeader(HEADER_STRING); 
     if (token != null) { 
      // parse the token. 
      Claims claims = Jwts.parser().setSigningKey(SECRET) 
        .parseClaimsJws(token.replace(TOKEN_PREFIX, "")).getBody(); 
      String userName = claims.getSubject(); 
      Date expirationTime = claims.getExpiration(); 
      if (expirationTime.compareTo(new Date()) < 0) { 
       return null; 
      } 
      UserDetails user = customUserDetailsService.loadUserByUsername(userName); 
      return user != null ? new UsernamePasswordAuthenticationToken(user.getUsername(), 
        user.getPassword(), user.getAuthorities()) : null; 
     } 
     return null; 
    } 
} 

addAuthentication使用由JWTLoginFilter類登錄時發送認證碼,「getAuthentication is used by the JWTAuthenticationFilter`該過濾器的所有請求的端點。

什麼是最好的做法嗎?

回答

10

我不認爲這裏有一個最好的做法。我想這取決於你正在構建的應用程序,它的要求。

智威湯遜的好處是,他們是無狀態的。您不需要查詢數據庫來驗證令牌。當你希望減少數據庫的負載時這是很好的,但是當你想要使一個現有的非過期令牌失效時就很不好。

可能的解決方案:

  • JWT儲存在數據庫中。你可以檢查哪些標記是有效的,哪些標記被撤銷,但這在我看來完全違背了使用JWT的目的。
  • 從客戶端刪除令牌。這將阻止客戶端能夠進行已認證的請求,但如果令牌仍然有效並且其他人有權訪問該令牌,則令牌仍然可以使用。這引導我到下一個要點。
  • 短令牌生存期。讓令牌快速過期。根據應用,可能需要幾分鐘或半小時。當客戶端刪除它的令牌時,有一段時間仍然可以使用。從客戶端刪除令牌並縮短令牌生存時間不需要對後端進行重大修改。但是令牌壽命短意味着用戶會因爲令牌已過期而不斷被註銷。
  • 旋轉標記。也許引入一個刷新令牌的概念。用戶登錄時,向他們提供JWT和刷新令牌。將刷新令牌存儲在數據庫中。對於認證的請求,客戶端可以使用JWT但是當令牌到期(或即將到期),讓客戶端使用的刷新令牌的請求,以換取新的JWT。這樣,當用戶登錄或要求新的JWT時,您只需點擊數據庫即可。當用戶註銷時,您需要使存儲的刷新令牌無效。否則,即使用戶已註銷,有人在連接上監聽也可能獲得新的JWT。
  • 創建智威湯遜黑名單。根據過期時間,當客戶端刪除其令牌時,它可能在一段時間內仍然有效。如果令牌生存期很短,這可能不是問題,但是如果您仍然希望該令牌立即失效,則可以創建令牌黑名單。當後端接收到註銷請求時,從請求中取出JWT並將其存儲在內存數據庫中。對於每個經過驗證的請求,您需要檢查內存數據庫以查看令牌是否已失效。爲了保持較小的搜索空間,您可以從黑名單中刪除已經過期的令牌。
3

我不知道什麼是最好的做法,但在一個系統,其內部我也看到了,有哪知道所有當前有效的身份驗證令牌的中央認證管理器,所以註銷將僅包括從取出令牌做收集有效令牌。

所以,下一次的認證管理器問令牌是否是有效的,它會用一個「不」迴應。

+0

這裏會出現問題。看看如何實現addAuthentication。認證碼取決於兩個因素:1.用戶名2.期望時間。用戶名永不改變,因此驗證碼在到期時間到期之前一直有效。 –

+0

除非在驗證管理器的當前有效令牌集合中可以找到它才被認爲是有效的。這正是我的答案所暗示的。 –

+0

在任何情況下,如果這是什麼讓您感到困擾,請在令牌中再添加一個獨特的術語,如計數器。 –