文章目录
2.核心配置详解
2.1 测试用例
这是Spring Security官方提供的入门示例:
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("/", "/home").permitAll()
.anyRequest().authenticated()
.and()
.formLogin()
.loginPage("/login")
.permitAll()
.and()
.logout()
.permitAll();
}
@Bean
@Override
public UserDetailsService userDetailsService() {
UserDetails user =
User.withDefaultPasswordEncoder()
.username("user")
.password("password")
.roles("USER")
.build();
return new InMemoryUserDetailsManager(user);
}
}
从上面的示例可以看到,WebSecurityConfig
上有两个注解:
@Configuration
:,Spring Configuration,用来注册bean。详情可以查看Configuration详解@EnableWebSecurity
:用来开启Spring Security支持。如果需要自定义配置,可扩展WebSecurityConfigurerAdapter
并覆盖其一些方法来设置Web安全配置的某些细节。@EnableGlobalMethodSecurity(prePostEnabled = true)
,用来开启@PreFilter
,@PreAuthorize
,@PostAuthorize
,@PostFilter
注解的支持
解释一下这样配置的作用:
-
该
configure(HttpSecurity)
方法定义应保护哪些URL路径,不应该保护哪些URL路径。具体来说,/
和/home
路径配置为不需要任何身份验证。所有其他路径必须经过验证。 -
用户成功登录后,他们将被重定向到之前要求身份验证的页面。有一个自定义
/login
页面(由指定loginPage()
),每个人都可以查看它。 -
该
userDetailsService()
方法与单个用户一起建立内存用户存储。该用户的用户名为user
,密码为password
,角色为USER
。
2.2 @EnableWebSecurity
@Import({
WebSecurityConfiguration.class,
SpringWebMvcImportSelector.class })
@EnableGlobalAuthentication
@Configuration
public @interface EnableWebSecurity {
boolean debug() default false;
}
@Import
是用于Spring Boot提供的引入外部配置的注解,具体如何加载可查看bean加载
WebSecurityConfiguration
用来配置web Security。在这个类中有一个非常重要的Bean被注册了。
private WebSecurity webSecurity;
@Bean(name = AbstractSecurityWebApplicationInitializer.DEFAULT_FILTER_NAME)
public Filter springSecurityFilterChain() throws Exception {
boolean hasConfigurers = webSecurityConfigurers != null
&& !webSecurityConfigurers.isEmpty();
if (!hasConfigurers) {
WebSecurityConfigurerAdapter adapter = objectObjectPostProcessor
.postProcess(new WebSecurityConfigurerAdapter() {
});
webSecurity.apply(adapter);
}
return webSecurity.build();
}
通过WebSecurity#build
创建了filter springSecurityFilterChain
,build方法在WebSecurity
详细说明。
而WebSecurity
的初始化是在:
@Autowired(required = false)
public void setFilterChainProxySecurityConfigurer(
ObjectPostProcessor<Object> objectPostProcessor,
@Value("#{@autowiredWebSecurityConfigurersIgnoreParents.getWebSecurityConfigurers()}") List<SecurityConfigurer<Filter, WebSecurity>> webSecurityConfigurers)
throws Exception {
webSecurity = objectPostProcessor
.postProcess(new WebSecurity(objectPostProcessor));
if (debugEnabled != null) {
webSecurity.debug(debugEnabled);
}
Collections.sort(webSecurityConfigurers, AnnotationAwareOrderComparator.INSTANCE);
//...
for (SecurityConfigurer<Filter, WebSecurity> webSecurityConfigurer : webSecurityConfigurers) {
webSecurity.apply(webSecurityConfigurer);
}
this.webSecurityConfigurers = webSecurityConfigurers;
}
创建WebSecurity
的实例,并将WebSecurityConfigurer
设置到实例中。那么WebSecurityConfigurer
来自于哪里呢? 注意看入参 @Value("#{@autowiredWebSecurityConfigurersIgnoreParents.getWebSecurityConfigurers()}")List<SecurityConfigurer<Filter, WebSecurity>> webSecurityConfigurers
。
public static AutowiredWebSecurityConfigurersIgnoreParents autowiredWebSecurityConfigurersIgnoreParents(
ConfigurableListableBeanFactory beanFactory) {
return new AutowiredWebSecurityConfigurersIgnoreParents(beanFactory);
}
//AutowiredWebSecurityConfigurersIgnoreParents#getWebSecurityConfigurers
public List<SecurityConfigurer<Filter, WebSecurity>> getWebSecurityConfigurers() {
List<SecurityConfigurer<Filter, WebSecurity>> webSecurityConfigurers = new ArrayList<SecurityConfigurer<Filter, WebSecurity>>();
Map<String, WebSecurityConfigurer> beansOfType = beanFactory
.getBeansOfType(WebSecurityConfigurer.class);
for (Entry<String, WebSecurityConfigurer> entry : beansOfType.entrySet()) {
webSecurityConfigurers.add(entry.getValue());
}
return webSecurityConfigurers;
}
获取注册在Spring容器中的所有WebSecurityConfigurer
bean。比如测试用例WebSecurityConfig
。如果没有自定义的实现类,即没有配置的webSecurityConfigurers
,则会new 一个WebSecurityConfigurerAdapter
作为默认的webSecurityConfigurers
。
SpringWebMvcImportSelector
如果当前的环境包含Spring MVC时,需要加载WebMvcSecurityConfiguration
,该配置文件用于用于为Spring MVC和Spring Security添加CSRF。
class SpringWebMvcImportSelector implements ImportSelector {
public String[] selectImports(AnnotationMetadata importingClassMetadata) {
boolean webmvcPresent = ClassUtils.isPresent(
"org.springframework.web.servlet.DispatcherServlet",
getClass().getClassLoader());
return webmvcPresent
? new String[] {
"org.springframework.security.config.annotation.web.configuration.WebMvcSecurityConfiguration" }
: new String[] {
};
}
EnableGlobalAuthentication
源码:
@Retention(value = java.lang.annotation.RetentionPolicy.RUNTIME)
@Target(value = {
java.lang.annotation.ElementType.TYPE })
@Documented
@Import(AuthenticationConfiguration.class)
@Configuration
public @interface EnableGlobalAuthentication {
}
可以看出,这个注解引入了AuthenticationConfiguration
。主要用来初始化AuthenticationManager
@Configuration
@Import(ObjectPostProcessorConfiguration.class)
public class AuthenticationConfiguration {
private AuthenticationManager authenticationManager;
@Bean
//创建默认的DefaultPasswordEncoderAuthenticationManagerBuilder 并注册EventPublisher
public AuthenticationManagerBuilder authenticationManagerBuilder(
ObjectPostProcessor<Object> objectPostProcessor, ApplicationContext context) {
LazyPasswordEncoder defaultPasswordEncoder = new LazyPasswordEncoder(context);
AuthenticationEventPublisher authenticationEventPublisher = getBeanOrNull(context, AuthenticationEventPublisher.class);
DefaultPasswordEncoderAuthenticationManagerBuilder result =