Spring Security 5 Stateless OAuth2 Login - 如何实现基于 cookie 的 AuthorizationRequestRepository

San*_*jay 7 spring spring-security spring-boot

我正在尝试使用 Spring Security 5 OAuth2 登录功能让 Google/Facebook 登录。但我面临的问题是我正在编写一个无状态 API,而 Spring security 5 用于HttpSessionOAuth2AuthorizationRequestRepository存储授权请求,它使用会话。因此,我认为不要使用它并编写基于 cookie 的实现,如下所示:

public class HttpCookieOAuth2AuthorizationRequestRepository implements AuthorizationRequestRepository<OAuth2AuthorizationRequest> {

    private static final String COOKIE_NAME = "some-name";

    @Override
    public OAuth2AuthorizationRequest loadAuthorizationRequest(HttpServletRequest request) {

        Assert.notNull(request, "request cannot be null");

        return fetchCookie(request)
                .map(this::toOAuth2AuthorizationRequest)
                .orElse(null);
    }

    @Override
    public void saveAuthorizationRequest(OAuth2AuthorizationRequest authorizationRequest, HttpServletRequest request,
            HttpServletResponse response) {

        Assert.notNull(request, "request cannot be null");
        Assert.notNull(response, "response cannot be null");

        if (authorizationRequest == null) {

            deleteCookie(request, response);
            return;
        }

        Cookie cookie = new Cookie(COOKIE_NAME, fromAuthorizationRequest(authorizationRequest));
        cookie.setPath("/");
        cookie.setHttpOnly(true);
        response.addCookie(cookie);
    }


    private String fromAuthorizationRequest(OAuth2AuthorizationRequest authorizationRequest) {

        return Base64.getUrlEncoder().encodeToString(
                SerializationUtils.serialize(authorizationRequest));
    }

    private void deleteCookie(HttpServletRequest request, HttpServletResponse response) {

        fetchCookie(request).ifPresent(cookie -> {

            cookie.setValue("");
            cookie.setPath("/");
            cookie.setMaxAge(0);
            response.addCookie(cookie);
        });
    }

    @Override
    public OAuth2AuthorizationRequest removeAuthorizationRequest(HttpServletRequest request) {

        // Question: How to remove the cookie, because we don't have access to response object here.
        return loadAuthorizationRequest(request);
    }

    private Optional<Cookie> fetchCookie(HttpServletRequest request) {

        Cookie[] cookies = request.getCookies();

        if (cookies != null && cookies.length > 0)
            for (int i = 0; i < cookies.length; i++)
                if (cookies[i].getName().equals(COOKIE_NAME))
                    return Optional.of(cookies[i]);

        return Optional.empty();
    }

    private OAuth2AuthorizationRequest toOAuth2AuthorizationRequest(Cookie cookie) {

        return SerializationUtils.deserialize(
                Base64.getUrlDecoder().decode(cookie.getValue()));
    }
}
Run Code Online (Sandbox Code Playgroud)

以上基本上将数据存储在cookie而不是会话中。我有几个问题:

  1. 如何准确地编码上述removeAuthorizationRequest方法?我想在那里删除 cookie,但我们无权访问该response对象。
  2. 上述(基于 cookie 的)方法看起来好吗?例如任何安全问题?

更新:在https://github.com/spring-projects/spring-security/issues/5313创建了一个问题。在解决这个问题之前,这是我想出的解决方法:https : //www.naturalprogrammer.com/blog/1681261/spring-security-5-oauth2-login-signup-stateless-restful-web-services