Spring Boot保留本地认证与OAuth2双认证方式的实现咨询
同时保留Spring Boot本地认证与OAuth2认证的解决方案
好问题!直接使用@EnableOAuth2Sso确实会默认接管整个登录流程,导致本地表单登录被覆盖。要同时保留两种认证方式,我们可以通过拆分安全配置、设置优先级的方式,让本地认证和OAuth2认证各自处理对应的路径,同时在自定义登录页面提供两种登录选项。
核心思路
- 拆分两个独立的安全配置类,分别对应本地认证和OAuth2认证,通过
@Order指定优先级(数值越小优先级越高)。 - 本地认证配置负责处理大部分业务路径的权限控制,以及本地表单登录流程。
- OAuth2配置仅处理OAuth2相关的跳转路径,并且指定跳转到我们的自定义登录页面,而非直接重定向到第三方平台。
- 在自定义登录页面添加本地表单和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
相关产品推荐
相关产品推荐

