如何使用OAuth2RestTemplate?

时间:2015-01-09 15:50:49

标签: spring api rest oauth spring-security

我正在尝试了解如何使用OAuth2RestTemplate对象来使用我的OAuth2安全REST服务(该服务在不同的项目下运行,我们也假设在不同的服务器上等等)。

f.e。我的休息服务是:

http://localhost:8082/app/helloworld

- >访问此URL会生成错误,因为我未经过身份验证

要请求令牌,我会去:

http://localhost:8082/app/oauth/token?grant_type=password&client_id=restapp&client_secret=restapp&username=**USERNAME**&password=**PASSWORD**

收到令牌后,我可以使用以下URL连接到REST API(插入示例令牌)

http://localhost:8082/app/helloworld/?access_token=**4855f557-c6ee-43b7-8617-c24591965206**

现在我的问题是如何实现可以使用这个OAuth2安全REST API的第二个应用程序?我真的没有找到任何提供用户名和密码的工作示例(例如来自登录表单),然后生成一个令牌,可以重新使用该令牌从REST API获取数据。

我目前尝试使用以下对象:

BaseOAuth2ProtectedResourceDetails baseOAuth2ProtectedResourceDetails =  new BaseOAuth2ProtectedResourceDetails();
baseOAuth2ProtectedResourceDetails.setClientId("restapp");
baseOAuth2ProtectedResourceDetails.setClientSecret("restapp");
baseOAuth2ProtectedResourceDetails.setGrantType("password");
// how to set user name and password ???

DefaultAccessTokenRequest accessTokenRequest = new DefaultAccessTokenRequest();
OAuth2ClientContext oAuth2ClientContext = new DefaultOAuth2ClientContext(accessTokenRequest());

OAuth2RestTemplate restTemplate = new OAuth2RestTemplate(baseOAuth2ProtectedResourceDetails,oAuth2ClientContext);

