自己实现一个 OAuth2 授权服务器(充当 Gitee 的角色),以下是 Spring Boot 服务端的核心配置。
下面是一个最小可运行的核心示例,省略掉界面和数据库部分,只演示服务端的基本配置。
官方推荐用 Spring Authorization Server 来搭建 OAuth2 授权中心。
1. 引入依赖(pom.xml)
<dependencies>
<!-- Spring Web -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- Spring Security -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<!-- Spring Authorization Server -->
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-oauth2-authorization-server</artifactId>
<version>1.3.1</version> <!-- 对应 Spring Boot 3.x -->
</dependency>
</dependencies>
2. 安全配置(Authorization Server)
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.oauth2.server.authorization.config.annotation.web.configuration.OAuth2AuthorizationServerConfiguration;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.authentication.LoginUrlAuthenticationEntryPoint;
@Configuration
public class AuthorizationServerConfig {
@Bean
public SecurityFilterChain authorizationServerSecurityFilterChain(HttpSecurity http) throws Exception {
// 应用 Spring Authorization Server 的默认配置
OAuth2AuthorizationServerConfiguration.applyDefaultSecurity(http);
// 未登录时跳转到登录页
http.exceptionHandling(e -> e
.authenticationEntryPoint(new LoginUrlAuthenticationEntryPoint("/login"))
);
return http.build();
}
}
3. 客户端注册(相当于 Gitee 的应用配置)
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.crypto.factory.PasswordEncoderFactories;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.oauth2.core.AuthorizationGrantType;
import org.springframework.security.oauth2.core.ClientAuthenticationMethod;
import org.springframework.security.oauth2.server.authorization.client.RegisteredClient;
import org.springframework.security.oauth2.server.authorization.client.RegisteredClientRepository;
import org.springframework.security.oauth2.server.authorization.client.InMemoryRegisteredClientRepository;
import java.util.UUID;
@Configuration
public class ClientConfig {
@Bean
public RegisteredClientRepository registeredClientRepository() {
PasswordEncoder encoder = PasswordEncoderFactories.createDelegatingPasswordEncoder();
RegisteredClient client = RegisteredClient.withId(UUID.randomUUID().toString())
.clientId("demo-client") // 模拟 gitee 给出的 client-id
.clientSecret(encoder.encode("demo-secret")) // 模拟 gitee 给出的 client-secret
.clientAuthenticationMethod(ClientAuthenticationMethod.CLIENT_SECRET_POST)
.authorizationGrantType(AuthorizationGrantType.AUTHORIZATION_CODE)
.authorizationGrantType(AuthorizationGrantType.REFRESH_TOKEN)
.redirectUri("http://localhost:8080/login/oauth2/code/gitee") // 回调地址
.scope("user_info")
.build();
return new InMemoryRegisteredClientRepository(client);
}
}
4. 用户认证(模拟 Gitee 登录)
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.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.provisioning.InMemoryUserDetailsManager;
import org.springframework.security.web.SecurityFilterChain;
@Configuration
public class DefaultSecurityConfig {
@Bean
public UserDetailsService userDetailsService() {
UserDetails user = User.withUsername("testuser")
.password("{noop}123456") // {noop} 表示明文密码
.roles("USER")
.build();
return new InMemoryUserDetailsManager(user);
}
@Bean
public SecurityFilterChain defaultSecurityFilterChain(HttpSecurity http) throws Exception {
http
.authorizeHttpRequests(auth -> auth.anyRequest().authenticated())
.formLogin();
return http.build();
}
}
5. 服务端加一个 /userinfo 接口
import org.springframework.security.core.annotation.AuthenticationPrincipal;
import org.springframework.security.oauth2.jwt.Jwt;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.Map;
@RestController
public class UserInfoController {
@GetMapping("/userinfo")
public Map<String, Object> userInfo(@AuthenticationPrincipal Jwt jwt) {
return Map.of(
"sub", jwt.getSubject(),
"username", jwt.getClaimAsString("sub"),
"email", jwt.getClaimAsString("email"),
"scope", jwt.getClaimAsString("scope")
);
}
}
6. 暴露 OAuth2 元信息(发现文档)
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.oauth2.server.authorization.settings.AuthorizationServerSettings;
@Configuration
public class ServerSettingsConfig {
@Bean
public AuthorizationServerSettings authorizationServerSettings() {
return AuthorizationServerSettings.builder()
.issuer("http://localhost:9000") // 服务端地址
.build();
}
}
7. 启动后可用的端点
启动后,Spring Authorization Server 会自动暴露标准 OAuth2 端点,比如:
- 授权端点:
http://localhost:9000/oauth2/authorize
- 令牌端点:
http://localhost:9000/oauth2/token
- JWK 公钥端点:
http://localhost:9000/oauth2/jwks
- OIDC 配置:
http://localhost:9000/.well-known/openid-configuration
客户端(比如上篇文章的 gitee 客户端配置)就可以指向这些地址,完成整个闭环。
这个服务端就相当于自己搭建了一个“迷你版 Gitee”,可以作为 OAuth2 授权中心 使用。