Spring Security详解(二)认证之核心配置详解

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上有两个注解:

  1. @Configuration:,Spring Configuration,用来注册bean。详情可以查看Configuration详解
  2. @EnableWebSecurity:用来开启Spring Security支持。如果需要自定义配置,可扩展WebSecurityConfigurerAdapter并覆盖其一些方法来设置Web安全配置的某些细节。
  3. @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 = 
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值