Spring Security 5无状态OAuth2登录 - 如何实现基于Cookie的AuthorizationRequestRepository

时间:2018-03-04 12:27:53

标签: spring spring-boot spring-security

我正在尝试使用Spring Security 5 OAuth2登录功能登录Google / Facebook。但我面临的问题是我正在编写无状态API,而Spring安全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()));
    }
}

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

  1. 如何准确编码上面的removeAuthorizationRequest方法?我希望在那里删除cookie,但我们无法访问response对象。
  2. 上述(基于cookie)方法看起来不错吗?例如。任何安全问题?
  3. 更新:在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

0 个答案:

没有答案