This commit is contained in:
孙小云 2025-07-19 17:15:03 +08:00
parent 09bfe63b27
commit a856062a90
3 changed files with 125 additions and 14 deletions

View File

@ -5,11 +5,15 @@ import com.nimbusds.jose.jwk.RSAKey;
import com.nimbusds.jose.jwk.source.ImmutableJWKSet; import com.nimbusds.jose.jwk.source.ImmutableJWKSet;
import com.nimbusds.jose.jwk.source.JWKSource; import com.nimbusds.jose.jwk.source.JWKSource;
import com.nimbusds.jose.proc.SecurityContext; import com.nimbusds.jose.proc.SecurityContext;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Lazy;
import org.springframework.core.annotation.Order; import org.springframework.core.annotation.Order;
import org.springframework.security.authentication.AuthenticationProvider;
import org.springframework.security.config.Customizer; import org.springframework.security.config.Customizer;
import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.core.userdetails.User; import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails; import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService; import org.springframework.security.core.userdetails.UserDetailsService;
@ -49,6 +53,9 @@ import java.util.UUID;
@Configuration @Configuration
public class SecurityConfig { public class SecurityConfig {
@Autowired
@Lazy
AuthenticationProvider tenantAwareAuthenticationProvider;
// 自定义认证入口点保留client_id参数 // 自定义认证入口点保留client_id参数
public static class CustomLoginUrlAuthenticationEntryPoint extends LoginUrlAuthenticationEntryPoint { public static class CustomLoginUrlAuthenticationEntryPoint extends LoginUrlAuthenticationEntryPoint {
public CustomLoginUrlAuthenticationEntryPoint(String loginFormUrl) { public CustomLoginUrlAuthenticationEntryPoint(String loginFormUrl) {
@ -89,6 +96,7 @@ public class SecurityConfig {
@Bean @Bean
@Order(2) @Order(2)
public SecurityFilterChain defaultSecurityFilterChain(HttpSecurity http) throws Exception { public SecurityFilterChain defaultSecurityFilterChain(HttpSecurity http) throws Exception {
http http
.authorizeHttpRequests(authorize -> .authorizeHttpRequests(authorize ->
authorize authorize
@ -115,22 +123,28 @@ public class SecurityConfig {
.invalidateHttpSession(true) .invalidateHttpSession(true)
.deleteCookies("JSESSIONID") .deleteCookies("JSESSIONID")
.permitAll() .permitAll()
); )
// 添加会话管理配置
// .sessionManagement(session -> session
// .sessionCreationPolicy(SessionCreationPolicy.ALWAYS)
// .maximumSessions(1) // 限制每个用户只能有一个会话
// )
// 添加自定义认证提供者
.authenticationProvider(tenantAwareAuthenticationProvider);
return http.build(); return http.build();
} }
//
// 用户信息服务内存存储 // // 用户信息服务内存存储
@Bean // @Bean
public UserDetailsService userDetailsService(PasswordEncoder passwordEncoder) { // public UserDetailsService userDetailsService(PasswordEncoder passwordEncoder) {
UserDetails user = User.builder() // UserDetails user = User.builder()
.username("user") // .username("user")
.password(passwordEncoder.encode("password")) // .password(passwordEncoder.encode("password"))
.roles("USER") // .roles("USER")
.build(); // .build();
//
return new InMemoryUserDetailsManager(user); // return new InMemoryUserDetailsManager(user);
} // }
// 注册客户端内存存储 // 注册客户端内存存储
@Bean @Bean

View File

@ -0,0 +1,62 @@
package com.tuoheng.oauth.oidc.provider;
import com.tuoheng.oauth.oidc.service.CustomUserDetailsService;
import jakarta.servlet.http.HttpServletRequest;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.AuthenticationProvider;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
@Component
public class TenantAwareAuthenticationProvider implements AuthenticationProvider {
@Autowired
private CustomUserDetailsService userDetailsService;
@Autowired
private PasswordEncoder passwordEncoder;
@Override
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
String username = authentication.getName();
String password = authentication.getCredentials().toString();
// 获取请求中的额外参数
HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder
.currentRequestAttributes()).getRequest();
String clientId = request.getParameter("client_id");
String tenantCode = request.getParameter("tenant-code");
System.out.println("=== 认证信息 ===");
System.out.println("用户名: " + username);
System.out.println("客户端ID: " + clientId);
System.out.println("租户代码: " + tenantCode);
// 执行标准的用户认证
UserDetails userDetails = userDetailsService.loadUserByUsername(username);
if (userDetails != null && passwordEncoder.matches(password, userDetails.getPassword())) {
System.out.println("用户认证成功");
return new UsernamePasswordAuthenticationToken(
userDetails, password, userDetails.getAuthorities());
}
System.out.println("用户认证失败");
throw new BadCredentialsException("Invalid username or password");
}
@Override
public boolean supports(Class<?> authentication) {
return UsernamePasswordAuthenticationToken.class.isAssignableFrom(authentication);
}
}

View File

@ -0,0 +1,35 @@
package com.tuoheng.oauth.oidc.service;
import org.springframework.beans.factory.annotation.Autowired;
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.core.userdetails.UsernameNotFoundException;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import java.util.HashSet;
@Service
public class CustomUserDetailsService implements UserDetailsService {
@Autowired
private PasswordEncoder passwordEncoder;
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
// 创建UserDetails对象
return org.springframework.security.core.userdetails.User.builder()
.username("user")
.password(passwordEncoder.encode("password"))
.authorities(new HashSet<>())
.accountExpired(false)
.accountLocked(false)
.credentialsExpired(false)
.disabled(false)
.build();
}
}