我遇到的问题是在用户通过身份验证后--意思是用户已经登录了,我从客户端了解到要注销一个用户,我从本地存储中删除令牌,但问题是如何使令牌无效或从服务器端注销。
我最初的方法是让logout API许可全部在我的SecurityFilterChain中,但是当我试图在用户登录后从SecurityContextHolder抓取经过身份验证的用户时,我就得到了anonymousUser。
我的第二种/当前方法是授权LOGOUT API,这意味着访问API,必须在标头中传递令牌。然后,我可以设置SecurityContextHolder.getContext().setAuthentication(authentication == false);和clearContext()。通过这种方法,我可以获得登录用户,但我的问题是:
STATELESS。但有办法绕过这件事吗?因为即使在SecurityContextHolder中将身份验证设置为false并在尝试访问经过身份验证的API (即CRUD operations )时清除安全上下文SecurityContextHolder.clearContext();,我仍然能够使用令牌.以下是我在RestController类中的登录和注销方法
注销
@PostMapping(path = "/logout", headers = "Authorization")
@ResponseStatus(OK)
public ResponseEntity<?> logout() {
LOGGER.info("Trying to Logout ");
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
String username = authentication.getName();
LOGGER.info("Username {} ", username);
authentication.setAuthenticated(false);
SecurityContextHolder.getContext().setAuthentication(authentication);
SecurityContextHolder.clearContext();
return ResponseEntity.ok().body("Successfully logged out");
}登录
@PostMapping(path = "/login", consumes = "application/json", produces = "application/json")
@ResponseStatus(OK)
public ResponseEntity<?> login(@Valid @RequestBody UserDTO userDTO) {
Authentication authentication;
LOGGER.info("Authenticating {}", userDTO.getUsername());
var authenticationToken = confirmUser(userDTO); // returns a UsernamePasswordAuthenticationToken
try {
authentication = authenticationManager.authenticate(authenticationToken); // Authenticate user password token
SecurityContextHolder.getContext().setAuthentication(authentication); // Set the security context to the logged user
} catch (AuthenticationException e) {
LOGGER.error("Stack trace {}", e.getMessage());
SecurityContextHolder.getContext().setAuthentication(null);
throw new InvalidPasswordException("Wrong username or password");
}
LOGGER.info("{} has signed in", userDTO.getUsername());
return ResponseEntity.ok()
.header( AUTHORIZATION, tokenService.generateToken(authentication) )
.build();
}发布于 2022-10-28 20:26:39
我可能会推荐一种不同的方法,但让我们从你的问题开始。
到期访问令牌
若要使资源服务器令牌过期,您需要添加某种状态。
这通常是以某种有效令牌列表的形式出现的。如果令牌不在列表中,则令牌无效。
实现这一目标的一个常见方法是依赖授权服务器。许多授权服务器都附带了一个端点,您可以点击该端点来查看令牌是否仍然有效。
以不同的方式建模
尽管如此,如果您应该以不同的方式来考虑访问令牌,这可能是值得考虑的。访问令牌不表示用户经过身份验证的会话。它表示授予客户端代表用户操作的权限的用户。
因此,在用户注销后,客户端拥有一个有效的访问令牌仍然很有意义,这样用户就不必每次登录时都重新授权客户机。
https://stackoverflow.com/questions/74229764
复制相似问题