在前一篇文章 《Spring Security使用基础》 中讲到了使用Spring Security的基础知识,下面就对其的使用进行拆解说明


1、基本原理

Spring Security中有几个关键的对象需要我们深入理解,下图是他们间的关系

Spring Security使用拆解_抽象类

首先,其核心是HttpSecurity,该对象负责对安全控制的所有方面进行配置,例如配置对哪些路径的访问需要具备哪些角色等。其本身是一个SecurityBuilder类型对象,最终会构建出一个用于拦截所有请求的过滤器链(FilterChian实例对象)。

HttpSecurity的职责是为了构建出一条过滤器链,而这个链中具备哪些Filter则需要对其进行配置。由于其可配置的过滤器有很多,如果都放在HttpSecurity中对过滤器进行创建和设置,那么HttpSecurity将会变得十分笨重且难以维护,对后续的扩展也十分不利。

为了应对上述的问题,随后便出现了许多针对HttpSecurity的配置类,每个配置类负责对HttpSecurity的某一面进行配置,HttpSecurity则负责统筹和协调。所以你就看到了诸如:HeadersConfigurer、SessionManagementConfigurer、RememberMeConfigurer、AuthorizeHttpRequestsConfigurer等配置类,这些配置类都会负责给HttpSecurity创建Filter和相关类的实例对象。

其次就是WebSecurity,一个HttpSecurity可以生成一个SecurityFilterChain,但WebSecurity中可将多个SecurityFilterChian包装成一个FilterChainProxy来对外提供服务。


2、SecurityBuilder

在Spring Security中,对象是“构建”出来的,其定义了一个用于构建任意类型实例的接口

public interface SecurityBuilder<O> {

	O build() throws Exception;

}

通过调用以上的build()方法来构建指定泛型类型的实例对象。基于该接口,还定义了一个抽象类

public abstract class AbstractSecurityBuilder<O> 
															implements SecurityBuilder<O> {
	
  @Override
	public final O build() throws Exception {
		if (this.building.compareAndSet(false, true)) {
			this.object = doBuild();
			return this.object;
		}
		throw new AlreadyBuiltException("This object has "+
    	"already been built");
	}
  
  protected abstract O doBuild() throws Exception;
}

考虑到对象的创建过程中可能还需要经过一些类的配置(例如上面讲到的HttpSecurity在构建FilterChian实例对象的过程中需要进行配置),所以又衍生出了以下的抽象类,该抽象类将对象的构建分成了多个阶段,可以在各阶段执行对应的动作

public abstract class AbstractConfiguredSecurityBuilder<O, B extends SecurityBuilder<O>>
		extends AbstractSecurityBuilder<O> {
    //SecurityConfigurer本身也是SecurityBuilder类型
    private final LinkedHashMap<Class<? extends SecurityConfigurer<O, B>>, List<SecurityConfigurer<O, B>>> configurers = new LinkedHashMap<>();

	@Override
	protected final O doBuild() throws Exception {
		synchronized (this.configurers) {
			this.buildState = BuildState.INITIALIZING;
			beforeInit();
			init();
			this.buildState = BuildState.CONFIGURING;
			beforeConfigure();
			configure();
			this.buildState = BuildState.BUILDING;
			O result = performBuild();
			this.buildState = BuildState.BUILT;
			return result;
		}
	}
    
  	protected void beforeInit() throws Exception {
	}
    protected void beforeConfigure() throws Exception {
	}
    protected abstract O performBuild() throws Exception;
    
    private void init() throws Exception {
    	//以自身为参数调用每个配置类
		Collection<SecurityConfigurer<O, B>> configurers = getConfigurers();
		for (SecurityConfigurer<O, B> configurer : configurers) {
			configurer.init((B) this);
		}
		for (SecurityConfigurer<O, B> configurer : this.configurersAddedInInitializing) {
			configurer.init((B) this);
		}
	}

	@SuppressWarnings("unchecked")
	private void configure() throws Exception {
    	//以自身为参数调用每个配置类
		Collection<SecurityConfigurer<O, B>> configurers = getConfigurers();
		for (SecurityConfigurer<O, B> configurer : configurers) {
			configurer.configure((B) this);
		}
	}
    
    private Collection<SecurityConfigurer<O, B>> getConfigurers() {
		List<SecurityConfigurer<O, B>> result = new ArrayList<>();
		for (List<SecurityConfigurer<O, B>> configs : this.configurers.values()) {
			result.addAll(configs);
		}
		return result;
	}
}

