本文目录导读:

- Maven依赖配置
- 配置文件 application.yml
- 主应用类
- 安全配置类
- 自定义请求实体转换器
- 自定义OAuth2用户服务
- 自定义OAuth2用户类
- 控制器类
- API客户端调用示例
- HTML模板
- 配置文件 application.properties (备用)
- 运行说明
- 完整功能说明
我来提供一个完整的Java实现OAuth2客户端的案例,使用Spring Security OAuth2 Client框架。
Maven依赖配置
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.7.14</version>
<relativePath/>
</parent>
<groupId>com.example</groupId>
<artifactId>oauth2-client-demo</artifactId>
<version>1.0.0</version>
<name>oauth2-client-demo</name>
<description>OAuth2 Client Demo</description>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<!-- Spring Boot Web -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- Spring Security OAuth2 Client -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-oauth2-client</artifactId>
</dependency>
<!-- Spring Security -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<!-- Thymeleaf模板引擎 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<!-- WebClient for HTTP requests -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-webflux</artifactId>
</dependency>
<!-- Lombok -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<excludes>
<exclude>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</exclude>
</excludes>
</configuration>
</plugin>
</plugins>
</build>
</project>
配置文件 application.yml
spring:
application:
name: oauth2-client-demo
security:
oauth2:
client:
registration:
github:
client-id: your-github-client-id
client-secret: your-github-client-secret
scope:
- read:user
- user:email
google:
client-id: your-google-client-id
client-secret: your-google-client-secret
scope:
- email
- profile
# 自定义OAuth2服务提供商
custom:
client-id: your-custom-client-id
client-secret: your-custom-client-secret
client-name: Custom OAuth2 Provider
authorization-grant-type: authorization_code
redirect-uri: "{baseUrl}/login/oauth2/code/{registrationId}"
scope:
- read
- write
provider:
github:
authorization-uri: https://github.com/login/oauth/authorize
token-uri: https://github.com/login/oauth/access_token
user-info-uri: https://api.github.com/user
user-name-attribute: id
google:
authorization-uri: https://accounts.google.com/o/oauth2/v2/auth
token-uri: https://oauth2.googleapis.com/token
user-info-uri: https://www.googleapis.com/oauth2/v3/userinfo
user-name-attribute: sub
custom:
authorization-uri: https://your-provider.com/oauth2/authorize
token-uri: https://your-provider.com/oauth2/token
user-info-uri: https://your-provider.com/api/userinfo
user-name-attribute: sub
server:
port: 8080
logging:
level:
org.springframework.security: DEBUG
主应用类
package com.example.oauth2client;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class OAuth2ClientApplication {
public static void main(String[] args) {
SpringApplication.run(OAuth2ClientApplication.class, args);
}
}
安全配置类
package com.example.oauth2client.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.oauth2.client.userinfo.DefaultOAuth2UserService;
import org.springframework.security.oauth2.client.userinfo.OAuth2UserRequest;
import org.springframework.security.oauth2.client.userinfo.OAuth2UserService;
import org.springframework.security.oauth2.core.user.OAuth2User;
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
import org.springframework.security.web.authentication.SavedRequestAwareAuthenticationSuccessHandler;
@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("/", "/login", "/oauth2/**", "/error").permitAll()
.anyRequest().authenticated()
.and()
.oauth2Login()
.loginPage("/login")
.defaultSuccessUrl("/home", true)
.successHandler(successHandler())
.userInfoEndpoint()
.userService(oAuth2UserService())
.and()
.failureUrl("/login?error=true")
.and()
.logout()
.logoutSuccessUrl("/")
.invalidateHttpSession(true)
.deleteCookies("JSESSIONID");
}
@Bean
public OAuth2UserService<OAuth2UserRequest, OAuth2User> oAuth2UserService() {
DefaultOAuth2UserService service = new DefaultOAuth2UserService();
service.setRequestEntityConverter(new CustomRequestEntityConverter());
return new CustomOAuth2UserService(service);
}
@Bean
public AuthenticationSuccessHandler successHandler() {
SavedRequestAwareAuthenticationSuccessHandler handler =
new SavedRequestAwareAuthenticationSuccessHandler();
handler.setDefaultTargetUrl("/home");
handler.setTargetUrlParameter("redirect");
handler.setAlwaysUseDefaultTargetUrl(false);
return handler;
}
}
自定义请求实体转换器
package com.example.oauth2client.config;
import org.springframework.core.convert.converter.Converter;
import org.springframework.http.RequestEntity;
import org.springframework.security.oauth2.client.endpoint.OAuth2AuthorizationCodeGrantRequest;
import org.springframework.security.oauth2.client.endpoint.OAuth2AuthorizationCodeGrantRequestEntityConverter;
public class CustomRequestEntityConverter
implements Converter<OAuth2AuthorizationCodeGrantRequest, RequestEntity<?>> {
private final OAuth2AuthorizationCodeGrantRequestEntityConverter
defaultConverter = new OAuth2AuthorizationCodeGrantRequestEntityConverter();
@Override
public RequestEntity<?> convert(OAuth2AuthorizationCodeGrantRequest request) {
RequestEntity<?> entity = defaultConverter.convert(request);
// 可以在这里添加自定义的Headers或修改请求参数
return entity;
}
}
自定义OAuth2用户服务
package com.example.oauth2client.config;
import lombok.extern.slf4j.Slf4j;
import org.springframework.security.oauth2.client.userinfo.DefaultOAuth2UserService;
import org.springframework.security.oauth2.client.userinfo.OAuth2UserRequest;
import org.springframework.security.oauth2.client.userinfo.OAuth2UserService;
import org.springframework.security.oauth2.core.OAuth2AuthenticationException;
import org.springframework.security.oauth2.core.user.OAuth2User;
import org.springframework.stereotype.Component;
import java.util.HashMap;
import java.util.Map;
@Slf4j
@Component
public class CustomOAuth2UserService implements OAuth2UserService<OAuth2UserRequest, OAuth2User> {
private final DefaultOAuth2UserService defaultOAuth2UserService;
public CustomOAuth2UserService() {
this.defaultOAuth2UserService = new DefaultOAuth2UserService();
}
public CustomOAuth2UserService(DefaultOAuth2UserService defaultOAuth2UserService) {
this.defaultOAuth2UserService = defaultOAuth2UserService;
}
@Override
public OAuth2User loadUser(OAuth2UserRequest userRequest) throws OAuth2AuthenticationException {
log.info("Loading user from provider: {}", userRequest.getClientRegistration().getRegistrationId());
OAuth2User oauth2User = defaultOAuth2UserService.loadUser(userRequest);
// 创建自定义User对象,可以在这里添加业务逻辑
Map<String, Object> attributes = new HashMap<>(oauth2User.getAttributes());
attributes.put("provider", userRequest.getClientRegistration().getRegistrationId());
return new CustomOAuth2User(
oauth2User.getAuthorities(),
attributes,
userRequest.getClientRegistration().getProviderDetails()
.getUserInfoEndpoint().getUserNameAttributeName()
);
}
}
自定义OAuth2用户类
package com.example.oauth2client.config;
import lombok.Getter;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.oauth2.core.user.DefaultOAuth2User;
import java.util.Collection;
import java.util.Map;
@Getter
public class CustomOAuth2User extends DefaultOAuth2User {
private final String provider;
public CustomOAuth2User(Collection<? extends GrantedAuthority> authorities,
Map<String, Object> attributes,
String nameAttributeKey) {
super(authorities, attributes, nameAttributeKey);
this.provider = (String) attributes.get("provider");
}
public String getEmail() {
return (String) this.getAttributes().get("email");
}
public String getNameAttribute() {
return this.getAttribute(this.getNameAttributeKey());
}
public String getPicture() {
return (String) this.getAttributes().get("picture");
}
public String getAvatarUrl() {
// 对GitHub支持
return (String) this.getAttributes().getOrDefault("avatar_url",
this.getAttributes().get("picture"));
}
}
控制器类
package com.example.oauth2client.controller;
import com.example.oauth2client.config.CustomOAuth2User;
import lombok.extern.slf4j.Slf4j;
import org.springframework.security.core.annotation.AuthenticationPrincipal;
import org.springframework.security.oauth2.core.user.OAuth2User;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import java.security.Principal;
import java.util.Map;
@Slf4j
@Controller
public class HomeController {
@GetMapping("/")
public String index(Principal principal) {
return principal != null ? "redirect:/home" : "index";
}
@GetMapping("/login")
public String login() {
return "login";
}
@GetMapping("/home")
public String home(@AuthenticationPrincipal OAuth2User oauth2User, Model model) {
model.addAttribute("name", oauth2User.getAttribute("name"));
model.addAttribute("email", oauth2User.getAttribute("email"));
model.addAttribute("avatar", getAvatar(oauth2User));
if (oauth2User instanceof CustomOAuth2User) {
CustomOAuth2User customUser = (CustomOAuth2User) oauth2User;
model.addAttribute("provider", customUser.getProvider());
}
return "home";
}
@GetMapping("/profile")
public String profile(@AuthenticationPrincipal OAuth2User oauth2User, Model model) {
Map<String, Object> attributes = oauth2User.getAttributes();
model.addAttribute("attributes", attributes);
model.addAttribute("authorities", oauth2User.getAuthorities());
return "profile";
}
@GetMapping("/user")
public String user(@AuthenticationPrincipal OAuth2User oauth2User, Model model) {
model.addAttribute("user", oauth2User);
return "user";
}
private String getAvatar(OAuth2User oauth2User) {
String avatarUrl = oauth2User.getAttribute("avatar_url");
if (avatarUrl == null) {
avatarUrl = oauth2User.getAttribute("picture");
}
return avatarUrl != null ? avatarUrl : "/images/default-avatar.png";
}
}
API客户端调用示例
package com.example.oauth2client.controller;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.*;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.oauth2.client.OAuth2AuthorizedClient;
import org.springframework.security.oauth2.client.OAuth2AuthorizedClientService;
import org.springframework.security.oauth2.client.authentication.OAuth2AuthenticationToken;
import org.springframework.security.oauth2.core.OAuth2AccessToken;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.client.RestTemplate;
import java.util.Map;
@Slf4j
@Controller
public class ApiController {
@Autowired
private OAuth2AuthorizedClientService authorizedClientService;
@Autowired
private RestTemplate restTemplate;
@GetMapping("/api/data")
public String getApiData(Model model) {
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
if (authentication instanceof OAuth2AuthenticationToken) {
OAuth2AuthenticationToken oauthToken = (OAuth2AuthenticationToken) authentication;
String clientRegistrationId = oauthToken.getAuthorizedClientRegistrationId();
OAuth2AuthorizedClient client = authorizedClientService.loadAuthorizedClient(
clientRegistrationId,
oauthToken.getName()
);
if (client != null) {
OAuth2AccessToken accessToken = client.getAccessToken();
model.addAttribute("accessToken", accessToken.getTokenValue());
// 使用access token调用第三方API
String apiUrl = "https://api.github.com/user/emails";
HttpHeaders headers = new HttpHeaders();
headers.setBearerAuth(accessToken.getTokenValue());
headers.setContentType(MediaType.APPLICATION_JSON);
HttpEntity<String> entity = new HttpEntity<>(headers);
try {
ResponseEntity<String> response = restTemplate.exchange(
apiUrl, HttpMethod.GET, entity, String.class);
model.addAttribute("apiResponse", response.getBody());
} catch (Exception e) {
log.error("Error calling API", e);
model.addAttribute("error", e.getMessage());
}
}
}
return "api-data";
}
}
HTML模板
login.html
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">Login</title>
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css" rel="stylesheet">
</head>
<body>
<div class="container mt-5">
<div class="row justify-content-center">
<div class="col-md-6">
<div class="card">
<div class="card-header">
<h3 class="text-center">Login</h3>
</div>
<div class="card-body">
<th:block th:if="${param.error}">
<div class="alert alert-danger">
Login failed. Please try again.
</div>
</th:block>
<div class="text-center">
<h4>Choose a provider:</h4>
<a th:href="@{/oauth2/authorization/github}"
class="btn btn-dark btn-lg btn-block mb-3">
Login with GitHub
</a>
<br>
<a th:href="@{/oauth2/authorization/google}"
class="btn btn-primary btn-lg btn-block">
Login with Google
</a>
</div>
</div>
</div>
</div>
</div>
</div>
</body>
</html>
home.html
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">Home</title>
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css" rel="stylesheet">
</head>
<body>
<nav class="navbar navbar-expand-lg navbar-dark bg-dark">
<div class="container">
<a class="navbar-brand" href="/">OAuth2 Client</a>
<div class="navbar-nav ms-auto">
<a class="nav-link" th:href="@{/profile}">Profile</a>
<a class="nav-link" th:href="@{/api/data}">API Data</a>
<form th:action="@{/logout}" method="post" class="d-inline">
<button type="submit" class="btn btn-outline-light">Logout</button>
</form>
</div>
</div>
</nav>
<div class="container mt-5">
<div class="row">
<div class="col-md-6 mx-auto">
<div class="card">
<div class="card-body text-center">
<img th:src="${avatar}" class="rounded-circle mb-3"
style="width: 100px; height: 100px;" alt="Avatar">
<h2 th:text="${name}">User Name</h2>
<p class="text-muted" th:text="${email}">email@example.com</p>
<p>
<span class="badge bg-success" th:text="${provider}">
Provider
</span>
</p>
<div class="mt-4">
<h5>User Information:</h5>
<ul class="list-group">
<li class="list-group-item" th:text="${name}">Name</li>
<li class="list-group-item" th:text="${email}">Email</li>
<li class="list-group-item">Provider: <span th:text="${provider}">Provider</span></li>
</ul>
</div>
</div>
</div>
</div>
</div>
</div>
</body>
</html>
配置文件 application.properties (备用)
# 应用配置
spring.application.name=oauth2-client-demo
server.port=8080
# GitHub OAuth2配置
spring.security.oauth2.client.registration.github.client-id=${GITHUB_CLIENT_ID}
spring.security.oauth2.client.registration.github.client-secret=${GITHUB_CLIENT_SECRET}
spring.security.oauth2.client.registration.github.scope=read:user,user:email
# Google OAuth2配置
spring.security.oauth2.client.registration.google.client-id=${GOOGLE_CLIENT_ID}
spring.security.oauth2.client.registration.google.client-secret=${GOOGLE_CLIENT_SECRET}
spring.security.oauth2.client.registration.google.scope=email,profile
# OAuth2 Provider配置
spring.security.oauth2.client.provider.github.authorization-uri=https://github.com/login/oauth/authorize
spring.security.oauth2.client.provider.github.token-uri=https://github.com/login/oauth/access_token
spring.security.oauth2.client.provider.github.user-info-uri=https://api.github.com/user
spring.security.oauth2.client.provider.github.user-name-attribute=id
运行说明
-
获取OAuth2客户端凭证:在GitHub、Google等平台上注册应用,获取Client ID和Client Secret。
-
配置环境变量:
export GITHUB_CLIENT_ID=your_client_id export GITHUB_CLIENT_SECRET=your_client_secret export GOOGLE_CLIENT_ID=your_client_id export GOOGLE_CLIENT_SECRET=your_client_secret
-
启动应用:
mvn spring-boot:run
-
访问应用:打开浏览器访问
http://localhost:8080
完整功能说明
- OAuth2登录:支持GitHub、Google等OAuth2提供商
- 用户信息获取:从提供商获取用户基本信息
- 自定义用户服务:扩展默认的用户服务,处理自定义业务逻辑
- API调用:使用访问令牌调用受保护的API
- 会话管理:管理OAuth2会话和令牌
- 多提供商支持:支持多个OAuth2提供商
这个案例提供了完整的OAuth2客户端实现,包括配置、安全设置、控制器、模板和API调用示例,可以根据实际需求进行扩展和定制。
版权声明:NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
篮球直播
篮球直播
篮球直播
篮球直播
篮球直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
中超直播
中超直播
中超直播
中超直播
中超直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
篮球直播
篮球直播
篮球直播
篮球直播
篮球直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
中超直播
中超直播
中超直播
中超直播
中超直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播