构建OAuth2客户端时,使用Spring Security的authCodeGrant,如何在授权码交换访问令牌的步骤中进行干预?

问题描述 投票:0回答:1

我正在针对 Quickbooks 构建一个 Java Spring Boot OAuth2 客户端应用程序,我正在使用 Spring Security 对 OAuth2 客户端开发的本机支持(spring-documentation)并且能够成功获取访问令牌和刷新令牌,谢谢注释@RegisteredOAuth2AuthorizedClient.

问题是 Quickbooks 在授权代码交换访问令牌的 OAuth2 步骤中发送连接到预期 OAuth2 客户端应用程序的帐户(和帐户中的特定公司)的帐户 ID(他们称之为 realmId)。在开发人员工具上看到网络调用时,我可以看到 302 到 http://localhost/8080/?code=<>&state=<>&realmId=<>(如图所示),我的应用程序中需要这个 realmId我找不到抓住它的方法。

OAuth2AuthorizedClient 对象为我提供了访问令牌和刷新令牌,但无法到达之前的 OAuth2 授权代码交换舞步以获取访问令牌,我需要处理该访问令牌才能获取 realmId。

根据 Quickbooks,没有可以访问的 API(有或没有持有者令牌)来获取 realmId,唯一的方法是在 OAuth2 舞蹈之间进行干预并获取它。

spring-boot spring-security quickbooks-online
1个回答
0
投票

这是一个示例

OAuth2AuthorizationRequestResolver
在授权代码流期间在会话中保存
realmId

@Component
static class MyOAuth2AuthorizationRequestResolver implements OAuth2AuthorizationRequestResolver {
    private final OAuth2AuthorizationRequestResolver defaultResolver;

    public MyOAuth2AuthorizationRequestResolver(InMemoryClientRegistrationRepository clientRegistrationRepository) {
        defaultResolver = new DefaultOAuth2AuthorizationRequestResolver(
                clientRegistrationRepository,
                OAuth2AuthorizationRequestRedirectFilter.DEFAULT_AUTHORIZATION_REQUEST_BASE_URI);
    }

    @Override
    public OAuth2AuthorizationRequest resolve(HttpServletRequest request) {
        saveRealmIdInSession(request);
        return defaultResolver.resolve(request);
    }

    @Override
    public OAuth2AuthorizationRequest resolve(HttpServletRequest request, String clientRegistrationId) {
        saveRealmIdInSession(request);
        return defaultResolver.resolve(request, clientRegistrationId);
    }

    private void saveRealmIdInSession(HttpServletRequest request) {
        final var realmIds = request.getParameterValues("realmId");
        if (realmIds.length < 1) {
            return;
        }
        SessionSupport.setAttribute("realmId", realmIds[0]);
    }
}

static class SessionSupport {
    static Optional<HttpSession> getSession() {
        RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();
        if (requestAttributes instanceof ServletRequestAttributes servletAttributes) {
            return Optional.ofNullable(servletAttributes.getRequest()).flatMap(req -> Optional.ofNullable(req.getSession()));
        }
        return Optional.empty();
    }

    static Object getAttribute(String name) {
        return getSession().map(session -> session.getAttribute(name)).orElse(null);
    }

    static void setAttribute(String name, Object value) {
        getSession().ifPresent(session -> session.setAttribute(name, value));
    }
}

您将其添加到您的安全过滤器链配置中,如下所示:

@Bean
SecurityFilterChain clientSecurityFilterChain(
        HttpSecurity http,
        OAuth2AuthorizationRequestResolver authorizationRequestResolver)
        throws Exception {
    http.oauth2Login(oauth2 -> oauth2.authorizationEndpoint(authorization -> authorization.authorizationRequestResolver(authorizationRequestResolver)));

    ...

    return http.build();
}

之后您要做的就是阅读会话以获取

realmId
,访问它的方式与保存在
MyOAuth2AuthorizationRequestResolver
中时相同。

© www.soinside.com 2019 - 2024. All rights reserved.