这里可以看到有一个SecurityConfigurer类型,从名字可见,这应该是一个用于起到配置作用的类型,定义如下

public interface SecurityConfigurer<O, B extends SecurityBuilder<O>> {
	void init(B builder) throws Exception;
  void configure(B builder) throws Exception;
}

该配置类型,用于对构建O类型实例对象的SecurityBuilder类型(例如构建FilterChian的HttpSecurity)进行配置。这里需要注意的是,在这接口中定义的方法的参数为“要对其进行配置的SecurityBuilder”,这样在SecurityConfigurer中就可以通过方法的参数来回调被配置类的方法了。

Spring Security使用拆解_抽象类_02

对于初次接触的人来讲,这几个类有点不好里理解,我用叙事的方式进行说明下,这种方式就等同于:我是一个SecurityBuilder构造器[HttpSecurity],用于构造A类型[FilterChian],我会创建A类型实例,并对其属性进行设置,然后返回给使用方。

但在给A实例设置属性前,我需要先询问下和我有关系的各个SecurityConfigurer实例希望对其属性怎么设置,当然,我开放了一些窗口来接收大家的意见,同时我也会依次拜访各位SecurityConfigurer,大伙有啥建议可以通过我提供的接口反馈给我,届时我会基于大家的返回来构建A实例对象。


3、HttpSecurity

Spring Security中内置了许多的过滤器,这些过滤器起着不同的作用,我们可以根据需要来构建对应的Filter。其内置的HttpSecurity对象为我们装配Filter提供了入口。

HttpSecurity的作用是为了构建DefaultSecurityFilterChain类型实例对象,一个DefaultSecurityFilterChain实例中包含了多个Filter,每个内置的Filter都可以通过HttpSecurity的各个配置类(SecurityConfigurer)来进行提供。

下面列出部分HttpSecurity的代码,可以看到其内置许多Configurer给我们创建需要的Filter。我们只需要调用HttpSecurity的方法就可以获取到配置类的实例,并进一步根据配置类提供的接口来对Filter进行配置。

