Spring 安全架構 - 線程應用

Spring Security 從根本上講是線程綁定的,因爲它需要使當前經過身份驗證的主體可供各種下游使用者使用。基本構件是 SecurityContext,它可以包含一個 Authentication(當用戶登錄時,它將是一個經過顯式 authenticatedAuthentication)。你始終可以通過 SecurityContextHolder 中的靜態便捷方法來訪問和操作 SeucurityContext,而該方法又可以簡單地操作 ThreadLocal,例如:

SecurityContext context = SecurityContextHolder.getContext();
Authentication authentication = context.getAuthentication();
assert(authentication.isAuthenticated);

用戶應用代碼執行該操作並不常見,但是例如在你需要編寫自定義身份驗證過濾器時可能會很有用(儘管即使如此,Spring Security 中也可以使用基類來避免需要使用 SecurityContextHolder)。

如果你需要訪問 Web 端點中當前經過身份驗證的用戶,則可以在 @RequestMapping 中使用 method 參數。例如:

@RequestMapping("/foo")
public String foo(@AuthenticationPrincipal User user) {
  ... // do stuff with user
}

該註解將當前的 AuthenticationSecurityContext 中拉出,並對其調用 getPrincipal() 方法以產生 method 參數。Authentication 中的 Principal 類型取決於驗證身份驗證的 AuthenticationManager,因此這是獲得對用戶數據的類型安全應用的有用的小技巧。

如果使用 Spring Security,則 HttpServletRequest 中的 Principal 將爲 Authentication 類型,因此你也可以直接使用它:

@RequestMapping("/foo")
public String foo(Principal principal) {
  Authentication authentication = (Authentication) principal;
  User = (User) authentication.getPrincipal();
  ... // do stuff with user
}

如果你需要編寫在不使用 Spring Security 時可以工作的代碼,那麼有時這很有用(你需要在裝入 Authentication 類時更具防禦性)。

異步處理安全方法

由於 SecurityContext 是線程綁定的,因此,如果要執行任何調用安全方法的後臺處理,例如使用 @Async,你需要確保傳播上下文。這歸結爲將 SecurityContext 打包爲在後臺執行的任務(RunnableCallable 等)。Spring Security 提供了一些幫助程序,例如 RunnableCallable 的包裝器。要將 SecurityContext 傳播到 @Async 方法,你需要提供 AsyncConfigurer 並確保 Executor 具有正確的類型:

@Configuration
public class ApplicationConfiguration extends AsyncConfigurerSupport {

  @Override
  public Executor getAsyncExecutor() {
    return new DelegatingSecurityContextExecutorService(Executors.newFixedThreadPool(5));
  }

}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章