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

Spring Boot保留本地认证与OAuth2双认证方式的实现咨询

同时保留Spring Boot本地认证与OAuth2认证的解决方案

好问题!直接使用@EnableOAuth2Sso确实会默认接管整个登录流程,导致本地表单登录被覆盖。要同时保留两种认证方式,我们可以通过拆分安全配置、设置优先级的方式,让本地认证和OAuth2认证各自处理对应的路径,同时在自定义登录页面提供两种登录选项。

核心思路

  1. 拆分两个独立的安全配置类,分别对应本地认证和OAuth2认证,通过@Order指定优先级(数值越小优先级越高)。
  2. 本地认证配置负责处理大部分业务路径的权限控制,以及本地表单登录流程。
  3. OAuth2配置仅处理OAuth2相关的跳转路径,并且指定跳转到我们的自定义登录页面,而非直接重定向到第三方平台。
  4. 在自定义登录页面添加本地表单和OAuth2登录的入口选项。

方案一:基于WebSecurityConfigurerAdapter(适用于旧版本Spring Security)

1. 本地认证配置类

保留原有本地认证逻辑,调整@Order为更高优先级,并明确权限规则:

@Configuration
@Order(1)
public class LocalSecurityConfig extends WebSecurityConfigurerAdapter {
    @Autowired
    private DataSource dataSource;

    @Bean
    public static BCryptPasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }

    @Autowired
    public void configureAuthentication(AuthenticationManagerBuilder auth) throws Exception {
        auth.jdbcAuthentication()
                .dataSource(dataSource)
                .passwordEncoder(passwordEncoder());
    }

    @Override
    public void configure(WebSecurity web) throws Exception {
        web.ignoring().antMatchers("/resources/**");
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
                .authorizeRequests()
                .antMatchers("/", "/login").permitAll()
                .antMatchers("/welcome").hasAnyRole("USER", "ADMIN")
                .antMatchers("/getEmployees").hasAnyRole("USER", "ADMIN")
                .antMatchers("/addNewEmployee").hasAnyRole("ADMIN")
                .anyRequest().authenticated()
                .and()
                .formLogin()
                .loginPage("/login") // 自定义登录页面
                .defaultSuccessUrl("/welcome")
                .permitAll()
                .and()
                .logout()
                .permitAll()
                .and()
                .httpBasic()
                .and()
                .csrf().disable();
    }
}

2. OAuth2认证配置类

新建专门处理OAuth2流程的配置,优先级低于本地认证:

@Configuration
@Order(2)
public class OAuth2SecurityConfig extends WebSecurityConfigurerAdapter {

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
                .antMatcher("/oauth2/**") // 仅处理OAuth2相关路径
                .authorizeRequests()
                .anyRequest().authenticated()
                .and()
                .oauth2Login() // 启用OAuth2登录
                .loginPage("/login") // 跳转到自定义登录页面
                .defaultSuccessUrl("/welcome"); // 登录成功后的跳转页
    }
}

3. 配置OAuth2客户端信息(application.properties)

替换为你的Facebook应用凭证:

spring.security.oauth2.client.registration.facebook.client-id=你的Facebook App ID
spring.security.oauth2.client.registration.facebook.client-secret=你的Facebook App Secret
spring.security.oauth2.client.registration.facebook.scope=email,public_profile
spring.security.oauth2.client.provider.facebook.authorization-uri=https://www.facebook.com/v18.0/dialog/oauth
spring.security.oauth2.client.provider.facebook.token-uri=https://graph.facebook.com/v18.0/oauth/access_token
spring.security.oauth2.client.provider.facebook.user-info-uri=https://graph.facebook.com/v18.0/me?fields=id,name,email
spring.security.oauth2.client.provider.facebook.user-name-attribute=name

4. 自定义登录页面(login.html)

添加本地表单和Facebook登录选项:

<!DOCTYPE html>
<html>
<head>
    <title>系统登录</title>
</head>
<body>
    <h2>账号登录</h2>
    <!-- 本地登录表单 -->
    <form action="/login" method="post">
        <div>
            <label>用户名: </label>
            <input type="text" name="username"/>
        </div>
        <div>
            <label>密码: </label>
            <input type="password" name="password"/>
        </div>
        <div>
            <input type="submit" value="登录"/>
        </div>
    </form>

    <!-- OAuth2登录入口 -->
    <hr>
    <p>或者使用第三方账号登录:</p>
    <a href="/oauth2/authorization/facebook">使用Facebook登录</a>
</body>
</html>

方案二:基于SecurityFilterChain(推荐,适用于Spring Security 5.7+)

由于WebSecurityConfigurerAdapter已被废弃,推荐使用最新的SecurityFilterChain配置方式:

@Configuration
public class SecurityConfig {

    @Autowired
    private DataSource dataSource;

    @Bean
    public BCryptPasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }

    // 本地认证过滤器链(优先级更高)
    @Bean
    @Order(1)
    public SecurityFilterChain localSecurityFilterChain(HttpSecurity http) throws Exception {
        http
                .securityMatcher("/**")
                .authorizeRequests(auth -> auth
                        .antMatchers("/", "/login").permitAll()
                        .antMatchers("/welcome").hasAnyRole("USER", "ADMIN")
                        .antMatchers("/getEmployees").hasAnyRole("USER", "ADMIN")
                        .antMatchers("/addNewEmployee").hasAnyRole("ADMIN")
                        .anyRequest().authenticated()
                )
                .formLogin(form -> form
                        .loginPage("/login")
                        .defaultSuccessUrl("/welcome")
                        .permitAll()
                )
                .logout(logout -> logout.permitAll())
                .httpBasic()
                .and()
                .csrf().disable();

        return http.build();
    }

    // OAuth2认证过滤器链
    @Bean
    @Order(2)
    public SecurityFilterChain oauth2SecurityFilterChain(HttpSecurity http) throws Exception {
        http
                .securityMatcher("/oauth2/**")
                .authorizeRequests(auth -> auth.anyRequest().authenticated())
                .oauth2Login(oauth2 -> oauth2
                        .loginPage("/login")
                        .defaultSuccessUrl("/welcome")
                );

        return http.build();
    }

    @Bean
    public AuthenticationManager authenticationManager(AuthenticationConfiguration authConfig) throws Exception {
        return authConfig.getAuthenticationManager();
    }

    @Bean
    public UserDetailsService userDetailsService() {
        return new JdbcUserDetailsManager(dataSource);
    }
}

关键说明

  • 优先级控制:@Order(1)的本地配置会先处理请求,确保本地登录和业务权限规则优先生效;OAuth2配置仅处理/oauth2/**路径的跳转。
  • 用户关联(可选):如果需要将OAuth2用户与本地数据库用户关联,可以实现OAuth2UserService接口,在用户通过OAuth2登录时完成注册或关联逻辑。
  • 兼容性:上述配置同时支持本地表单登录、HTTP Basic认证和Facebook OAuth2认证,原有业务接口的权限规则不受影响。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.12 04:41:11