public final class HttpSecurity extends 
   AbstractConfiguredSecurityBuilder<DefaultSecurityFilterChain, HttpSecurity>
   implements SecurityBuilder<DefaultSecurityFilterChain>, HttpSecurityBuilder<HttpSecurity> {
   
   private List<OrderedFilter> filters = new ArrayList<>();
   
   //定义了内置Filter的排序
   private FilterOrderRegistration filterOrders = new FilterOrderRegistration();
    
   private AuthenticationManager authenticationManager;
    
    
   public CorsConfigurer<HttpSecurity> cors() throws Exception {
		return getOrApply(new CorsConfigurer<>());
	}

	public SessionManagementConfigurer<HttpSecurity> sessionManagement() throws Exception {
		return getOrApply(new SessionManagementConfigurer<>());
	}
   
	public RememberMeConfigurer<HttpSecurity> rememberMe() throws Exception {
		return getOrApply(new RememberMeConfigurer<>());
	}
   
	public RequestCacheConfigurer<HttpSecurity> requestCache() throws Exception {
		return getOrApply(new RequestCacheConfigurer<>());
	}
   
	public ExceptionHandlingConfigurer<HttpSecurity> exceptionHandling() throws Exception {
		return getOrApply(new ExceptionHandlingConfigurer<>());
	}
   
	public SecurityContextConfigurer<HttpSecurity> securityContext() throws Exception {
		return getOrApply(new SecurityContextConfigurer<>());
	}
   
	public FormLoginConfigurer<HttpSecurity> formLogin() throws Exception {
		return getOrApply(new FormLoginConfigurer<>());
	}
   
	public LogoutConfigurer<HttpSecurity> logout() throws Exception {
		return getOrApply(new LogoutConfigurer<>());
	}
   
	public AnonymousConfigurer<HttpSecurity> anonymous() throws Exception {
		return getOrApply(new AnonymousConfigurer<>());
	}
   
	public HttpSecurity authenticationManager(AuthenticationManager authenticationManager) {
		Assert.notNull(authenticationManager, "authenticationManager cannot be null");
		this.authenticationManager = authenticationManager;
		return HttpSecurity.this;
	}

	public <C> void setSharedObject(Class<C> sharedType, C object) {
		super.setSharedObject(sharedType, object);
	}
	public HttpSecurity authenticationProvider(AuthenticationProvider authenticationProvider) {
		getAuthenticationRegistry().authenticationProvider(authenticationProvider);
		return this;
	}
	public HttpSecurity userDetailsService(UserDetailsService userDetailsService) throws Exception {
		getAuthenticationRegistry().userDetailsService(userDetailsService);
		return this;
	}  
   
   //添加配置类并返回
   private <C extends SecurityConfigurerAdapter<DefaultSecurityFilterChain, HttpSecurity>> C getOrApply(C configurer)
			throws Exception {
      //父类AbstractConfiguredSecurityBuilder方法获取
		C existingConfig = (C) getConfigurer(configurer.getClass());
		if (existingConfig != null) {
			return existingConfig;
		}
      //父类AbstractConfiguredSecurityBuilder方法放入集合
		return apply(configurer);
	}
   
	@Override
	protected void beforeConfigure() throws Exception {
		if (this.authenticationManager != null) {
			setSharedObject(AuthenticationManager.class, this.authenticationManager);
		}
		else {
			ObservationRegistry registry = getObservationRegistry();
			AuthenticationManager manager = getAuthenticationRegistry().build();
			if (!registry.isNoop() && manager != null) {
				setSharedObject(AuthenticationManager.class, new ObservationAuthenticationManager(registry, manager));
			}
			else {
				setSharedObject(AuthenticationManager.class, manager);
			}
		}
	}

	@SuppressWarnings("unchecked")
	@Override
	protected DefaultSecurityFilterChain performBuild() {
		
      ExpressionUrlAuthorizationConfigurer<?> expressionConfigurer = getConfigurer(
				ExpressionUrlAuthorizationConfigurer.class);
		AuthorizeHttpRequestsConfigurer<?> httpConfigurer = getConfigurer(AuthorizeHttpRequestsConfigurer.class);
		
      boolean oneConfigurerPresent = expressionConfigurer == null ^ httpConfigurer == null;
		Assert.state((expressionConfigurer == null && httpConfigurer == null) || oneConfigurerPresent,
				"authorizeHttpRequests cannot be used in conjunction with authorizeRequests. Please select just one.");
		
      this.filters.sort(OrderComparator.INSTANCE);
		List<Filter> sortedFilters = new ArrayList<>(this.filters.size());
		for (Filter filter : this.filters) {
			sortedFilters.add(((OrderedFilter) filter).filter);
		}
      //最终构建出了FilterChain实例对象
		return new DefaultSecurityFilterChain(this.requestMatcher, sortedFilters);
	}
}

附:Spring Security中的内置过滤器(部分)

Spring Security使用拆解_ide_03


4、WebSecurity

理清了上面的关系后再看WebSecurity就变得简单了。该类的目的就是调用所持有的SecurityBuilder<? extends SecurityFilterChain>类型(例如HttpSecurity)的build()方法来获取SecurityFilterChian,再将所有的SecurityFilterChian包装成FilterChainProxy。

