OAuth2RestTemplate 简介
1、概览
本文将带你了解如何使用 Spring OAuth2RestTemplate
进行 OAuth2 REST 调用。
创建一个 Spring Web 应用,用于列出 GitHub 账户下的所有仓库。
2、Maven 依赖
首先,需要在 pom.xml
中添加 spring-boot-starter-security 和 spring-security-oauth2-autoconfigure 依赖。由于构建的是 Web 应用,因此还需要包含 spring-boot-starter-web 和 spring-boot-starter-thymeleaf Starter。
<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 Properties
接下来,在 application.properties
文件中添加 OAuth 配置,以连接到 GitHub 账户:
# 替换为你的 CLIENT_ID
github.client.clientId=[CLIENT_ID]
# 替换为你的 CLIENT_SECRET
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
注意,需要用 GitHub OAuth App 中的值替换 [CLIENT_ID]
和 [CLIENT_SECRET]
。你可以按照 创建 OAuth App 指南在 GitHub 上注册一个新的应用:
确保 “Authorization callback URL” 设置为 http://localhost:8080
,这会把 OAuth 流程重定向到我们的 Web 应用主页。
4、OAuth2RestTemplate
配置
创建 Security 配置,为应用提供 OAuth2 支持。
4.1、SecurityConfig
类
@Configuration
@EnableOAuth2Client
public class SecurityConfig {
OAuth2ClientContext oauth2ClientContext;
public SecurityConfig(OAuth2ClientContext oauth2ClientContext) {
this.oauth2ClientContext = oauth2ClientContext;
}
...
}
@EnableOAuth2Client
使我们能够访问 OAuth2 Context,用它来创建 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 Properties 和 Context 来创建 Template 实例。
@ConfigurationProperties
注解将所有 github.client
属性注入 AuthorizationCodeResourceDetails
实例。
4.3、Authentication Filter
我们需要一个 Authentication Filter 来处理 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();
}
如上,指定 Filter 在应用的 /login/github
URL 上启动 OAuth2 流程。
4.4、Spring Security 配置
最后,注册 OAuth2ClientContextFilter
并创建 Web Security 配置:
@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、使用 Auth2RestTemplate
OAuth2RestTemplate
的主要目标是减少进行基于 OAuth2 的 API 调用所需的代码。它基本上满足了应用的两个需求:
- 处理 OAuth2 认证流程。
- 继承
RestTemplate
以进行 API 调用。
现在,可以在 Web Controller 中注入 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、主页
现在,创建一个 Controller 来处理通过身份认证的 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
的 name
作为视图中 Model 的属性。
home.html
template 如下:
<!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 仓库
使用 Controller 中的 OAuth2RestTemplate
来展示用户拥有的所有 GitHub 仓库。
首先,创建 GithubRepo
类来表示一个仓库:
public class GithubRepo {
Long id;
String name;
// get / set 省略
}
接着,在 AppController
添加一个 repos
端点:
@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
template 来遍历 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
来简化对 OAuth2 资源服务器(如 GitHub)的 REST 调用。
参考:https://www.baeldung.com/spring-oauth2resttemplate