SpringSecurity原理分析
Posted _微风轻起
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了SpringSecurity原理分析相关的知识,希望对你有一定的参考价值。
距离上次更新已经5个月了,因为这段时间主要是面试准备+适应新公司的内容,8月份离职,9月份入职,虽然看了很多内容,但没有进行系统整理。之后应该也会渐渐的整理一些内容,会继续更新,虽然没什么人看,但还是说明下,_O(∩_∩)O哈哈~。
这一篇我们主要梳理下SpringSecurity
的原理,SpringSecurity
主要是用于认证、授权的,其的主要原理就是通过Filter
来处理。
一、SpringSecurity的基本原理
1、基本流程
SpringSecurity
的基本原理就是应用了Tomcat
容器的Filter
,其的实现原理也就是类似于Tomcat
本身的ApplicationFilterChain
,也就是Filter
执行链。
public final class ApplicationFilterChain implements FilterChain
........
private ApplicationFilterConfig[] filters = new ApplicationFilterConfig[0];
...........
public ApplicationFilterChain()
public void doFilter(ServletRequest request, ServletResponse response) throws IOException, ServletException
..........
else
this.internalDoFilter(request, response);
private void internalDoFilter(ServletRequest request, ServletResponse response) throws IOException, ServletException
if (this.pos < this.n)
ApplicationFilterConfig filterConfig = this.filters[this.pos++];
try
Filter filter = filterConfig.getFilter();
.........
else
filter.doFilter(request, response, this);
.........
else
try
.........
else
this.servlet.service(request, response);
........
ApplicationFilterChain
本身就是先执行所有的filters
,执行完成后,其就会执行当前请求的Servlet
,对于SpringMVC
来说,就是DispatchSevelt
:
这里也就是说,先执行Tomcat
自身已有的Filter
,然后再交给SpringSecurity
定义的FilterChainProxy
,然后其再去执行SpringSecurity
用于认证、授权管理的各种Filter
。这个就是SpringSecurity
的核心原理。
2、默认注入的Filter列表
我们看下默认引入spring-boot-starter-security
后其会默认加入的Filter
:
3、FilterChainProxy
public class FilterChainProxy extends GenericFilterBean
..........
private void doFilterInternal(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException
......
List<Filter> filters = getFilters(firewallRequest);
........
VirtualFilterChain virtualFilterChain = new VirtualFilterChain(firewallRequest, chain, filters);
virtualFilterChain.doFilter(firewallRequest, firewallResponse);
........
private static final class VirtualFilterChain implements FilterChain
private final FilterChain originalChain;
private final List<Filter> additionalFilters;
..........
@Override
public void doFilter(ServletRequest request, ServletResponse response) throws IOException, ServletException
if (this.currentPosition == this.size)
if (logger.isDebugEnabled())
logger.debug(LogMessage.of(() -> "Secured " + requestLine(this.firewalledRequest)));
// Deactivate path stripping as we exit the security filter chain
this.firewalledRequest.reset();
this.originalChain.doFilter(request, response);
return;
this.currentPosition++;
Filter nextFilter = this.additionalFilters.get(this.currentPosition - 1);
if (logger.isTraceEnabled())
logger.trace(LogMessage.format("Invoking %s (%d/%d)", nextFilter.getClass().getSimpleName(),
this.currentPosition, this.size));
nextFilter.doFilter(request, response, this);
二、SpringSecurity对FilterChain的组装初始化
其的组装是借助于两个类来添加关于认证、授权相关的信息,由这些信息来添加FilterChain
中需要的Filter
,这两个类就是WebSecurity
、HttpSecurity
。
1、WebSecurity、HttpSecurity
这两个类都是继承的AbstractConfiguredSecurityBuilder
,以及实现SecurityBuilder
接口(用于构建对象)。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-6vdAJhTC-1638686018791)(F:\\MarkDown-File\\知识点资料\\Untitled.assets\\image-20211204221618377.png)]
public final class WebSecurity extends AbstractConfiguredSecurityBuilder<Filter, WebSecurity>
implements SecurityBuilder<Filter>, ApplicationContextAware
public final class HttpSecurity extends AbstractConfiguredSecurityBuilder<DefaultSecurityFilterChain, HttpSecurity>
implements SecurityBuilder<DefaultSecurityFilterChain>, HttpSecurityBuilder<HttpSecurity>
public interface SecurityBuilder<O>
O build() throws Exception;
2、AbstractConfiguredSecurityBuilder
public abstract class AbstractConfiguredSecurityBuilder<O, B extends SecurityBuilder<O>>
extends AbstractSecurityBuilder<O>
private final Log logger = LogFactory.getLog(getClass());
private final LinkedHashMap<Class<? extends SecurityConfigurer<O, B>>, List<SecurityConfigurer<O, B>>> configurers = new LinkedHashMap<>();
private final List<SecurityConfigurer<O, B>> configurersAddedInInitializing = new ArrayList<>();
private final Map<Class<?>, Object> sharedObjects = new HashMap<>();
这个基类主要有两个成员变量需要关注,也就是configurers
,与sharedObjects
。configurers(SecurityConfigurer)
这个主要是添加的各种配置信息。然后sharedObjects
中是添加一些共享的类对象,然后需要就能取出来。例如:
private Map<Class<?>, Object> createSharedObjects()
Map<Class<?>, Object> sharedObjects = new HashMap<>();
sharedObjects.putAll(this.localConfigureAuthenticationBldr.getSharedObjects());
sharedObjects.put(UserDetailsService.class, userDetailsService());
sharedObjects.put(ApplicationContext.class, this.context);
sharedObjects.put(ContentNegotiationStrategy.class, this.contentNegotiationStrategy);
sharedObjects.put(AuthenticationTrustResolver.class, this.trustResolver);
return sharedObjects;
而对于SecurityConfigurer
的添加主要是使用apply()
方法:
public <C extends SecurityConfigurer<O, B>> C apply(C configurer) throws Exception
add(configurer);
return configurer;
3、SecurityConfigurer
public interface SecurityConfigurer<O, B extends SecurityBuilder<O>>
void init(B builder) throws Exception;
void configure(B builder) throws Exception;
其主要是两个方法,一个就是先init
产生化,另一个就是configure
,也就是通过configure
方法来设置SecurityBuilder
中的内容。
下面我们来看下WebSecurity
的构建,以及通过其来产生FilterChainProxy
:
@Autowired(required = false)
public void setFilterChainProxySecurityConfigurer(ObjectPostProcessor<Object> objectPostProcessor,
@Value("#@autowiredWebSecurityConfigurersIgnoreParents.getWebSecurityConfigurers()") List<SecurityConfigurer<Filter, WebSecurity>> webSecurityConfigurers)
throws Exception
this.webSecurity = objectPostProcessor.postProcess(new WebSecurity(objectPostProcessor));
if (this.debugEnabled != null)
this.webSecurity.debug(this.debugEnabled);
..........
for (SecurityConfigurer<Filter, WebSecurity> webSecurityConfigurer : webSecurityConfigurers)
this.webSecurity.apply(webSecurityConfigurer);
this.webSecurityConfigurers = webSecurityConfigurers;
这里我们看到入参有webSecurityConfigurers(List<SecurityConfigurer)
,而我们当前有添加一个WebSecurityConfigurerAdapter
, 其是继承与WebSecurityConfigurerAdapter
,可以看到其是属于SecurityConfigurer
,我们能通过其来进行对应的属性拓展
然后就是通过this.webSecurity.apply(webSecurityConfigurer)
来添加到configurers
中
4、构建Filter(FilterChainProxy)
@Configuration(proxyBeanMethods = false)
public class WebSecurityConfiguration implements ImportAware, BeanClassLoaderAware
private WebSecurity webSecurity;
.....
private List<SecurityConfigurer<Filter, WebSecurity>> webSecurityConfigurers;
private List<SecurityFilterChain> securityFilterChains = Collections.emptyList();
@Bean(name = AbstractSecurityWebApplicationInitializer.DEFAULT_FILTER_NAME)
public Filter springSecurityFilterChain() throws Exception
........
return this.webSecurity.build();
@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");
public abstract class AbstractConfiguredSecurityBuilder<O, B extends SecurityBuilder<O>>
extends AbstractSecurityBuilder<O>
...........
@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;
这里的init()
,就是遍历configurers
进行初始化:
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);
再通过configure()
遍历执行configurers
的configurer
方法:
private void configure() throws Exception
Collection<SecurityConfigurer<O, B>> configurers = getConfigurers();
for (SecurityConfigurer<O, B> configurer : configurers)
configurer.configure((B) this);
例如我们当前添加了自定义的SecurityConfiguration
:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-S5cLdHCB-1638686018792)(F:\\MarkDown-File\\知识点资料\\Untitled.assets\\image-20211204230515150.png)]
这里还有beforeConfigure()
方法,例如HttpSecurity
对其的实现:
@Override
protected void beforeConfigure() throws Exception
setSharedObject(AuthenticationManager.class, getAuthenticationRegistry().build());
添加认证管理器。对于SecurityConfigurer
的实现类来说,其主要是设置填充各种类对象例如我们当前填充了``UserDetailsService,以及属于
SpringSecurity的
Filter`。
5、HttpSecurity构建
对于HttpSecurity
的构建,其是在WebSecurity
下构建的:
public abstract class WebSecurityConfigurerAdapter implements WebSecurityConfigurer<WebSecurity>
...........
@Override
public void init(WebSecurity web) throws Exception
HttpSecurity http = getHttp();
web.addSecurityFilterChainBuilder(http).postBuildAction(() ->
FilterSecurityInterceptor securityInterceptor = http.getSharedObject(FilterSecurityInterceptor.class);
web.securityInterceptor(securityInterceptor);
);
我们看到其是在前面doBuild()
遍历调用init
调用的。创建后,通过web.addSecurityFilterChainBuilder(http)
添加到WebSecurity
中。而定义对于HttpSecurity
,其主要会通过SecurityConfigurer
来添加各种Filter
public final class HttpSecurity extends AbstractConfiguredSecurityBuilder<DefaultSecurityFilterChain, HttpSecurity>
implements SecurityBuilder<DefaultSecurityFilterChain>, HttpSecurityBuilder<HttpSecurity>
private final RequestMatcherConfigurer requestMatcherConfigurer;
private List<OrderedFilter> filters = new ArrayList<>();
private RequestMatcher requestMatcher = AnyRequestMatcher.INSTANCE;
private FilterOrderRegistration filterOrders = new FilterOrderRegistration();
protected final HttpSecurity getHttp() throws Exception
if (this.http != null)
return this.http;
........
AuthenticationManager authenticationManager = authenticationManager();
this.authenticationBuilder.parentAuthenticationMan以上是关于SpringSecurity原理分析的主要内容,如果未能解决你的问题,请参考以下文章
[SpringSecurity]web权限方案_自动登陆_原理分析和具体实现