public final class WebSecurity extends 
    AbstractConfiguredSecurityBuilder<Filter, WebSecurity>
    implements SecurityBuilder<Filter>, ApplicationContextAware, 
	ServletContextAware {
    
    private final List<SecurityBuilder<? extends SecurityFilterChain>> securityFilterChainBuilders = new ArrayList<>();
    
    
    public WebSecurity addSecurityFilterChainBuilder(
			SecurityBuilder<? extends SecurityFilterChain> securityFilterChainBuilder) {
		this.securityFilterChainBuilders.add(securityFilterChainBuilder);
		return this;
	}
    
    @Override
	protected Filter performBuild() throws Exception {
		Assert.state(!this.securityFilterChainBuilders.isEmpty(),
				() -> "At least one SecurityBuilder<? extends SecurityFilterChain> needs to be specified. "
						+ "Typically this is done by exposing a SecurityFilterChain bean. "
						+ "More advanced users can invoke " + WebSecurity.class.getSimpleName()
						+ ".addSecurityFilterChainBuilder directly");
		int chainSize = this.ignoredRequests.size() + this.securityFilterChainBuilders.size();
		List<SecurityFilterChain> securityFilterChains = new ArrayList<>(chainSize);
		List<RequestMatcherEntry<List<WebInvocationPrivilegeEvaluator>>> requestMatcherPrivilegeEvaluatorsEntries = new ArrayList<>();
		for (RequestMatcher ignoredRequest : this.ignoredRequests) {
			WebSecurity.this.logger.warn("You are asking Spring Security to ignore " + ignoredRequest
					+ ". This is not recommended -- please use permitAll via HttpSecurity#authorizeHttpRequests instead.");
			SecurityFilterChain securityFilterChain = new DefaultSecurityFilterChain(ignoredRequest);
			securityFilterChains.add(securityFilterChain);
			requestMatcherPrivilegeEvaluatorsEntries
					.add(getRequestMatcherPrivilegeEvaluatorsEntry(securityFilterChain));
		}
        
		for (SecurityBuilder<? extends SecurityFilterChain> securityFilterChainBuilder : this.securityFilterChainBuilders) {
			SecurityFilterChain securityFilterChain = securityFilterChainBuilder.build();
			securityFilterChains.add(securityFilterChain);
			requestMatcherPrivilegeEvaluatorsEntries
					.add(getRequestMatcherPrivilegeEvaluatorsEntry(securityFilterChain));
		}
		if (this.privilegeEvaluator == null) {
			this.privilegeEvaluator = new RequestMatcherDelegatingWebInvocationPrivilegeEvaluator(
					requestMatcherPrivilegeEvaluatorsEntries);
		}
        
        //构建出FilterChainProxy
		FilterChainProxy filterChainProxy = new FilterChainProxy(securityFilterChains);
		if (this.httpFirewall != null) {
			filterChainProxy.setFirewall(this.httpFirewall);
		}
		if (this.requestRejectedHandler != null) {
			filterChainProxy.setRequestRejectedHandler(this.requestRejectedHandler);
		}
		else if (!this.observationRegistry.isNoop()) {
			CompositeRequestRejectedHandler requestRejectedHandler = new CompositeRequestRejectedHandler(
					new ObservationMarkingRequestRejectedHandler(this.observationRegistry),
					new HttpStatusRequestRejectedHandler());
			filterChainProxy.setRequestRejectedHandler(requestRejectedHandler);
		}
		filterChainProxy.setFilterChainDecorator(getFilterChainDecorator());
		filterChainProxy.afterPropertiesSet();

		Filter result = filterChainProxy;
		if (this.debugEnabled) {
			this.logger.warn("\n\n" + "********************************************************************\n"
					+ "**********        Security debugging is enabled.       *************\n"
					+ "**********    This may include sensitive information.  *************\n"
					+ "**********      Do not use in a production system!     *************\n"
					+ "********************************************************************\n\n");
			result = new DebugFilter(filterChainProxy);
		}

		this.postBuildAction.run();
		return result;
	}
}


5、@EnableWebSecurity

通过HttpSecurity我们完成了安全所需的配置,通过WebSecurity完成了FilterChainProxy的创建,那么他们被执行的入口在哪呢?接下来就看看可以让所有安全配置生效的EnableWebSecurity注解

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Documented
@Import({ WebSecurityConfiguration.class, 
         SpringWebMvcImportSelector.class, 
         OAuth2ImportSelector.class,
		HttpSecurityConfiguration.class })
@EnableGlobalAuthentication
public @interface EnableWebSecurity {

	/**
	 * Controls debugging support for Spring Security.
   * Default is false.
	 * @return if true, enables debug support with Spring Security
	 */
	boolean debug() default false;

}

首先看下HttpSecurityConfiguration配置类,之所以先看这个是因为这里面完成了对HttpSecurity的实例创建,并对其进行了默认的配置

@Configuration(proxyBeanMethods = false)
class HttpSecurityConfiguration {
	
  //1、重点:HttpSecurity实例被创建了
  @Bean(HTTPSECURITY_BEAN_NAME)
	@Scope("prototype")
	HttpSecurity httpSecurity() throws Exception {
		LazyPasswordEncoder passwordEncoder = new LazyPasswordEncoder(this.context);
		AuthenticationManagerBuilder authenticationBuilder = new DefaultPasswordEncoderAuthenticationManagerBuilder(
				this.objectPostProcessor, passwordEncoder);
		authenticationBuilder.parentAuthenticationManager(authenticationManager());
		authenticationBuilder.authenticationEventPublisher(getAuthenticationEventPublisher());
		HttpSecurity http = new HttpSecurity(this.objectPostProcessor, authenticationBuilder, createSharedObjects());
		WebAsyncManagerIntegrationFilter webAsyncManagerIntegrationFilter = new WebAsyncManagerIntegrationFilter();
		webAsyncManagerIntegrationFilter.setSecurityContextHolderStrategy(this.securityContextHolderStrategy);
		// @formatter:off
		http
			.csrf(withDefaults())
			.addFilter(webAsyncManagerIntegrationFilter)
			.exceptionHandling(withDefaults())
			.headers(withDefaults())
			.sessionManagement(withDefaults())
			.securityContext(withDefaults())
			.requestCache(withDefaults())
			.anonymous(withDefaults())
			.servletApi(withDefaults())
			.apply(new DefaultLoginPageConfigurer<>());
		http.logout(withDefaults());
		// @formatter:on
		applyDefaultConfigurers(http);
		return http;
	}
  
