Spring Security3是目前使用非常广泛的java web安全框架,我经历的项目中有很多在使用它。尽管有shiro等使用更方便、更容易理解、应用范围更广的安全框架开始流行,但Spring Security3在Java web领域无疑是更强大、更容易扩展的。
对Spring Security3配置、应用的blog很多,我就不再介绍这些了。此系列文章主要根据我学习Spring Security3的过程,沿着Filter链介绍Spring Security3的原理。
启用Spring Security3需要做如下三件事:
1、在web.xml配置配置过滤器DelegatingFilterProxy
<filter>
<filter-name>springSecurityFilterChain</filter-name>
<filterclass>
org.springframework.web.filter.DelegatingFilterProxy
</filter-class>
</filter>
<filter-mapping>
<filter-name>springSecurityFilterChain</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
这里filter的名字必须是springSecurityFilterChain,原因稍后解释。
2、新建spring-sucirity.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans:beans xmlns="http://www.springframework.org/schema/security"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:beans="http://www.springframework.org/schema/beans"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/security
http://www.springframework.org/schema/security/
spring-security-3.0.xsd">
<http auto-config="true">
<intercept-url pattern="/*" access="ROLE_USER"/>
</http>
<authentication-manager alias="authenticationManager">
<authentication-provider>
<user-service>
<user authorities="ROLE_USER" name="guest" password="guest"/>
</user-service>
</authentication-provider>
</authentication-manager>
</beans:beans>
3、添加spring-security.xml到web.xml
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath*:/spring-security.xml</param-value>
</context-param>
下面开始从入DelegatingFilterProxy手:
从名字上可以看出,这个过滤器其实没做什么,只是委派给了其他过滤器。它并不在spring-security包中,而是在spring-web包
看它的doFilter方法
public void doFilter(ServletRequest request, ServletResponse response, FilterChain filterChain)
throws ServletException, IOException {
// Lazily initialize the delegate if necessary.
Filter delegateToUse = null;
synchronized (this.delegateMonitor) {
if (this.delegate == null) {
WebApplicationContext wac = findWebApplicationContext();
if (wac == null) {
throw new IllegalStateException("No WebApplicationContext found: no ContextLoaderListener registered?");
}
//初始化FilterChain代理
this.delegate = initDelegate(wac);
}
delegateToUse = this.delegate;
}
// Let the delegate perform the actual doFilter operation.
//调用doFilter方法
invokeDelegate(delegateToUse, request, response, filterChain);
}
分析initDelegate方法
protected Filter initDelegate(WebApplicationContext wac) throws ServletException {
Filter delegate = wac.getBean(getTargetBeanName(), Filter.class);
if (isTargetFilterLifecycle()) {
delegate.init(getFilterConfig());
}
return delegate;
}
getTargetBeanName()其实获取到的是Filter名字springSecurityFilterChain:在initFilterBean()方法中对targetBeanName做了赋值
protected void initFilterBean() throws ServletException {
// If no target bean name specified, use filter name.
if (this.targetBeanName == null) {
//targetBeanName被设置为filterName
this.targetBeanName = getFilterName();
}
......
}
initFilterBean方法在父类GenericFilterBean的init方法中被执行。
这里根据我们在web.xml设置filter的名字去获取Spring Seucurity3的代理过滤器。后面回看到这个名字是springSecurityFilterChain,所以在web.xml的filter名字也必须是这个。
再分析spring-scurity.xml的解析:
org.springframework.security.config.SecurityNamespaceHandler负责解析namespace为security的xml文档,即我们的spring-security.xml文件,它在spring-security-config包:
SecurityNamespaceHandler继承了NamespaceHandler接口,有三个方法:init初始化,parse解析,decorate装饰,在SecurityNamespaceHandler的init方法进行了每个解析类的注册
private void loadParsers() {
// Parsers
parsers.put(Elements.LDAP_PROVIDER, new LdapProviderBeanDefinitionParser());
parsers.put(Elements.LDAP_SERVER, new LdapServerBeanDefinitionParser());
parsers.put(Elements.LDAP_USER_SERVICE, new LdapUserServiceBeanDefinitionParser());
parsers.put(Elements.USER_SERVICE, new UserServiceBeanDefinitionParser());
parsers.put(Elements.JDBC_USER_SERVICE, new JdbcUserServiceBeanDefinitionParser());
parsers.put(Elements.AUTHENTICATION_PROVIDER, new AuthenticationProviderBeanDefinitionParser());
parsers.put(Elements.GLOBAL_METHOD_SECURITY, new GlobalMethodSecurityBeanDefinitionParser());
parsers.put(Elements.AUTHENTICATION_MANAGER, new AuthenticationManagerBeanDefinitionParser());
// Only load the web-namespace parsers if the web classes are available
if (ClassUtils.isPresent("org.springframework.security.web.FilterChainProxy", getClass().getClassLoader())) {
parsers.put(Elements.HTTP, new HttpSecurityBeanDefinitionParser());
parsers.put(Elements.HTTP_FIREWALL, new HttpFirewallBeanDefinitionParser());
parsers.put(Elements.FILTER_INVOCATION_DEFINITION_SOURCE, new FilterInvocationSecurityMetadataSourceParser());
parsers.put(Elements.FILTER_SECURITY_METADATA_SOURCE, new FilterInvocationSecurityMetadataSourceParser());
filterChainMapBDD = new FilterChainMapBeanDefinitionDecorator();
}
}
HttpSecurityBeanDefinitionParser时解析http节点的解析类
parsers.put(Elements.HTTP, new HttpSecurityBeanDefinitionParser());
看一下HttpSecurityBeanDefinitionParser是如何解析http节点的,上parse
public BeanDefinition parse(Element element, ParserContext pc) {
CompositeComponentDefinition compositeDef =
new CompositeComponentDefinition(element.getTagName(), pc.extractSource(element));
pc.pushContainingComponent(compositeDef);
final Object source = pc.extractSource(element);
final String portMapperName = createPortMapper(element, pc);
final UrlMatcher matcher = createUrlMatcher(element);
HttpConfigurationBuilder httpBldr = new HttpConfigurationBuilder(element, pc, matcher, portMapperName);
httpBldr.parseInterceptUrlsForEmptyFilterChains();
httpBldr.createSecurityContextPersistenceFilter();
httpBldr.createSessionManagementFilters();
ManagedList<BeanReference> authenticationProviders = new ManagedList<BeanReference>();
BeanReference authenticationManager = createAuthenticationManager(element, pc, authenticationProviders, null);
httpBldr.createServletApiFilter();
httpBldr.createChannelProcessingFilter();
httpBldr.createFilterSecurityInterceptor(authenticationManager);
AuthenticationConfigBuilder authBldr = new AuthenticationConfigBuilder(element, pc,
httpBldr.isAllowSessionCreation(), portMapperName);
//http节点的默认的11个过滤器
authBldr.createAnonymousFilter();
authBldr.createRememberMeFilter(authenticationManager);
authBldr.createRequestCache();
authBldr.createBasicFilter(authenticationManager);
authBldr.createFormLoginFilter(httpBldr.getSessionStrategy(), authenticationManager);
authBldr.createOpenIDLoginFilter(httpBldr.getSessionStrategy(), authenticationManager);
authBldr.createX509Filter(authenticationManager);
authBldr.createLogoutFilter();
authBldr.createLoginPageFilterIfNeeded();
authBldr.createUserServiceInjector();
authBldr.createExceptionTranslationFilter();
List<OrderDecorator> unorderedFilterChain = new ArrayList<OrderDecorator>();
//将过滤器加入过滤器链
unorderedFilterChain.addAll(httpBldr.getFilters());
unorderedFilterChain.addAll(authBldr.getFilters());//这里加入的过滤器和我们设置auto-config="true"有关
authenticationProviders.addAll(authBldr.getProviders());
BeanDefinition requestCacheAwareFilter = new RootBeanDefinition(RequestCacheAwareFilter.class);
requestCacheAwareFilter.getPropertyValues().addPropertyValue("requestCache", authBldr.getRequestCache());
unorderedFilterChain.add(new OrderDecorator(requestCacheAwareFilter, REQUEST_CACHE_FILTER));
unorderedFilterChain.addAll(buildCustomFilterList(element, pc));
//对过滤器进行排序
Collections.sort(unorderedFilterChain, new OrderComparator());
checkFilterChainOrder(unorderedFilterChain, pc, source);
//排好序的过滤器链
List<BeanMetadataElement> filterChain = new ManagedList<BeanMetadataElement>();
for (OrderDecorator od : unorderedFilterChain) {
filterChain.add(od.bean);
}
ManagedMap<Object, List<BeanMetadataElement>> filterChainMap = httpBldr.getFilterChainMap();
filterChainMap.put(matcher.getUniversalMatchPattern(), filterChain);
//注册过滤器链proxy
registerFilterChainProxy(pc, filterChainMap, matcher, source);
pc.popAndRegisterContainingComponent();
return null;
}
http节点的11个过滤器不是都要加入过滤器链的,这个和我们的auto-config有关。使用auto-config="true"会自动提供以下三个认证相关的功能:
HTTP基本认证
Form登录认证
退出
这一点从源码中可以找到:AuthenticationConfigBuilder类的createLogoutFilter、createBasicFilter和createFormLoginFilter三个方法
void createLogoutFilter() {
Element logoutElt = DomUtils.getChildElementByTagName(httpElt, Elements.LOGOUT);
if (logoutElt != null || autoConfig) {
logoutFilter = new LogoutBeanDefinitionParser(rememberMeServicesId).parse(logoutElt, pc);
}
}
void createBasicFilter(BeanReference authManager) {
......
if (basicAuthElt != null || autoConfig) {
......
}
......
}
void createFormLoginFilter(BeanReference sessionStrategy, BeanReference authManager) {
......
if (formLoginElt != null || autoConfig) {
......
}
......
}
可见只有autoConfig=true
时才会加入这仨过滤器。
在对unorderedFilterChain进行排序时,这11个过滤器怎么排序的呢?org.springframework.core.OrderComparator的排序逻辑是根据org.springframework.core.Ordered的getOrder方法的比较。在AuthenticationConfigBuilder的getFilters方法返回的事List<OrderDecorator>集合,OrderDecorator的构造方法:
public OrderDecorator(BeanMetadataElement bean, SecurityFilters filterOrder) {
this.bean = bean;
this.order = filterOrder.getOrder();
}
继续看SecurityFilters枚举类
enum SecurityFilters {
FIRST (Integer.MIN_VALUE),
CHANNEL_FILTER,
CONCURRENT_SESSION_FILTER,
SECURITY_CONTEXT_FILTER,
LOGOUT_FILTER,
X509_FILTER,
PRE_AUTH_FILTER,
CAS_FILTER,
FORM_LOGIN_FILTER,
OPENID_FILTER,
LOGIN_PAGE_FILTER,
DIGEST_AUTH_FILTER,
BASIC_AUTH_FILTER,
REQUEST_CACHE_FILTER,
SERVLET_API_SUPPORT_FILTER,
REMEMBER_ME_FILTER,
ANONYMOUS_FILTER,
SESSION_MANAGEMENT_FILTER,
EXCEPTION_TRANSLATION_FILTER,
FILTER_SECURITY_INTERCEPTOR,
SWITCH_USER_FILTER,
LAST (Integer.MAX_VALUE);
private static final int INTERVAL = 100;
private final int order;
private SecurityFilters() {
order = ordinal() * INTERVAL;
}
private SecurityFilters(int order) {
this.order = order;
}
public int getOrder() {
return order;
}
}
可见是根据枚举的定义进行排序的,在http节点的配置中,我们将自定一个的过滤器用before、after、position等关键字插入到这11个过滤器前后。
再看注册过滤器链:
private void registerFilterChainProxy(ParserContext pc, Map<Object, List<BeanMetadataElement>> filterChainMap, UrlMatcher matcher, Object source) {
if (pc.getRegistry().containsBeanDefinition(BeanIds.FILTER_CHAIN_PROXY)) {
pc.getReaderContext().error("Duplicate <http> element detected", source);
}
//定义一个FilterChainProxy
BeanDefinitionBuilder fcpBldr = BeanDefinitionBuilder.rootBeanDefinition(FilterChainProxy.class);
fcpBldr.getRawBeanDefinition().setSource(source);
fcpBldr.addPropertyValue("matcher", matcher);
fcpBldr.addPropertyValue("stripQueryStringFromUrls", Boolean.valueOf(matcher instanceof AntUrlPathMatcher));
fcpBldr.addPropertyValue("filterChainMap", filterChainMap);//设置过滤器链集合
BeanDefinition fcpBean = fcpBldr.getBeanDefinition();
//注册bean
pc.registerBeanComponent(new BeanComponentDefinition(fcpBean, BeanIds.FILTER_CHAIN_PROXY));
//注册的别名为springSecurityFilterChain,在web.xml配置的filter名也要是这个
pc.getRegistry().registerAlias(BeanIds.FILTER_CHAIN_PROXY, BeanIds.SPRING_SECURITY_FILTER_CHAIN);
}
那么在DelegatingFilterProxy的initDelegate方法就可以获取到这个过滤器链了,然后就是doFilter了。
好了,囫囵吞枣的列出这么多,也不是很连贯,但大概应该能说明白原理了。下一篇开始分析过滤器,所以再把过滤器列出来:
过滤器名称
|
描述
|
o.s.s.web.context.SecurityContextPersistenceFilter
|
负责从SecurityContextRepository获取或存储SecurityContext。SecurityContext代表了用户安全和认证过的session。
|
o.s.s.web.authentication.logout.LogoutFilter
|
监控一个实际为退出功能的URL(默认为/j_spring_security_logout),并且在匹配的时候完成用户的退出功能。
|
o.s.s.web.authentication.UsernamePasswordAuthenticationFilter
|
监控一个使用用户名和密码基于form认证的URL(默认为/j_spring_security_check),并在URL匹配的情况下尝试认证该用户。
|
o.s.s.web.authentication.ui.DefaultLoginPageGeneratingFilter
|
监控一个要进行基于forn或OpenID认证的URL(默认为/spring_security_login),并生成展现登录form的HTML
|
o.s.s.web.authentication.www.BasicAuthenticationFilter
|
监控HTTP 基础认证的头信息并进行处理
|
o.s.s.web.savedrequest.
RequestCacheAwareFilter
|
用于用户登录成功后,重新恢复因为登录被打断的请求。
|
o.s.s.web.servletapi.
SecurityContextHolderAwareRequest
Filter
|
用一个扩展了HttpServletRequestWrapper的子类(o.s.s.web. servletapi.SecurityContextHolderAwareRequestWrapper)包装HttpServletRequest。它为请求处理器提供了额外的上下文信息。
|
o.s.s.web.authentication.
AnonymousAuthenticationFilter
|
如果用户到这一步还没有经过认证,将会为这个请求关联一个认证的token,标识此用户是匿名的。
|
o.s.s.web.session.
SessionManagementFilter
|
根据认证的安全实体信息跟踪session,保证所有关联一个安全实体的session都能被跟踪到。
|
o.s.s.web.access.
ExceptionTranslationFilter
|
解决在处理一个请求时产生的指定异常
|
o.s.s.web.access.intercept.
FilterSecurityInterceptor
|
简化授权和访问控制决定,委托一个AccessDecisionManager完成授权的判断
|
- 大小: 20.9 KB
- 大小: 10.3 KB
分享到:
相关推荐
《Spring Security Web源码解析与...在Web应用中,Spring Security通过过滤器链来实现安全控制,这些过滤器包括但不限于:`DelegatingRequestMatcherFilter`,`SecurityContextPersistenceFilter`,`LogoutFilter`,`...
3. **过滤器链**:Spring Security 的核心是Filter Security Interceptor(过滤器安全拦截器)和Access Decision Manager(访问决策管理器)。过滤器链处理HTTP请求,进行身份验证和授权检查,而访问决策管理器根据...
3. **Filter Chain**:Spring Security通过一系列过滤器(Filter)实现请求的拦截和处理。在3.1.0.RC1中,这些过滤器如`DelegatingFilterProxy`、`ChannelProcessingFilter`、`SecurityContextPersistenceFilter`等...
在"SpringSecurity笔记2-SpringSecurity命名空间"的学习中,还会涉及到如何自定义过滤器链,以及如何通过`<custom-filter>`元素插入自定义的SpringSecurity过滤器。同时,理解`<access-denied-handler>`和`...
- `spring-security-web-4.0.0.CI-SNAPSHOT.jar`:处理HTTP请求的安全过滤器,如CSRF防护、登录、注销、会话管理等。 3. **spring-security-config**: - `spring-security-config-4.0.0.CI-SNAPSHOT-javadoc.jar...
8. **自定义过滤器**:在Spring Security中,我们还可以通过添加自定义过滤器来扩展其功能。例如,创建一个实现`FilterSecurityInterceptor`的过滤器,以便在用户请求到达控制器之前进行额外的权限检查。 9. **异常...
4. **Filter Chain**:Spring Security的核心在于一系列的过滤器,它们按照预定义的顺序执行,构成Filter Chain。`org.springframework.security.web`包下的Filter如FilterSecurityInterceptor、...
Spring Security是一个功能强大且高度可定制的身份验证和授权框架,专门用于保护Java应用程序的...Web集成:Spring Security能够无缝集成到Spring框架和Spring MVC中,提供了过滤器、标签库等工具,简化了权限控制和
3. spring-security-web-4.2.3.RELEASE.jar:此模块专注于Web应用的安全需求,提供了一套过滤器链来处理HTTP请求的安全方面。它包含了诸如`FilterSecurityInterceptor`(执行访问决策)和`...
3. **过滤器链**:Spring Security的核心是其过滤器链,包括登录过滤器、CSRF保护、会话管理等。这些过滤器按照特定顺序执行,确保每个请求都经过安全检查。 4. **会话管理**:Spring Security可以实现会话固定保护...
1. **Filter Chain**:Spring Security通过一系列过滤器实现其功能,这些过滤器按照特定顺序组织成一个过滤链。每个过滤器负责处理请求的特定方面,如认证、授权等。 2. **AuthenticationManager**:这是Spring ...
它提供HTTP安全拦截过滤器链,如`DelegatingFilterProxy`,可以与Spring的DispatcherServlet集成。 4. **spring-security-acl**:这个模块提供了细粒度访问控制,允许对对象级别的权限进行管理。例如,你可以控制...
- **Filter Security Interceptor (FSI)**: 一系列Spring MVC过滤器,负责处理HTTP请求的安全性。 - **Security Context**: 存储当前用户的认证信息。 - **Authentication Manager**: 处理身份验证请求,验证用户...
Spring Security 过滤器链机制和特性详解 Spring Security 过滤器链是 Spring Security 框架中的一种核心机制,负责处理 HTTP 请求的安全验证和授权。今天,我们将深入探讨 Spring Security 过滤器链的机制和特性,...
2. **spring-security-web-3.1.3.RELEASE.jar**:此模块关注于Web安全,提供了过滤器链来处理HTTP请求的安全性。例如,它包含RememberMe服务、HTTP基本和表单登录、CSRF防护以及URL级别的访问控制等功能。 3. **...
- **ResourceServerFilter**:资源服务器上的过滤器,验证访问令牌的有效性。 4. **OAuth2的工作流程** 1. 客户端引导用户前往授权服务器进行授权。 2. 用户同意授权后,授权服务器返回授权码或访问令牌。 3. ...
3. **过滤器链(Filter Chain)**:Spring Security的核心组件之一是过滤器链,它由多个过滤器组成,如`UsernamePasswordAuthenticationFilter`和`HttpSessionAuthenticationStrategy`等。这些过滤器负责处理HTTP...
3. **过滤器链**:Spring Security的核心在于其过滤器链,它拦截HTTP请求并应用安全策略。`FilterSecurityInterceptor`是其中的关键组件,负责根据配置的访问规则对请求进行处理。 4. **会话管理**:Spring ...
Spring Security 是一个强大的和高度可定制的身份验证和访问控制框架,用于Java应用程序...通过逐步学习和实践,可以掌握更复杂的授权策略和高级功能,如角色层次、自定义过滤器、OAuth2整合等,以满足实际项目的需求。