SpringSecurit原理解读和使用教程(一)——框架总览

我们知道SpringSecurity在Spring项目中是提供安全措施的,那么在web开发中我们一般通过Filter来保护web资源,同样,SpringSecurity也是通过一系列Filter来保护我们的Web资源,但是,和平时使用的不同的是,这些Filter不需要我们直接实现,在We开发中的常用的Filter已经在框架中实现了,我们需要做的就是进行相应的配置即可,这些已经实现的filter将会被组建成一个FilterChain,在项目启动的时候,将启动这个过滤器链来为我们的项目提供安全服务;

所以,在研究SpringSecurity框架原理的时候就是在研究这个FilterChain是怎样在项目启动的时候组建起来的,而我们自己的配置又是通过怎样的机制加载进去的;以及后续的学习中,这些Filters具体的工作流程是什么 ;

第一个问题,FilterChain的创建流程——
在这里,我们需要开始接触SpringSecurity相关的代码(只是很小的一部分):

@Configuration
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter

在项目中,我们通过声明上面的类来为我们的项目引入SpringSecurity的安全服务,具体来说,是一个注解@EnableWebSecurity和继承的一个类WebSecurityConfigureAdapter;

SPringSecurity就是从这两样东西开始——

首先来看一下@EnableWebSecurity注解:

官方通过注释说明:将此注释添加到具有@configuration注解的类上以使用SpringSecurity;也就是说,是这个注解为我们引入了SpringSecurity,现在记住这点就可以了,至于是通过什么机制引入的我们之后再看;

其次,我们来看看另一个——WebSecurityConfigureAdapter类,

public abstract class WebSecurityConfigurerAdapter implements
      WebSecurityConfigurer<WebSecurity> 

通过注释我们可以知道:为创建websecurityconfigurer实例提供了一个方便的基类,具体可以通过重写方法进行定制其实现。

也就是说,这个类的作用是方便我们通过继承他并重写其中的相关方法来定制我们自己websecurityconfigurer;至于websecurityconfigurer,看名字就是知道是用来配置Filter的;

所以,要使用spring security,首先我们需要继承websecurityconfigureadapter类并重写其中相关的方法类为我们的项目进行配置;同时在这个类上要添加@configuration注解和@Enable web Security注解来引入spring security的支持;

所以,到此为止,具体是怎么创建出FilterChain的呢?我们直接来看对应创建的源码——

int chainSize = ignoredRequests.size() + securityFilterChainBuilders.size();
	List<SecurityFilterChain> securityFilterChains = new ArrayList<SecurityFilterChain>(
			chainSize);
	for (RequestMatcher ignoredRequest : ignoredRequests) {
		securityFilterChains.add(new DefaultSecurityFilterChain(ignoredRequest));
	}
	for (SecurityBuilder<? extends SecurityFilterChain> securityFilterChainBuilder : securityFilterChainBuilders) {
		securityFilterChains.add(securityFilterChainBuilder.build());
	}
	FilterChainProxy filterChainProxy = new FilterChainProxy(securityFilterChains);

上面的代码可以看到FilterChain的创建主要依赖两个对象——ignoredRequest和securityfilterchainbuilder,

分别通过

new DefaultSecurityFilterChain(ignoredRequest)

securityFilterChainBuilder.build()

可分别创建一个FilterChain,然后“add”进“securityFilterChains”中,具体的实现我们暂且不去理会,主要来大概看一下这两中创建方式,

第一种大概可以看出是以ignoredRequest对象为参数“new”了一个default的FilterChain——创建出的应该是一个默认配置的FilterChain,(我们暂且这样理解)

而第二种调用的是filterchain的“builder”方法,也就是通过他的构造器build出了一个FilterChain;

这两种方式穿件有什么不同的地方或者有什么联系,我们之后再说,在这里,我们应该知道的是我们所需要的这过滤器链是在哪、通过什么样的方式创建出来的,看过这里的创建代码,对这个过程有一个大概的了解对之后的分析将会带来很大的帮助;

同时,在上面的代码中应该注意到一个细节——创建的FilterChain加入到了一个列表中,也就说,允许为我们的项目创建多个FilterChain;还有就是,最后创建的并不是真正的filter组成的链,而是一个“proxy”,是一个代理;

到此为止,我们知道创建FilterChain有两种方式:
new一个默认的实现,或者通过构建器构建一个,在这里我们很容易猜想到的是,通过构建器securityFilterChainBuilder构建的FilterChain应该是与默认实现相对的——自定义配置的实现,所以说,我们之前提到的自定义配置是通过构建器来实现的,那么下面就来看一看这个过程的具体实现流程,

首先,securityFilterChainBuilder是什么?

final HttpSecurity http = getHttp();
web.addSecurityFilterChainBuilder(http)

上面的代码中通过getHttp方法返回一个http对象,然后将这个http对象作为参数传递给了addSecurityFilterChainBuilder方法,再来看这个方法:

public WebSecurity addSecurityFilterChainBuilder(
			SecurityBuilder<? extends SecurityFilterChain> securityFilterChainBuilder) {
		this.securityFilterChainBuilders.add(securityFilterChainBuilder);
		return this;
	}

代码注释中对这个方法的说明:

  • 添加生成器以创建securityfilterchain实例。
  • 这个函数通常在 WebSecurityConfigurerAdapter类的init(WebSecurity)方法中被自动调用;
  • securityfilterchainbuilder用于创建securityfilterchain实例
  • 返回websecurity进行进一步的自定义

现在很明了的是,http对象就是一个securityFilterChainBuilder,通过addsecurityFilterChainBuilder()方法将其加入到了securityFilterChainBuilders列表中,而这个列表我们已经在上面创建FilterChain的代码中见过了,就是一个用来存放securityFilterChainBuilder的列表;

所以说,这个通过getHttp()方法得到的http对象就是用来生成filterchain的构建器,

因此,接着来看关于getHttp()的代码 :

protected final HttpSecurity getHttp() throws Exception {
		if (http != null) {
			return http;
		}
/*省略不必要的代码*/
		http = new HttpSecurity(objectPostProcessor, authenticationBuilder,
				sharedObjects);
		configure(http);
		return http;
	}

上面的代码不必仔细阅读,直接看代码中关于这个方法的注释:

创建httpsecurity或返回当前实例

很假单的一句说明,这个方法的功能也和这个注释一样简单——直接返回一个http对象,如果没有的话则创建一个http对象然后返回,(这里要说明的是,该方法中直接返回的http对象是源自于该方法所属的类中的,在这里读者可能也会有疑惑,本文中所提及到的方法均没有说明其所属的类,在这里说明一下,未提及到具体的类是为了刚开始接触源码的同学逻辑产生混乱;以及这些需要记忆的类名会对理解造成困扰,而不提及方法所属的类对于我们理解FilterChain的创建过程并没有任何的影响,反而因为不会分散过多的注意力在类名和类之间的调用关系上而对创建的过程有一个更加清楚的了解,上面所提及到的代代码和所属的类将会在之后详细分析的时候一一解读;本篇文章只是让读者对SpringSecurity框架的原理和工作流程有一个整体把握)

现在,我们应该来看一下最后这个最重要的角色——http对象:
下面列出了该类中主要的属性和方法;但是也不用细看,分析中有对应的详细说明;

public final class HttpSecurity{
    private final RequestMatcherConfigurer requestMatcherConfigurer;
	private List<Filter> filters = new ArrayList<Filter>();
	private RequestMatcher requestMatcher = AnyRequestMatcher.INSTANCE;
	private FilterComparator comparator = new FilterComparator();

private ApplicationContext getContext();
public OpenIDLoginConfigurer<HttpSecurity> openidLogin()
public HeadersConfigurer<HttpSecurity> headers()
public CorsConfigurer<HttpSecurity> cors() 
public SessionManagementConfigurer<HttpSecurity> sessionManagement()
public PortMapperConfigurer<HttpSecurity> portMapper()
public JeeConfigurer<HttpSecurity> jee()
public X509Configurer<HttpSecurity> x509()
public RememberMeConfigurer<HttpSecurity> rememberMe()
public ExpressionUrlAuthorizationConfigurer<HttpSecurity>.ExpressionInterceptUrlRegistry authorizeRequests()
public RequestCacheConfigurer<HttpSecurity> requestCache()
public ExceptionHandlingConfigurer<HttpSecurity> exceptionHandling()
public SecurityContextConfigurer<HttpSecurity> securityContext()
public ServletApiConfigurer<HttpSecurity> servletApi()
public CsrfConfigurer<HttpSecurity> csrf()
public LogoutConfigurer<HttpSecurity> logout()
public AnonymousConfigurer<HttpSecurity> anonymous() 
public FormLoginConfigurer<HttpSecurity> formLogin()
public ChannelSecurityConfigurer<HttpSecurity>.ChannelRequestMatcherRegistry requiresChannel()
public HttpBasicConfigurer<HttpSecurity> httpBasic()
protected void beforeConfigure()
protected DefaultSecurityFilterChain performBuild() 
public HttpSecurity authenticationProvider(
			AuthenticationProvider authenticationProvider)
public HttpSecurity userDetailsService(UserDetailsService userDetailsService)
private AuthenticationManagerBuilder getAuthenticationRegistry()
public HttpSecurity addFilterAfter(Filter filter, Class<? extends Filter> afterFilter)
public HttpSecurity addFilterBefore(Filter filter,
			Class<? extends Filter> beforeFilter) 
public HttpSecurity addFilter(Filter filter) 
public HttpSecurity addFilterAt(Filter filter, Class<? extends Filter> atFilter)
public RequestMatcherConfigurer requestMatchers()
public HttpSecurity requestMatcher(RequestMatcher requestMatcher) 
public HttpSecurity antMatcher(String antPattern)
public HttpSecurity regexMatcher(String pattern)
public final class MvcMatchersRequestMatcherConfigurer 
private <C extends SecurityConfigurerAdapter<DefaultSecurityFilterChain, HttpSecurity>> C getOrApply(
			C configurer)
}