  private AuthenticationManager authenticationManager() throws Exception {
		return this.authenticationConfiguration.getAuthenticationManager();
	}

	private AuthenticationEventPublisher getAuthenticationEventPublisher() {
		if (this.context.getBeanNamesForType(AuthenticationEventPublisher.class).length > 0) {
			return this.context.getBean(AuthenticationEventPublisher.class);
		}
		return this.objectPostProcessor.postProcess(new DefaultAuthenticationEventPublisher());
	}

	private void applyDefaultConfigurers(HttpSecurity http) throws Exception {
		ClassLoader classLoader = this.context.getClassLoader();
		List<AbstractHttpConfigurer> defaultHttpConfigurers = SpringFactoriesLoader
				.loadFactories(AbstractHttpConfigurer.class, classLoader);
		for (AbstractHttpConfigurer configurer : defaultHttpConfigurers) {
			http.apply(configurer);
		}
	}

	private Map<Class<?>, Object> createSharedObjects() {
		Map<Class<?>, Object> sharedObjects = new HashMap<>();
		sharedObjects.put(ApplicationContext.class, this.context);
		sharedObjects.put(ContentNegotiationStrategy.class, this.contentNegotiationStrategy);
		return sharedObjects;
	}
}

接着看看WebSecurityConfiguration配置类

@Configuration(proxyBeanMethods = false)
public class WebSecurityConfiguration implements ImportAware, BeanClassLoaderAware {

	private WebSecurity webSecurity;

	private Boolean debugEnabled;

	private List<SecurityConfigurer<Filter, WebSecurity>> webSecurityConfigurers;

	private List<SecurityFilterChain> securityFilterChains = Collections.emptyList();

	private List<WebSecurityCustomizer> webSecurityCustomizers = Collections.emptyList();

	private ClassLoader beanClassLoader;

	@Autowired(required = false)
	private ObjectPostProcessor<Object> objectObjectPostProcessor;

    //1、重点:HttpSecurityConfiguration创建的HttpSecurity被注入
	@Autowired(required = false)
	private HttpSecurity httpSecurity;

	@Bean
	public static DelegatingApplicationListener delegatingApplicationListener() {
		return new DelegatingApplicationListener();
	}

	@Bean
	@DependsOn(AbstractSecurityWebApplicationInitializer.DEFAULT_FILTER_NAME)
	public SecurityExpressionHandler<FilterInvocation> webSecurityExpressionHandler() {
		return this.webSecurity.getExpressionHandler();
	}
    
    public WebSecurity addSecurityFilterChainBuilder(
			SecurityBuilder<? extends SecurityFilterChain> securityFilterChainBuilder) {
		this.securityFilterChainBuilders.add(securityFilterChainBuilder);
		return this;
	}

    //2、重点:开始创建WebSecurity实例
    @Autowired(required = false)
	public void setFilterChainProxySecurityConfigurer(ObjectPostProcessor<Object> objectPostProcessor,
			ConfigurableListableBeanFactory beanFactory) throws Exception {
		//创建WebSecurity实例
        this.webSecurity = objectPostProcessor.postProcess(new WebSecurity(objectPostProcessor));
		if (this.debugEnabled != null) {
			this.webSecurity.debug(this.debugEnabled);
		}
		List<SecurityConfigurer<Filter, WebSecurity>> webSecurityConfigurers = new AutowiredWebSecurityConfigurersIgnoreParents(
				beanFactory).getWebSecurityConfigurers();
		webSecurityConfigurers.sort(AnnotationAwareOrderComparator.INSTANCE);
		Integer previousOrder = null;
		Object previousConfig = null;
        
		for (SecurityConfigurer<Filter, WebSecurity> config : webSecurityConfigurers) {
			Integer order = AnnotationAwareOrderComparator.lookupOrder(config);
			if (previousOrder != null && previousOrder.equals(order)) {
				throw new IllegalStateException("@Order on WebSecurityConfigurers must be unique. Order of " + order
						+ " was already used on " + previousConfig + ", so it cannot be used on " + config + " too.");
			}
			previousOrder = order;
			previousConfig = config;
		}
        //扩展点:我们可以自己创建SecurityConfigurer对WebSecurity进行配置
		for (SecurityConfigurer<Filter, WebSecurity> webSecurityConfigurer : webSecurityConfigurers) {
			this.webSecurity.apply(webSecurityConfigurer);
		}
		this.webSecurityConfigurers = webSecurityConfigurers;
	}
    
