OAuth 2 最小可运行的完整 Demo,实现:
/userinfo
接口/authorize
、/token
、/userinfo
pom.xml
<dependencies>
<!-- Web & Security -->
<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>
<!-- Spring Authorization Server -->
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-oauth2-authorization-server</artifactId>
<version>1.3.1</version>
</dependency>
</dependencies>
@Configuration
public class AuthorizationServerConfig {
@Bean
public SecurityFilterChain authServerSecurityFilterChain(HttpSecurity http) throws Exception {
OAuth2AuthorizationServerConfiguration.applyDefaultSecurity(http);
http.exceptionHandling(e -> e.authenticationEntryPoint(new LoginUrlAuthenticationEntryPoint("/login")));
return http.build();
}
@Bean
public SecurityFilterChain defaultSecurityFilterChain(HttpSecurity http) throws Exception {
http.authorizeHttpRequests(auth -> auth.anyRequest().authenticated())
.formLogin();
return http.build();
}
@Bean
public RegisteredClientRepository registeredClientRepository() {
PasswordEncoder encoder = PasswordEncoderFactories.createDelegatingPasswordEncoder();
RegisteredClient client = RegisteredClient.withId(UUID.randomUUID().toString())
.clientId("demo-client")
.clientSecret(encoder.encode("demo-secret"))
.authorizationGrantType(AuthorizationGrantType.AUTHORIZATION_CODE)
.authorizationGrantType(AuthorizationGrantType.REFRESH_TOKEN)
.clientAuthenticationMethod(ClientAuthenticationMethod.CLIENT_SECRET_POST)
.redirectUri("http://localhost:8080/login/oauth2/code/gitee")
.scope("user_info")
.build();
return new InMemoryRegisteredClientRepository(client);
}
@Bean
public UserDetailsService userDetailsService() {
UserDetails user = User.withUsername("testuser")
.password("{noop}123456")
.roles("USER")
.build();
return new InMemoryUserDetailsManager(user);
}
@Bean
public AuthorizationServerSettings authServerSettings() {
return AuthorizationServerSettings.builder()
.issuer("http://localhost:9000")
.build();
}
}
/userinfo
接口@RestController
public class UserInfoController {
@GetMapping("/userinfo")
public Map<String, Object> userInfo(@AuthenticationPrincipal Jwt jwt) {
return Map.of(
"sub", jwt.getSubject(),
"username", jwt.getClaimAsString("sub"),
"scope", jwt.getClaimAsString("scope")
);
}
}
启动服务端,端口 9000
。
pom.xml
<dependencies>
<!-- Web & Security -->
<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>
<!-- Thymeleaf (可选,用于自定义登录页) -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
</dependencies>
application.yml
server:
port: 8080
spring:
security:
oauth2:
client:
registration:
gitee: # 这里的名字随便,但要和 redirectUri 的 {registrationId} 一致
client-id: demo-client
client-secret: demo-secret
client-authentication-method: client_secret_post
authorization-grant-type: authorization_code
redirect-uri: "{baseUrl}/login/oauth2/code/{registrationId}"
scope: user_info
provider:
gitee:
authorization-uri: http://localhost:9000/oauth2/authorize
token-uri: http://localhost:9000/oauth2/token
user-info-uri: http://localhost:9000/userinfo
user-name-attribute: username
@Configuration
public class SecurityConfig {
@Bean
public SecurityFilterChain clientSecurityFilterChain(HttpSecurity http) throws Exception {
http.authorizeHttpRequests(auth -> auth
.requestMatchers("/", "/login").permitAll()
.anyRequest().authenticated()
)
.oauth2Login(oauth2 -> oauth2.loginPage("/login"));
return http.build();
}
}
@Controller
public class HomeController {
@GetMapping("/")
@ResponseBody
public String home(@AuthenticationPrincipal OAuth2User user) {
if (user != null) {
return "Hello, " + user.getAttribute("username") +
" (scope=" + user.getAttribute("scope") + ")";
}
return "未登录,<a href='/oauth2/authorization/gitee'>点此登录</a>";
}
@GetMapping("/login")
public String login() {
return "login"; // 自定义页面,也可以省略直接用默认登录
}
}
启动 服务端 (端口 9000)
/oauth2/authorize
、令牌端点 /oauth2/token
、用户信息端点 /userinfo
testuser/123456
启动 客户端 (端口 8080)
http://localhost:8080/
→ 点击登录/login
登录页/userinfo
拿到 profile页面显示:
Hello, testuser (scope=user_info)
这样就是一个 完整的 OAuth2 授权中心 + 客户端闭环,逻辑和 Gitee 几乎一致。