先看注释:
http security类似于Spring Security在命名空间配置中的xml&lt和http&gt元素。

为特定的HTTP请求配置基于Web的安全性。默认情况下,将应用于所有请求,但可以使用requestmatcher(requestmatcher就是上面所提到的第一种创建默认配置的filter chain时的对象参数ignoredrequest所属的类)或其他类似方法进行限制。

也是就是说,http就是一个配置类,配置的内容是该类中的各种方法对应的Filter,见名知意,读者可以大致浏览一下上面列出的方法,httpSecurity就是通过这些类来配置相应的过滤器的;可以明显的看出来,上面的各种配制方法的返回值是一个***configrer——也就是后面在创建filter chain时要用到的各种configurer就是通过http对象中的方法返回的;

读到这里,我们可以有以下总结:

以上便是Spring Security创建filterChain的逻辑过程,之后我们来看具体的实现流程是怎样的,也就是这些类之间的调用关系和SpringSecurity的启动流程,几乎所有的工作将会围绕这个流程的实现来进行,或扩展某个具体过程,或添加被我们省略掉的步骤;

http对象在那里创建?http到底包含什么内容?http对象是怎样作为filter chain的builder来创建filter chain的?详见下一篇文章:
SpringSecurit原理解读和使用教程(二)——spring security的启动流程

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
很抱歉,我无法直接为您生成代码。但是,我可以为您提供一些指导,以便您开始使用Spring Security框架来实现PBAC模型。 首先,您需要了解什么是PBAC模型。 PBAC(基于角色的访问控制)是一种访问控制模型,其中用户的访问权限由其角色确定。因此,PBAC模型可以表示为具有以下组成部分的权限系统: 1. 用户 2. 角色 3. 权限 4. 资源 在Spring Security中,您可以使用以下组件来实现PBAC模型: 1. Authentication(认证) 2. Authorization(授权) 3. Access Control(访问控制) 下面是一个简单的示例,演示如何使用Spring Security框架实现基于角色的访问控制。 1. 配置授权规则: ```java @Configuration @EnableWebSecurity public class WebSecurityConfig extends WebSecurityConfigurerAdapter { @Override protected void configure(HttpSecurity http) throws Exception { http.authorizeRequests() .antMatchers("/admin/**").hasRole("ADMIN") .antMatchers("/user/**").hasRole("USER") .anyRequest().authenticated() .and() .formLogin() .and() .httpBasic(); } @Autowired public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception { auth.inMemoryAuthentication() .withUser("admin").password("{noop}admin").roles("ADMIN") .and() .withUser("user").password("{noop}user").roles("USER"); } } ``` 在这个例子中,我们定义了两个用户角色:ADMIN和USER。ADMIN用户可以访问“/admin/**”路径,而USER用户可以访问“/user/**”路径。任何其他请求都需要进行身份验证才能访问。 2. 创建自定义AccessDecisionVoter: ```java public class PbcaAccessDecisionVoter implements AccessDecisionVoter<Object> { @Override public int vote(Authentication authentication, Object object, Collection<ConfigAttribute> configAttributes) { if (authentication == null) { return ACCESS_DENIED; } int result = ACCESS_ABSTAIN; for (ConfigAttribute attribute : configAttributes) { if (this.supports(attribute)) { result = ACCESS_DENIED; List<GrantedAuthority> authorities = (List<GrantedAuthority>) authentication.getAuthorities(); for (GrantedAuthority authority : authorities) { if (attribute.getAttribute().equals(authority.getAuthority())) { return ACCESS_GRANTED; } } } } return result; } @Override public boolean supports(ConfigAttribute attribute) { return attribute.getAttribute() != null; } @Override public boolean supports(Class<?> clazz) { return true; } } ``` 这个自定义的AccessDecisionVoter实现了AccessDecisionVoter接口,并重写了其中的vote()、supports()和supports()方法。这个自定义的AccessDecisionVoter用于根据用户的角色来决定是否允许访问资源。 3. 配置AccessDecisionManager: ```java @Configuration @EnableGlobalMethodSecurity(prePostEnabled = true) public class MethodSecurityConfig extends GlobalMethodSecurityConfiguration { @Override protected AccessDecisionManager accessDecisionManager() { List<AccessDecisionVoter<? extends Object>> decisionVoters = Arrays.asList(new PbcaAccessDecisionVoter()); return new AffirmativeBased(decisionVoters); } } ``` 在这个例子中,我们定义了一个方法级别的安全配置,并通过@EnableGlobalMethodSecurity注解启用了prePostEnabled选项。我们还配置了一个AccessDecisionManager,该Manager使用我们之前定义的自定义AccessDecisionVoter来做出访问决策。 这是一个简单的示例,演示如何使用Spring Security框架实现基于角色的访问控制。当然,您需要根据您的需求进行更改和优化。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值