但这不起作用:(

非常感谢任何想法或非常感谢链接到工作示例和教程。

3 个答案:

答案 0 :(得分:39)

您可以在https://github.com/spring-projects/spring-security-oauth

找到编写Oauth客户的示例

在您的情况下,您不能只为所有内容使用默认或基类,您有多个类实现OAuth2ProtectedResourceDetails。配置取决于你如何配置你的Oauth服务,但假设从你的curl连接我会建议:

@EnableOAuth2Client
@Configuration
class MyConfig{




    @Value("${oauth.resource:http://localhost:8082}")
    private String baseUrl;
    @Value("${oauth.authorize:http://localhost:8082/oauth/authorize}")
    private String authorizeUrl;
    @Value("${oauth.token:http://localhost:8082/oauth/token}")
    private String tokenUrl


    @Bean
    protected OAuth2ProtectedResourceDetails resource() {

        ResourceOwnerPasswordResourceDetails resource = new ResourceOwnerPasswordResourceDetails();

        List scopes = new ArrayList<String>(2);
        scopes.add("write");
        scopes.add("read");
        resource.setAccessTokenUri(tokenUrl);
        resource.setClientId("restapp");
        resource.setClientSecret("restapp");
        resource.setGrantType("password");
        resource.setScope(scopes);

        resource.setUsername("**USERNAME**");
        resource.setPassword("**PASSWORD**");

        return resource;
    }

    @Bean
    public OAuth2RestOperations restTemplate() {
        AccessTokenRequest atr = new DefaultAccessTokenRequest();

        return new OAuth2RestTemplate(resource(), new DefaultOAuth2ClientContext(atr));
    }

}

@Service
@SuppressWarnings("unchecked")
class MyService {
    @Autowired
    private OAuth2RestOperations restTemplate;

    public MyService() {

        restTemplate.getAccessToken();
    }
}

不要忘记你的配置类上的@ EnableOAuth2Client,我也建议尝试使用你正在使用的网址首先使用curl,同时尝试使用调试器跟踪它,因为很多例外只是消耗而且从不打印出于正当的安全原因,所以很难找到问题所在。您应该使用具有调试启用集的记录器。 祝你好运

我在github https://github.com/mariubog/oauth-client-sample上传了示例springboot app 描述你的情况,因为我找不到你的情景的任何样本。

答案 1 :(得分:2)

在@mariubog(https://stackoverflow.com/a/27882337/1279002)的回答中,我也使用了密码授权类型,但是需要将客户端身份验证方案设置为表单。密码端点不支持范围,并且不需要设置授权类型,因为ResourceOwnerPasswordResourceDetails对象在构造函数中设置它本身。

...

public ResourceOwnerPasswordResourceDetails() {
    setGrantType("password");
}

...

对我来说,关键是如果未设置resource.setClientAuthenticationScheme(AuthenticationScheme.form);,则client_id和client_secret不会被添加到表单对象中以在正文中发布。

请参阅开关:      org.springframework.security.oauth2.client.token.auth.DefaultClientAuthenticationHandler.authenticateTokenRequest()

最后,当连接到Salesforce端点时,需要将密码令牌附加到密码。

@EnableOAuth2Client
@Configuration
class MyConfig {

@Value("${security.oauth2.client.access-token-uri}")
private String tokenUrl;

@Value("${security.oauth2.client.client-id}")
private String clientId;

@Value("${security.oauth2.client.client-secret}")
private String clientSecret;

@Value("${security.oauth2.client.password-token}")
private String passwordToken;

@Value("${security.user.name}")
private String username;

@Value("${security.user.password}")
private String password;


@Bean
protected OAuth2ProtectedResourceDetails resource() {

    ResourceOwnerPasswordResourceDetails resource = new ResourceOwnerPasswordResourceDetails();

    resource.setAccessTokenUri(tokenUrl);
    resource.setClientId(clientId);
    resource.setClientSecret(clientSecret);
    resource.setClientAuthenticationScheme(AuthenticationScheme.form);
    resource.setUsername(username);
    resource.setPassword(password + passwordToken);

    return resource;
}

@Bean
 public OAuth2RestOperations restTemplate() {
    return new OAuth2RestTemplate(resource(), new DefaultOAuth2ClientContext(new DefaultAccessTokenRequest()));
    }
}


@Service
@SuppressWarnings("unchecked")
class MyService {
    @Autowired
    private OAuth2RestOperations restTemplate;

    public MyService() {
        restTemplate.getAccessToken();
    }
}

答案 2 :(得分:0)

我的简单解决方案。恕我直言,这是最干净的。

首先创建一个 application.yml

spring.main.allow-bean-definition-overriding: true

security:
  oauth2:
    client:
      clientId: XXX
      clientSecret: XXX
      accessTokenUri: XXX
      tokenName: access_token
      grant-type: client_credentials

创建主类: Main

@SpringBootApplication
@EnableOAuth2Client
public class Main extends WebSecurityConfigurerAdapter {

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
                .authorizeRequests()
                .antMatchers("/").permitAll();
    }

    public static void main(String[] args) {
        SpringApplication.run(Main.class, args);
    }

    @Bean
    public OAuth2RestTemplate oauth2RestTemplate(ClientCredentialsResourceDetails details) {
        return new OAuth2RestTemplate(details);
    }

}

然后创建控制器类: Controller

@RestController
class OfferController {

    @Autowired
    private OAuth2RestOperations restOperations;

    @RequestMapping(value = "/<your url>"
            , method = RequestMethod.GET
            , produces = "application/json")
    public String foo() {
        ResponseEntity<String> responseEntity = restOperations.getForEntity(<the url you want to call on the server>, String.class);
        return responseEntity.getBody();
    }
}

Maven依赖项

<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>2.1.5.RELEASE</version>
</parent>
<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.security.oauth.boot</groupId>
        <artifactId>spring-security-oauth2-autoconfigure</artifactId>
        <version>2.1.5.RELEASE</version>
    </dependency>
</dependencies>