SpringSecurity 增加全局认证问题。
在SpringBoot2.7.9和 SpringSecurity5.7.7情况下:以下配置可以生效没有问题
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecurityConfig {
@Resource
SpringSecurityAdminConfig springSecurityAdminConfig;
@Resource
private UserDetailsService userDetailsService;
@Resource
private DefaultPasswordEncoder defaultPasswordEncoder;
@Resource
private AuthenticationEntryPointIHandler authenticationEntryPointIHandler;
@Resource
private SpringSecurityMobileConfig springSecurityMobileConfig;
@Resource
private TokenLogoutHandler tokenLogoutHandler;
@Resource
private AccessDeniedImplHandler accessDeniedImplHandler;
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
http
//禁用它,因为前后端分离不需要
.csrf(AbstractHttpConfigurer::disable)
//禁用session
.sessionManagement(AbstractHttpConfigurer::disable)
//设置无需权限可访问的链接
.authorizeHttpRequests(auhtor -> auhtor
.antMatchers("/security/captcha", "/security/login", "/security/getaMobileCode",
"/api/ums/user/sendMobileCode/**", "/three/sendMobileCode",
"/api/ums/user/loginByMobile", "/ums/user/getByMobile/**",
//
// "**/doc.html", "/swagger/**", "/v2/api-docs", "/doc.html",
// "/webjars/**", "/druid/**", "/login", "/swagger/**", "/v2/api-docs", "/doc.html", "/swagger-resources/**",
// "/",
" /**/*.html",
"/**/*.css",
"/**/*.js",
"/**/api-docs/**"
).permitAll()
.anyRequest().authenticated()
);
// 设置退出路径
http.logout().logoutUrl("/security/logout")
//注销成功后,回到首页
.logoutSuccessUrl("/")
//设置退出处理方法
.addLogoutHandler(tokenLogoutHandler);
//添加用户名登录配置类
http.apply(springSecurityAdminConfig);
//注入新的AuthenticationManager 认证管理
http.authenticationManager(authenticationManager(http));
//添加手机登录配置类型
http.apply(springSecurityMobileConfig);
//认证异常处理器
http.exceptionHandling(ex -> {
ex.authenticationEntryPoint(authenticationEntryPointIHandler).accessDeniedHandler(accessDeniedImplHandler);
});
return http.build();
}
/**
* 构造一个AuthenticationManager,使用自定义的userDetailsService和passwordEncoder
*/
@Bean
AuthenticationManager authenticationManager(HttpSecurity http) throws Exception {
AuthenticationManager authenticationManager = http.getSharedObject(AuthenticationManagerBuilder.class)
//设置查询service
.userDetailsService(userDetailsService)
//设置密码处理
.passwordEncoder(defaultPasswordEncoder)
.and()
.build();
return authenticationManager;
}
}
将项目升级到SpringBoot3.0.2后,SpringSecurity6.0.1后。
红色区域报错,切无法访问。
报错内容为:直接调用使用 @Bean 注解的方法。请改用依赖项注入。
虽能正常启动。但前端访问直接报:6Cross-Origin Read Blocking (CORB) 已屏蔽 MIME 类型为 text/html 的跨域响应
此处该如何解决?
"直接调用使用 @Bean 注解的方法。请改用依赖项注入" 这个只是IDEA的代码检查提示,因为你这个方法已经有@Bean
注解了,所以可以直接通过依赖的方式注入而不是去调用这个方法。
以下回答参考GPT并且由Bony-整理:
根据报错信息来看,似乎是因为在 Spring Boot 3.x 以及 Spring Security 6.x 中,调用 authenticationManager()
方法时使用了 http.getSharedObject(AuthenticationManagerBuilder.class)
,而在 Spring Security 6.x 中,http.getSharedObject()
已经被废弃了,所以建议您改为使用 http.getSharedObject(AuthenticationManager.class)
。
另外,关于跨域问题,建议您检查一下是否已经添加了跨域配置。如果您是使用 Spring Security 中的 CorsFilter 来进行跨域配置的话,可以尝试将其移动到 FilterRegistrationBean 中进行配置,然后在 SecurityConfig
中通过 @Order(Ordered.HIGHEST_PRECEDENCE)
来设置其优先级,以确保跨域配置优先于 Spring Security 过滤器的执行。
举个例子,可以这样配置:
@Configuration
public class CorsConfig {
@Bean
public FilterRegistrationBean<CorsFilter> corsFilterRegistrationBean() {
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
CorsConfiguration corsConfiguration = new CorsConfiguration();
corsConfiguration.addAllowedOrigin("*");
corsConfiguration.addAllowedHeader("*");
corsConfiguration.addAllowedMethod("*");
source.registerCorsConfiguration("/**", corsConfiguration);
CorsFilter corsFilter = new CorsFilter(source);
FilterRegistrationBean<CorsFilter> registrationBean = new FilterRegistrationBean<>(corsFilter);
registrationBean.setOrder(Ordered.HIGHEST_PRECEDENCE);
return registrationBean;
}
}
希望以上信息对您有所帮助。
引用chatGPT作答,在 Spring Security 6.0 中,关于配置 SecurityFilterChain 已经有所变化。现在,您需要在 SecurityConfig 类中注入一个类型为 SecurityFilterChainFactory 的 bean,并使用它来创建 SecurityFilterChain。
另外,关于报错 "直接调用使用 @Bean 注解的方法。请改用依赖项注入",可能是因为 Spring Security 6.0 引入了一个新的特性,该特性禁止直接调用使用 @Bean 注解的方法,而应该使用构造函数注入或依赖项注入的方式。
以下是更新后的代码示例:
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecurityConfig {
@Resource
SpringSecurityAdminConfig springSecurityAdminConfig;
@Resource
private UserDetailsService userDetailsService;
@Resource
private DefaultPasswordEncoder defaultPasswordEncoder;
@Resource
private AuthenticationEntryPointIHandler authenticationEntryPointIHandler;
@Resource
private SpringSecurityMobileConfig springSecurityMobileConfig;
@Resource
private TokenLogoutHandler tokenLogoutHandler;
@Resource
private AccessDeniedImplHandler accessDeniedImplHandler;
@Resource
private SecurityFilterChainFactory securityFilterChainFactory;
@Bean
public SecurityFilterChain securityFilterChain() throws Exception {
return securityFilterChainFactory.createHttpSecurityFilterChain(HttpSecurity.http());
}
// 其他代码...
}
对于前端报错 "Cross-Origin Read Blocking (CORB) 已屏蔽 MIME 类型为 text/html 的跨域响应",这通常是因为后端返回的响应类型是 text/html,而不是应该是 application/json。您可以在前端代码中添加一些配置,以避免这个错误。例如,对于 Vue.js,您可以添加以下配置:
axios.defaults.headers.common['X-Requested-With'] = 'XMLHttpRequest';
axios.defaults.headers.common['Content-Type'] = 'application/json';
这应该可以解决前端报错的问题。
该回答引用ChatGPT
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
private SpringSecurityAdminConfig springSecurityAdminConfig;
@Autowired
private UserDetailsService userDetailsService;
@Autowired
private DefaultPasswordEncoder defaultPasswordEncoder;
@Autowired
private AuthenticationEntryPointIHandler authenticationEntryPointIHandler;
@Autowired
private SpringSecurityMobileConfig springSecurityMobileConfig;
@Autowired
private TokenLogoutHandler tokenLogoutHandler;
@Autowired
private AccessDeniedImplHandler accessDeniedImplHandler;
@Override
protected void configure(HttpSecurity http) throws Exception {
http
//禁用它,因为前后端分离不需要
.csrf(AbstractHttpConfigurer::disable)
//禁用session
.sessionManagement(AbstractHttpConfigurer::disable)
//设置无需权限可访问的链接
.authorizeHttpRequests(auhtor -> auhtor
.antMatchers("/security/captcha", "/security/login", "/security/getaMobileCode",
"/api/ums/user/sendMobileCode/**", "/three/sendMobileCode",
"/api/ums/user/loginByMobile", "/ums/user/getByMobile/**",
//
// "/**/doc.html", "/swagger/**", "/v2/api-docs", "/doc.html",
// "/webjars/**", "/druid/**", "/login", "/swagger/**", "/v2/api-docs", "/doc.html", "/swagger-resources/**",
// "/",
" /**/*.html",
"/**/*.css",
"/**/*.js",
"/**/api-docs/**"
).permitAll()
.anyRequest().authenticated()
);
// 设置退出路径
http.logout().logoutUrl("/security/logout")
//注销成功后,回到首页
.logoutSuccessUrl("/")
//设置退出处理方法
.addLogoutHandler(tokenLogoutHandler);
//添加用户名登录配置类
http.apply(springSecurityAdminConfig);
//注入新的AuthenticationManager 认证管理
http.authenticationManager(authenticationManager());
//添加手机登录配置类型
http.apply(springSecurityMobileConfig);
//认证异常处理器
http.exceptionHandling(ex -> {
ex.authenticationEntryPoint(authenticationEntryPointIHandler).accessDeniedHandler(accessDeniedImplHandler);
});
}
/**
* 构造一个AuthenticationManager,使用自定义的userDetailsService和passwordEncoder
*/
@Bean
@Override
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
@Override
protected UserDetailsService userDetailsService() {
return userDetailsService;
}
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userDetailsService)
.passwordEncoder(defaultPasswordEncoder);
}
}
http.cors().configurationSource(request -> {
CorsConfiguration config = new CorsConfiguration();
config.setAllowedOrigins(Arrays.asList("*"));
config.setAllowedMethods(Arrays.asList("GET", "POST", "OPTIONS"));
return config;
});