概述
在这个教程中,我们将学习如何使用Spring的OAuth2RestTemplate
进行OAuth2 REST调用。
我们将创建一个能够列出GitHub账户仓库的Spring Web应用。
2. Maven配置
首先,我们需要在pom.xml
文件中添加以下依赖:spring-boot-starter-security 和 spring-security-oauth2-autoconfigure。由于我们正在构建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属性
接下来,我们需要在application.properties
文件中添加OAuth配置以连接到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. SecurityConfig
类
首先,创建Spring的安全配置:
@Configuration
@EnableOAuth2Client
public class SecurityConfig {
OAuth2ClientContext oauth2ClientContext;
public SecurityConfig(OAuth2ClientContext oauth2ClientContext) {
this.oauth2ClientContext = oauth2ClientContext;
}
...
}
@EnableOAuth2Client
提供了访问OAuth2上下文,我们将使用它来创建OAuth2RestTemplate
。
4.2. OAuth2RestTemplate
Bean
其次,创建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控制器中作为自动注入的bean使用OAuth2RestTemplate
。
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
方法中有一个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
模板遍历仓库集合:
<!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
简化对OAuth2资源服务器(如GitHub)的REST调用。
我们了解了运行OAuth2流程的Web应用的基本构建块,然后看到了如何调用REST API来获取GitHub用户的全部仓库。
如往常一样,本教程的完整示例可以在GitHub上找到。