You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Spring集成项目中OAuth2授权码模式调用REST API遇阻求助

解决Spring集成OAuth2授权码模式调用REST服务的重定向异常问题

你遇到的UserRedirectRequiredException是授权码模式的正常流程提示——因为授权码模式必须经过用户手动登录并同意授权的步骤,直接在代码里调用obtainAuthorizationCode是跳不过这个交互环节的。下面我来帮你梳理正确的实现方式:

错误原因分析

授权码模式的完整流程是:

  1. 客户端引导用户跳转到授权服务器的授权页面(就是你配置的userAuthorizationUri)
  2. 用户登录并同意授权后,授权服务器会重定向到你配置的preEstablishedRedirectUri,并携带授权码code
  3. 客户端用这个code加上客户端凭证,去授权服务器换取访问令牌access_token

你的代码直接调用authProvider.obtainAuthorizationCode(resource, request),但此时没有用户参与授权,所以框架抛出异常提示需要重定向到授权页面。

分场景解决方案

场景1:Web应用(推荐用Spring Security OAuth2 Client自动处理)

如果是Web项目,推荐用Spring Security的OAuth2客户端支持来自动处理重定向和授权流程,步骤如下:

  1. 配置OAuth2客户端信息(可以在application.yml中):
spring:
  security:
    oauth2:
      client:
        registration:
          infusionsoft:
            client-id: xxxxxx
            client-secret: xxxxxx
            authorization-grant-type: authorization_code
            redirect-uri: "https://myapps.com:8181/my_work"
            scope: full
        provider:
          infusionsoft:
            authorization-uri: https://signin.infusionsoft.com/app/oauth/authorize
            token-uri: https://api.infusionsoft.com/token
  1. 配置Spring Security,启用OAuth2登录:
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;

@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
            .authorizeRequests()
                .anyRequest().authenticated()
                .and()
            .oauth2Login() // 自动处理授权跳转、用户登录和回调逻辑
                .defaultSuccessUrl("/your-api-entry"); // 授权成功后的跳转路径
    }
}
  1. 注入OAuth2RestTemplate调用受保护API:
import org.springframework.security.oauth2.client.OAuth2RestTemplate;
import org.springframework.security.oauth2.client.resource.OAuth2ProtectedResourceDetails;
import org.springframework.stereotype.Component;

@Component
public class InfusionsoftApiClient {
    private final OAuth2RestTemplate restTemplate;

    public InfusionsoftApiClient(OAuth2ProtectedResourceDetails resourceDetails) {
        this.restTemplate = new OAuth2RestTemplate(resourceDetails);
    }

    public String fetchProtectedData() {
        // 框架会自动处理令牌的获取、刷新和携带
        return restTemplate.getForObject("https://api.infusionsoft.com/your-protected-endpoint", String.class);
    }
}

场景2:命令行/桌面应用(手动处理授权码)

如果是像你写的main方法那样的命令行程序,因为没有Web服务器处理回调,需要手动获取授权码:

import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
import java.util.Scanner;
import org.springframework.security.oauth2.client.token.AccessTokenRequest;
import org.springframework.security.oauth2.client.token.DefaultAccessTokenRequest;
import org.springframework.security.oauth2.client.token.grant.code.AuthorizationCodeAccessTokenProvider;
import org.springframework.security.oauth2.client.token.grant.code.AuthorizationCodeResourceDetails;
import org.springframework.security.oauth2.common.OAuth2AccessToken;
import org.springframework.security.oauth2.common.util.OAuth2Utils;

public class OAuth2Client1 {
    public static void main(String[] args) {
        AuthorizationCodeResourceDetails resource = new AuthorizationCodeResourceDetails();
        resource.setClientId("xxxxxx");
        resource.setClientSecret("xxxxxx");
        resource.setAccessTokenUri("https://api.infusionsoft.com/token");
        resource.setUserAuthorizationUri("https://signin.infusionsoft.com/app/oauth/authorize");
        resource.setPreEstablishedRedirectUri("https://myapps.com:8181/my_work");
        resource.setScope(Arrays.asList("full"));

        // 1. 生成授权URL,让用户手动打开浏览器访问
        Map<String, String> params = new HashMap<>();
        params.put(OAuth2Utils.CLIENT_ID, resource.getClientId());
        params.put(OAuth2Utils.REDIRECT_URI, resource.getPreEstablishedRedirectUri());
        params.put(OAuth2Utils.SCOPE, String.join(",", resource.getScope()));
        params.put(OAuth2Utils.RESPONSE_TYPE, "code");
        String authorizationUrl = OAuth2Utils.formatQueryString(params, resource.getUserAuthorizationUri());
        
        System.out.println("请打开以下链接完成授权:");
        System.out.println(authorizationUrl);

        // 2. 让用户复制回调URL中的code参数输入到程序
        Scanner scanner = new Scanner(System.in);
        System.out.println("请输入授权码:");
        String code = scanner.nextLine();

        // 3. 用授权码换取访问令牌
        try {
            AuthorizationCodeAccessTokenProvider authProvider = new AuthorizationCodeAccessTokenProvider();
            AccessTokenRequest request = new DefaultAccessTokenRequest();
            request.setAuthorizationCode(code);
            request.setRedirectUri(resource.getPreEstablishedRedirectUri());

            OAuth2AccessToken token = authProvider.obtainAccessToken(resource, request);
            System.out.println("获取到的访问令牌:" + token.getValue());
            // 后续可以用这个token调用受保护的REST服务
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

额外注意点

  • 确保你的preEstablishedRedirectUri已经在授权服务器(Infusionsoft)的应用配置中注册过,否则会被拒绝回调
  • Web应用中不要手动调用obtainAuthorizationCode,交给Spring Security自动处理流程更可靠
  • 生产环境中,不要硬编码客户端密钥clientSecret,建议通过配置中心或环境变量注入

内容的提问来源于stack exchange,提问作者user1516815

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.15 08:45:00