2015-11-19 151 views
2

我在服務層中有一個從隊列中讀取消息的異步方法。我需要將收到的消息發送給當前登錄用戶的用戶。用彈簧安全提取服務層中登錄的用戶

在我控制我獲取用戶的

(CustomUserDetail)SecurityContextHolder.getContext().getAuthentication().getPrincipal(); 

其工作正常,但在業務層相同的代碼拋出一個 NullPointerException。可能是由於SecurityContextHolder不是在相同的請求響應流中調用而不是異步調用,但同時我認爲Spring Security會保留會話中的所有用戶安全數據。所以它應該可以正常工作。

任何人都可以提出一種解決方法。如何獲取服務層中登錄的用戶?

我覺得一種可能的方式是,當控制器方法將消息推送到隊列&然後從服務層的會話中檢索用戶時,可以將活動用戶添加到會話中。

回答

2

HTTP會話在這裏也不可用。

問題出在這裏只是因爲您將調用從一個線程轉移到另一個線程。

如果您處理Spring Integration,您可以考慮使用SecurityContextPropagationChannelInterceptor爲您的queueChannel

否則你應該轉移Authentication對象與您的服務層手動一起數據。

的Spring Security可以幫助你Executors and Schedulers,但它不具有任何鉤與隊列操作......

+0

感謝您的建議,我添加身份驗證對象的消息。現在工作正常。我還嘗試了其他方式在會話中添加用戶對象,RequestContextHolder等,但將消息傳遞給身份驗證對象是最乾淨的。 – underdog

4

SecurityContextHolder默認模式是MODE_THREADLOCAL這意味着SecurityContextHolder僅在執行同一線程可用。

將其改爲MODE_INHERITABLETHREADLOCAL,應該會讓您在所有產生的線程中訪問SecurityContextHolder

SecurityContextHolder.setStrategyName(SecurityContextHolder.MODE_INHERITABLETHREADLOCAL)

應該解決您的問題。

+0

這隻適用於主線程產生的子線程。對使用@Async註釋的方法工作正常,但對隊列不起作用,仍然會給出NPE。我無法在同級線程之間共享安全上下文(例如,在線程池中)。儘管謝謝你的回答。 – underdog

+0

有沒有辦法將securitycontextobject添加到線程池或其他東西,以便每個線程都可以訪問它? – underdog

+1

如果您使用的是spring security 3.2或更高版本,則可以使用concurrncy支持。 http://docs.spring.io/spring-security/site/docs/current/reference/htmlsingle/#concurrency。 – nestrocuation