我遇到的问题是,在用户通过身份验证(即用户已登录)后,我从客户端了解到要注销用户,我从本地存储中删除令牌,但我遇到的问题是如何使令牌无效或从服务器端注销。
我最初的方法是让logout API
允许我的SecurityFilterChain
中的所有内容,但是当我试图在用户登录后从SecurityContextHolder
中获取经过身份验证的用户时,我得到的是anonymousUser
。
我的第二个/当前方法是我授权LOGOUT API
,这意味着要访问API,必须在头中传递一个令牌。然后我可以设置SecurityContextHolder.getContext().setAuthentication(authentication == false);
和clearContext()
。使用这种方法,我可以获得登录用户,但我的问题是:
1.这是实现注销的正确逻辑吗?
1.我知道令牌不能失效,因为它是STATELESS
。但有办法解决这个问题吗?因为即使在SecurityContextHolder
中将Authentication设置为false,并在我尝试访问Authenticated 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();
}
1条答案
按热度按时间zsohkypk1#
我可能会推荐一种不同的方法,但让我们从你的问题开始。
访问令牌到期
要使资源服务器令牌过期,您需要添加某种状态。
这通常以某种有效令牌列表的形式出现,如果令牌不在列表中,那么它就是无效的。
实现这一点的一个常见方法是依赖授权服务器。许多授权服务器都附带一个端点,您可以点击该端点来查看令牌是否仍然有效。
以不同方式建模
也就是说,如果您应该以不同的方式来考虑访问令牌,那么它可能是值得考虑的。访问令牌不代表用户的身份验证会话。它代表用户授权访问客户端以代表用户进行操作。
因此,在用户注销后,客户端仍然需要拥有一个有效的访问令牌,这样用户就不必在每次登录时重新授权客户端。