	//3、重点:创建名为springSecurityFilterChain的FilterChainProxy
    //并暴露到IOC中【通过暴露到IOC后,便可以被加入到Servlet容器里面】
	@Bean(name = AbstractSecurityWebApplicationInitializer.DEFAULT_FILTER_NAME)
	public Filter springSecurityFilterChain() throws Exception {
		boolean hasFilterChain = !this.securityFilterChains.isEmpty();
    	//通过该判断可知,如果IOC中已经有了FilterChian实例,
        //则不会再执行WebSecurity的方法来驱动FilterChian的创建
		if (!hasFilterChain) {
            //HttpSecurity实例被添加到WebSecurity中
            //并添加默认配置
			this.webSecurity.addSecurityFilterChainBuilder(() -> {
				this.httpSecurity.authorizeHttpRequests((authorize) -> authorize.anyRequest().authenticated());
				this.httpSecurity.formLogin(Customizer.withDefaults());
				this.httpSecurity.httpBasic(Customizer.withDefaults());
				return this.httpSecurity.build();
			});
		}
		for (SecurityFilterChain securityFilterChain : this.securityFilterChains) {
			this.webSecurity.addSecurityFilterChainBuilder(() -> securityFilterChain);
		}
		for (WebSecurityCustomizer customizer : this.webSecurityCustomizers) {
			customizer.customize(this.webSecurity);
		}
		return this.webSecurity.build();
	}
}

说明:以上只是摘录了部分代码,可自行深入查阅研究


6、简单使用示例

前面对Spring Security的允许原理做了简要的全貌说明,下面我们看看在SpringBoot中如何使用

@Configuration
public class CustomSecurityConfiguration {

  	//配置全局的忽略需要认证的资源路径,这些资源将绕过安全控制
  	@Bean
  	public WebSecurityCustomizer webSecurityCustomizer() {
    	return (web) -> web.ignoring().requestMatchers("/webjars/**", "/icon/**","/js/**","/css/**");
  	}
  
    //注入HttpSecurity,并对齐进行配置
  	@Bean
    public SecurityFilterChain configure(HttpSecurity http) throws Exception {
        return http.cors().and()
                .csrf().disable()
                .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).and()
                .exceptionHandling()
            		//假设你自定义了访问被拒绝时候的处理器
                    .accessDeniedHandler(new CustomAccessDeniedHandler())  
            		//假设你自定义了认证的入口实现(例如调整到某个登录页面)
                    .authenticationEntryPoint(customAuthenticationEntryPoint)
                    .and()
                //授权请求配置(以前版本是authorizeRequests())
                .authorizeHttpRequests()
            		//匹配的路径都可以访问
                    .requestMatchers("/auth/code","/error","/logout","/forbidden").permitAll()  
            		//具备某个角色的用户才可以访问的路径
                    .requestMatchers("/admin/**").hasAnyRole("admin")
            		//其他的资源访问都需要登录
                    .anyRequest().authenticated()
                .and()
            	//假设你自定义了一个Filter,并添加到UsernamePasswordAuthenticationFilter前面
                .addFilterBefore(customAuthenticationFilter,UsernamePasswordAuthenticationFilter.class)
            	//假设你自定义了认证方式(authenticationManager)
                .authenticationManager(authenticationManager)
                .build() ;
    }
}

本文对Spring Security的主要原理进行了拆解说明,虽然未讲解很多细节的内容,但按照上诉的思路去看源码也就容易了很多。

在后续的文章中还会对“认证”、“鉴权”等方面做详细的分析。Spring Security对认证和鉴权过程进行了诸多的抽象,这些抽象的内容可以很好的回答在 《Spring Security使用基础》 中提出的问题。