Spring Boot 在Spring应用程序中使用oauth2ResourceServer JWT实现RESTFUL注销API的逻辑

juzqafwq  于 2022-11-05  发布在  Spring
关注(0)|答案(1)|浏览(120)

我遇到的问题是,在用户通过身份验证(即用户已登录)后,我从客户端了解到要注销用户,我从本地存储中删除令牌,但我遇到的问题是如何使令牌无效或从服务器端注销。
我最初的方法是让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();
    }
zsohkypk

zsohkypk1#

我可能会推荐一种不同的方法,但让我们从你的问题开始。

访问令牌到期

要使资源服务器令牌过期,您需要添加某种状态。
这通常以某种有效令牌列表的形式出现,如果令牌不在列表中,那么它就是无效的。
实现这一点的一个常见方法是依赖授权服务器。许多授权服务器都附带一个端点,您可以点击该端点来查看令牌是否仍然有效。

以不同方式建模

也就是说,如果您应该以不同的方式来考虑访问令牌,那么它可能是值得考虑的。访问令牌不代表用户的身份验证会话。它代表用户授权访问客户端以代表用户进行操作。
因此,在用户注销后,客户端仍然需要拥有一个有效的访问令牌,这样用户就不必在每次登录时重新授权客户端。

相关问题