我正在尝试了解如何使用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);
但这不起作用:(
非常感谢任何想法或非常感谢链接到工作示例和教程。
答案 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>