[英]Logout with JAAS login module
問題比預期的要長一點。 下面是一個類似的鏈接(第 3 篇文章),我沒有找到令人滿意的答案。
我正在嘗試使用 JAAS 登錄模塊注銷。 下面是項目的簡要結構: LoginService
負責在用戶想要登錄時實例化LoginContext
:
@Service
public class LoginService {
public UserDTO getUserDTOFrom(Credentials credentials) {
try {
LoginContext loginContext = new LoginContext("Login", new JAASCallbackHandler(credentials));
loginContext.login();
// construct UserDTO object.
} catch (LoginException e) {
LOGGER.error("Login Exception: {}", e.getMessage());
// construct UserDTO object.
}
// return UserDTO object.
}
LoginController
調用方法:
@RestController
@RequestMapping("/login")
public class LoginController {
private final LoginService loginService;
@Autowired
public LoginController(LoginService loginService) {
this.loginService = loginService;
}
@PostMapping
public ResponseEntity<UserDTO> getUserDTOFrom(@Valid @RequestBody Credentials credentials) {
UserDTO userDTO = loginService.getUserDTOFrom(userForm);
// return response that depends on outcome in the login service
}
}
當我想注銷以前登錄的用戶時會出現問題。 LoginContext
負責調用 JAAS 登錄模塊中的注銷方法。 例如:
loginContext.logout();
JAAS登錄模塊中的方法:
public class JAASLoginModule implements LoginModule {
@Override
public boolean logout() {
subject.getPrincipals().remove(usernamePrincipal);
subject.getPrincipals().remove(passwordPrincipal);
return true;
}
}
我在LogoutService
沒有LoginContext
並且無法完全清除以前經過身份驗證的主題。
我試圖創建一個單例 bean 來獲取LoginContext
的相同實例:
@Configuration
public class LoginContextBean {
@Lazy
@Bean
public LoginContext getLoginContext(Credentials credentials) throws LoginException {
System.setProperty("java.security.auth.login.config", "resources/configuration/jaas.config");
return new LoginContext("Login", new JAASCallbackHandler(credentials));
}
}
@Service
public class LoginService {
private final ObjectProvider<LoginContext> loginContextProvider;
@Autowired
public LoginService(ObjectProvider<LoginContext> loginContextProvider) {
this.loginContextProvider = loginContextProvider;
}
public UserDTO getUserDTOFrom(Credentials credentials) {
try {
LoginContext loginContext = loginContextProvider.getObject(credentials);
loginContext.login();
// construct UserDTO object.
} catch (LoginException e) {
LOGGER.error("Login Exception: {}", e.getMessage());
// construct UserDTO object.
}
// return UserDTO object.
}
}
@Service
public class LogoutService {
private final ObjectProvider<LoginContext> loginContextProvider;
@Autowired
public LogoutService(ObjectProvider<LoginContext> loginContextProvider) {
this.loginContextProvider = loginContextProvider;
}
public void performLogout() {
LoginContext loginContext = loginContextProvider.getObject();
try {
loginContext.logout();
} catch (LoginException e) {
LOGGER.error("Failed to logout: {}.", e.getMessage());
}
}
}
該解決方案不是特別有用,因為下一個/同一用戶登錄將在LoginContext
上獲得 NPE。 我讀到HttpServletRequest
的getSession().invalidate();
假設調用 JAAS 的logout()
或HttpServletRequest
的logout()
將完成這項工作。 但是這兩種方法都沒有效果。 例如:
@RestController
@RequestMapping("/logout")
public class LogoutController {
private final LogoutService logoutService;
@Autowired
public LogoutController(LogoutService logoutService) {
this.logoutService = logoutService;
}
@DeleteMapping
public ResponseEntity<Void> deleteJwt(@CookieValue("jwt_cookie") String jwtToken, HttpServletRequest request) throws ServletException {
request.getSession().invalidate(); // logout() is not called.
request.logout(); // logout() is not called.
return getResponse();
}
}
我想在用戶想要注銷時使用之前創建的LoginContext
,但在另一個用戶嘗試登錄時創建一個新的LoginContext
。請注意,我沒有使用 Spring Security。
編輯:
其中一個想法是使用一個單例來保存一Set
與特定用戶關聯的登錄上下文。 然后在用戶注銷時調用並銷毀它們。 此類Set
鍵可以是 JWT 令牌或用戶 ID。 經過進一步思考,在我看來,一個用戶可能有多個會話,在這種情況下,用戶 ID 作為密鑰將無法達到其目的。 第二個選項是 JWT 令牌,但有一種情況,未來的中間件將在到期時發出新的 JWT 令牌,然后我的Set
將無法返回有效的登錄上下文。
經過一些研究,我的團隊認為 JAAS 不適合我們的需求。 我們沒有使用它提供的完整功能,它束縛了我們的手,而不是使開發過程順暢。
如果您會遇到類似的問題,這里有一個解釋:我們使用的是支持 JAAS 的 WebSphere 8.5.5。 可以注銷,但代價是將其綁定到應用程序服務器。 考慮到我們的計划是從 WebSphere 遷移,此實現不是一個選項。
此類指南之一的鏈接位於此處。
未來有兩種選擇:
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.