You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

基于Spring Security的OAuth2.0授权服务器自定义登录实现问询

Spring Security OAuth2授权服务器自定义登录流程集成问题

当前使用的依赖

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-security</artifactId>
</dependency>

<dependency>
    <groupId>org.springframework.security</groupId>
    <artifactId>spring-security-oauth2-authorization-server</artifactId>
    <version>0.3.0</version>
</dependency>

现有正常运行的授权码(带PKCE)流程

  • 客户端调用授权服务器的授权端点,示例请求:
https://authorization-server.com/authorize?response_type=code&client_id=zMP_79LS2UPtyFa1z0TrdwoN&redirect_uri=https://www.oauth.com/playground/authorization-code-with-pkce.html&scope=photo+offline_access&state=0OaV1kmkkK8yFbqe&code_challenge=WVe6cGEQGlHk3hXXpyUo4hvs2uzCg4j3-oXfnX9L6HA&code_challenge_method=S256
  • 授权服务器渲染登录表单完成用户认证
  • 授权服务器向客户端的redirect_uri返回授权码
  • 客户端调用令牌端点,携带授权码,示例请求:
https://authorization-server.com/token?grant_type=authorization_code&client_id=zMP_79LS2UPtyFa1z0TrdwoN&client_secret=VvfjKzAWIr0bxWKTUvzC48NkzlhwnAuSOsWOb6C8AdG7GH5O&redirect_uri=https://www.oauth.com/playground/authorization-code-with-pkce.html&code=z9dJErNexuAL0VRaOu9AfxhMuOJL-IT7zY5HILeKFW5XmFOT&code_verifier=Q3TsNTc5__76nzRtp43zjVJ3yxD_P1WD-khqJ7rdTxS_l73w
  • 授权服务器返回Access Token

需求修改

希望将登录表单改为由React前端渲染,流程调整为:

  1. 客户端渲染登录表单
  2. 客户端通过RESTful接口/auth/login将用户名/密码发送至后端

需要实现:

  1. 通过自定义Authentication Provider完成用户认证
  2. 将已认证用户注入OAuth2框架,让授权服务器无需渲染登录表单即可直接向redirect_uri发送授权码

已尝试的代码实现

1. 自定义认证相关实现

WebSecurity配置类

@Configuration
@EnableWebSecurity
@RequiredArgsConstructor
public class WebSecurityConfig {
    private final CustomAuthenticationProvider customAuthenticationProvider;


    @Bean
    public AuthenticationManager authenticationManager(HttpSecurity http) throws Exception {
        AuthenticationManagerBuilder builder = http.getSharedObject(AuthenticationManagerBuilder.class);
        builder.userDetailsService(customUserDetailService);
        builder.authenticationProvider(customAuthenticationProvider);

        return builder.build();
    }
}

自定义AuthenticationProvider

@Service
@RequiredArgsConstructor
public class CustomAuthenticationProvider implements AuthenticationProvider {
    private final CustomUserDetailService customUserDetailService;
    private final PasswordEncoder passwordEncoder;

    @Override
    public Authentication authenticate(Authentication authentication) throws AuthenticationException {
        String username = authentication.getName();
        String password = authentication.getCredentials().toString();

        E2AuthUserDetails user = (E2AuthUserDetails) customUserDetailService.loadUserByUsername(username);

        return checkPassword(user, password);
    }

    private Authentication checkPassword(UserDetails user, String rawLoginPassword) {
        String dbPassword = user.getPassword();
        if (passwordEncoder.matches(rawLoginPassword, dbPassword)) {
            return new UsernamePasswordAuthenticationToken(user.getUsername(),
                    dbPassword,
                    user.getAuthorities());
        } else {
            throw new BadCredentialsException("Bad Credentials");
        }
    }

    @Override
    public boolean supports(Class<?> authentication) {
        return UsernamePasswordAuthenticationToken.class.isAssignableFrom(authentication);
    }
}

认证服务类

@Service
@RequiredArgsConstructor
public class AuthService {
    private final AuthenticationManager authenticationManager;

    public LoginResponse attemptLogin(String email, String password) {
        var authentication = authenticationManager.authenticate(
                new UsernamePasswordAuthenticationToken(email, password)
        );
        SecurityContextHolder.getContext().setAuthentication(authentication);
    }
}

2. 授权服务器配置

@Configuration(proxyBeanMethods = false)
public class AuthorizationServerConfig {

    @Autowired
    private CustomUserDetailsService customUserDetailsService;

    @Autowired
    private PasswordEncoder passwordEncoder;

    // 添加自定义安全过滤器并设置为链中第一个
    @Bean
    @Order(Ordered.HIGHEST_PRECEDENCE)
    public SecurityFilterChain authServerSecurityFilterChain(HttpSecurity http) throws Exception {
        OAuth2AuthorizationServerConfiguration.applyDefaultSecurity(http);

        return http.formLogin(Customizer.withDefaults()).build();
    }

    // 自定义客户端注册
    @Bean
    public RegisteredClientRepository registeredClientRepository() {
        RegisteredClient registeredClient = RegisteredClient.withId(UUID.randomUUID().toString())
                .clientId("client")
                .clientSecret(passwordEncoder.encode("secret"))
                .clientAuthenticationMethod(ClientAuthenticationMethod.CLIENT_SECRET_BASIC)
                .clientAuthenticationMethod(ClientAuthenticationMethod.BASIC)
                .authorizationGrantType(AuthorizationGrantType.AUTHORIZATION_CODE)
                .redirectUri("http://spring.io/auth")
                .scope(OidcScopes.OPENID)
                .build();


        return new InMemoryRegisteredClientRepository(registeredClient);
    }

    // 配置OAuth端点及其他默认设置
    @Bean
    public ProviderSettings providerSettings() {
        return ProviderSettings.builder()
                //.issuer("http://auth-server:9000")
                .build();
    }
}

内容的提问来源于stack exchange,提问作者stackoverflowenjoyer

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.05 06:25:22