版权声明:本文为CSDN博主「滔涛江水」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/taotaojs/article/details/84955218
网上有一些关于这个问题的答案,但都不是基于SpringBoot的,一想到SpringBoot还要配置XML文件就头大呀有木有。
以下就是解决方法:
在SecurityConfig中添加如下代码
@Bean
public UserDetailsService myUserService(){
return new MyUserDetailsService();
}
并且在configure(AuthenticationManagerBuilder auth)方法中将new MyUserService()改为以上的方法名
@Override
public void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(myUserService());
}
至此,自定义DetailsService中的Service就可以注入成功了。
另外,自定义DetailsService的@Service标注不需要也没关系,因为已经有@Bean标注了
说一下线索:
Spring Security在Spring加载完Bean之前就加载了(Spring框架中的Web.xml配置相关)
MyUserDetailsService继承AbstractJUnit4SpringContextTests之后输出applicationContext,发现applicationContext为空,说明Spring没有加载完成
Spring没有扫描到MyUserDetailsService,否则@Service肯定能达到与@Bean同样的效果
这个问题是相当冷门的,所以肯定有一个约定俗成的办法,于是搜一下Spring Security详细搭建就可以找到问题所在了
完整代码,就是SpringSecurity配置类
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter{
protected void configure(HttpSecurity http) throws Exception {
http
// 过滤请求
.authorizeRequests()
// 配置permitAll的不进行访问控制!这里的话是直接配置的是访问首页和访问用户信息,用户分类,首页轮播图进行跳过
.antMatchers("/image/**", "/index/**", "/goods-info/**", "/goods-category/**", "/carousel/**").permitAll()
.antMatchers("/admin/**").hasAnyRole("ADMIN") // 访问用户的角色必须要有ROLE_ADMIN角色才能进行访问
.antMatchers("/article/**").hasRole("USER")
.anyRequest().authenticated()
.and()
.csrf().disable()
.formLogin().disable()
.sessionManagement().disable()
.cors()
.and()
.headers().addHeaderWriter(new StaticHeadersWriter(Arrays.asList(
new Header("Access-control-Allow-Origin","*"),
new Header("Access-Control-Expose-Headers","Authorization"))))
.and()
// 过滤Options请求
.addFilterAfter(new OptionsRequestFilter(), CorsFilter.class)
.apply(new JsonLoginConfigurer<>()).loginSuccessHandler(jsonLoginSuccessHandler())
.and()
.apply(new JwtLoginConfigurer<>()).tokenValidSuccessHandler(jwtRefreshSuccessHandler()).permissiveRequestUrls("/logout")
.and()
.logout()
// .logoutUrl("/logout") //默认就是"/logout"
.addLogoutHandler(tokenClearLogoutHandler())
.logoutSuccessHandler(new HttpStatusReturningLogoutSuccessHandler())
.and()
.sessionManagement().disable();
}
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userDetailsService());
auth.authenticationProvider(daoAuthenticationProvider()).authenticationProvider(jwtAuthenticationProvider());
}
@Bean
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
@Bean("jwtUserService")
protected JwtUserService jwtUserService() {
return new JwtUserService();
}
@Bean("jwtAuthenticationProvider")
protected AuthenticationProvider jwtAuthenticationProvider() {
return new JwtAuthenticationProvider(jwtUserService());
}
@Bean("daoAuthenticationProvider")
protected AuthenticationProvider daoAuthenticationProvider() throws Exception{
//这里会默认使用BCryptPasswordEncoder比对加密后的密码,注意要跟createUser时保持一致
DaoAuthenticationProvider daoProvider = new DaoAuthenticationProvider();
daoProvider.setUserDetailsService(userDetailsService());
return daoProvider;
}
@Override
@Bean
protected UserDetailsService userDetailsService() {
return new JwtUserService();
}
@Bean
protected JsonLoginSuccessHandler jsonLoginSuccessHandler() {
return new JsonLoginSuccessHandler(jwtUserService());
}
@Bean
protected JwtRefreshSuccessHandler jwtRefreshSuccessHandler() {
return new JwtRefreshSuccessHandler(jwtUserService());
}
@Bean
protected TokenClearLogoutHandler tokenClearLogoutHandler() {
return new TokenClearLogoutHandler(jwtUserService());
}
@Bean
protected CorsConfigurationSource corsConfigurationSource() {
CorsConfiguration configuration = new CorsConfiguration();
configuration.setAllowedOrigins(Arrays.asList("*"));
configuration.setAllowedMethods(Arrays.asList("GET","POST","HEAD", "OPTION"));
configuration.setAllowedHeaders(Arrays.asList("*"));
configuration.addExposedHeader("Authorization");
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/**", configuration);
return source;
}
}