1. 概述
在本教程中,我们将学习如何使用Spring OAuth2RestTemplate进行OAuth2 REST调用。
我们将创建一个能够列出GitHub帐户仓库的SpringWeb应用程序。
2. Maven配置
首先,我们需要将spring-boot-starter-security和spring-security-oauth2-autoconfigure依赖项添加到我们的pom.xml中。在构建Web应用程序时,我们还需要包含spring-boot-starter-web和spring-boot-starter-thymeleaf工件。
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.security.oauth.boot</groupId>
<artifactId>spring-security-oauth2-autoconfigure</artifactId>
<version>2.6.8</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
3. OAuth2属性
接下来,让我们将OAuth配置添加到我们的application.properties文件中,以便能够连接GitHub帐户:
github.client.clientId=[CLIENT_ID]
github.client.clientSecret=[CLIENT_SECRET]
github.client.userAuthorizationUri=https://github.com/login/oauth/authorize
github.client.accessTokenUri=https://github.com/login/oauth/access_token
github.client.clientAuthenticationScheme=form
github.resource.userInfoUri=https://api.github.com/user
github.resource.repoUri=https://api.github.com/user/repos
请注意,我们需要将[CLIENT_ID]和[CLIENT_SECRET]替换为来自GitHub OAuth应用程序的值。我们可以按照创建OAuth应用程序指南在GitHub上注册新应用程序:
让我们确保授权回调URL设置为http://localhost:8080,这会将OAuth流重定向到我们的Web应用程序主页。
4. OAuth2RestTemplate配置
现在,是时候创建一个安全配置来为我们的应用程序提供OAuth2支持了。
4.1 安全配置类
首先,让我们创建Spring的安全配置:
@Configuration
@EnableOAuth2Client
public class SecurityConfig {
OAuth2ClientContext oauth2ClientContext;
public SecurityConfig(OAuth2ClientContext oauth2ClientContext) {
this.oauth2ClientContext = oauth2ClientContext;
}
// ...
}
@EnableOAuth2Client使我们能够访问OAuth2上下文,我们将使用它来创建OAuth2RestTemplate。
4.2 OAuth2RestTemplateBean
其次,我们将为OAuth2RestTemplate创建bean:
@Bean
public OAuth2RestTemplate restTemplate() {
return new OAuth2RestTemplate(githubClient(), oauth2ClientContext);
}
@Bean
@ConfigurationProperties("github.client")
public AuthorizationCodeResourceDetails githubClient() {
return new AuthorizationCodeResourceDetails();
}
有了这个,我们使用OAuth2属性和上下文来创建模板的实例。
@ConfigurationProperties注解将所有github.client属性注入到AuthorizationCodeResourceDetails实例。
4.3 身份验证过滤器
第三,我们需要一个身份验证过滤器来处理OAuth2流程:
private Filter oauth2ClientFilter() {
OAuth2ClientAuthenticationProcessingFilter oauth2ClientFilter = new OAuth2ClientAuthenticationProcessingFilter("/login/github");
OAuth2RestTemplate restTemplate = restTemplate();
oauth2ClientFilter.setRestTemplate(restTemplate);
UserInfoTokenServices tokenServices = new UserInfoTokenServices(githubResource().getUserInfoUri(), githubClient().getClientId());
tokenServices.setRestTemplate(restTemplate);
oauth2ClientFilter.setTokenServices(tokenServices);
return oauth2ClientFilter;
}
@Bean
@ConfigurationProperties("github.resource")
public ResourceServerProperties githubResource() {
return new ResourceServerProperties();
}
在这里,我们指示过滤器在我们应用程序的/login/github URL上启动OAuth2流。
4.4 Spring Security配置
最后,让我们注册OAuth2ClientContextFilter并创建一个Web安全配置:
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers("/", "/login**", "/error**")
.permitAll()
.anyRequest()
.authenticated()
.and()
.logout()
.logoutUrl("/logout")
.logoutSuccessUrl("/")
.and()
.addFilterBefore(oauth2ClientFilter(), BasicAuthenticationFilter.class);
return http.build();
}
@Bean
public FilterRegistrationBean<OAuth2ClientContextFilter> oauth2ClientFilterRegistration(OAuth2ClientContextFilter filter) {
FilterRegistrationBean<OAuth2ClientContextFilter> registration = new FilterRegistrationBean<>();
registration.setFilter(filter);
registration.setOrder(Ordered.HIGHEST_PRECEDENCE + 1);
return registration;
}
我们保护我们的Web应用程序路径并确保OAuth2ClientAuthenticationProcessingFilter在BasicAuthenticationFilter之前注册。
5. 使用OAuth2RestTemplate
OAuth2RestTemplate的主要目标是减少进行基于OAuth2的API调用所需的代码。它基本上满足了我们应用程序的两个需求:
- 处理OAuth2身份验证流程
- 扩展Spring RestTemplate以进行API调用
我们现在可以在Web控制器中将OAuth2RestTemplate用作自动注入的bean。
5.1 登录
让我们创建带有登录和主页选项的index.html文件:
<!DOCTYPE html>
<html lang="en" xmlns="http://www.w3.org/1999/xhtml" xmlns:th="http://www.thymeleaf.org">
<head>
<title>OAuth2Client</title>
</head>
<body>
<h3>
<a href="/login/github" th:href="@{/home}" th:if="${#httpServletRequest?.remoteUser != undefined }">
Go to Home
</a>
<a href="/hello" th:href="@{/login/github}" th:if="${#httpServletRequest?.remoteUser == undefined }">
GitHub Login
</a>
</h3>
</body>
</html>
未经身份验证的用户将看到登录选项,而经过身份验证的用户可以访问主页。
5.2 主页
现在,让我们创建一个控制器来问候经过身份验证的GitHub用户:
@Controller
public class AppController {
OAuth2RestTemplate restTemplate;
public AppController(OAuth2RestTemplate restTemplate) {
this.restTemplate = restTemplate;
}
@GetMapping("/home")
public String welcome(Model model, Principal principal) {
model.addAttribute("name", principal.getName());
return "home";
}
}
请注意,我们在welcome方法中有一个security Principal参数。我们使用Principal的名称作为UI模型的属性。
让我们来看看home.html模板:
<!DOCTYPE html>
<html lang="en" xmlns="http://www.w3.org/1999/xhtml" xmlns:th="http://www.thymeleaf.org">
<head>
<title>Home</title>
</head>
<body>
<p>
Welcome <b th:inline="text"> [[${name}]] </b>
</p>
<h3>
<a href="/repos">View Repositories</a><br/><br/>
</h3>
<form th:action="@{/logout}" method="POST">
<input type="submit" value="Logout"/>
</form>
</body>
</html>
此外,我们还添加了查看用户仓库列表的链接和注销选项。
5.3 GitHub仓库
现在,是时候使用在之前的控制器中创建的OAuth2RestTemplate来呈现用户拥有的所有GitHub仓库了。
首先,我们需要创建GithubRepo类来表示一个仓库:
public class GithubRepo {
Long id;
String name;
// getters and setters
}
其次,让我们在之前的AppController中添加一个访问仓库的映射:
@GetMapping("/repos")
public String repos(Model model) {
Collection<GithubRepo> repos = restTemplate.getForObject("https://api.github.com/user/repos", Collection.class);
model.addAttribute("repos", repos);
return "repositories";
}
OAuth2RestTemplate处理向GitHub发出请求的所有样板代码。此外,它将REST响应转换为GithubRepo集合。
最后,让我们创建repositories.html模板来遍历repositories集合:
<!DOCTYPE html>
<html lang="en" xmlns="http://www.w3.org/1999/xhtml" xmlns:th="http://www.thymeleaf.org">
<head>
<title>Repositories</title>
</head>
<body>
<p>
<h2>Repos</h2>
</p>
<ul th:each="repo: ${repos}">
<li th:text="${repo.name}"></li>
</ul>
</body>
</html>
6. 总结
在本文中,我们学习了如何使用OAuth2RestTemplate来简化对GitHub等OAuth2资源服务器的REST调用。
我们浏览了运行OAuth2流程的Web应用程序的构建块。然后,我们看到了如何调用REST API来检索所有GitHub用户的仓库。
与往常一样,本教程的完整源代码可在GitHub上获得。