Spring Security 入门(1-6-1)Spring Security - 配置文件解析和访问请求处理
1.在pom.xml中添加maven坐标
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-config</artifactId>
<version>4.0.3.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-core</artifactId>
<version>4.0.3.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-web</artifactId>
<version>4.0.3.RELEASE</version>
</dependency>
2.在web.xml中添加如下配置
<filter>
<filter-name>springSecurityFilterChain</filter-name>
<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
</filter>
<filter-mapping>
<filter-name>springSecurityFilterChain</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
注意filter-name一定要写成springSecurityFilterChain。在DelegatingFilterProxy类init时,如果没有配置targetBeanName,默认会通过filter-name去spring中获取代理的bean。
protected Filter initDelegate(WebApplicationContext wac) throws ServletException {
Filter delegate = wac.getBean(getTargetBeanName(), Filter.class);
if (isTargetFilterLifecycle()) {
delegate.init(getFilterConfig());
}
return delegate;
}
而spring-security的配置是由HttpSecurityBeanDefinitionParser解析器解析,
每一个http都会被解析成一个SecurityFilterChain都添加到FilterChainProxy中的filterChains中。而且该FilterChainProxy会以springSecurityFilterChain注册到spring的bean中。
public BeanDefinition parse(Element element, ParserContext pc) {
CompositeComponentDefinition compositeDef = new CompositeComponentDefinition(element.getTagName(), pc.extractSource(element));
pc.pushContainingComponent(compositeDef);
registerFilterChainProxyIfNecessary(pc, pc.extractSource(element));
BeanDefinition listFactoryBean = pc.getRegistry().getBeanDefinition("org.springframework.security.filterChains");
List filterChains = (List)listFactoryBean.getPropertyValues().getPropertyValue("sourceList").getValue();
filterChains.add(this.createFilterChain(element, pc));
pc.popAndRegisterContainingComponent();
return null;
}
static void registerFilterChainProxyIfNecessary(ParserContext pc, Object source) {
if(!pc.getRegistry().containsBeanDefinition("org.springframework.security.filterChainProxy")) {
RootBeanDefinition listFactoryBean = new RootBeanDefinition(ListFactoryBean.class);
listFactoryBean.getPropertyValues().add("sourceList", new ManagedList());
pc.registerBeanComponent(new BeanComponentDefinition(listFactoryBean, "org.springframework.security.filterChains"));
BeanDefinitionBuilder fcpBldr = BeanDefinitionBuilder.rootBeanDefinition(FilterChainProxy.class);
fcpBldr.getRawBeanDefinition().setSource(source);
fcpBldr.addConstructorArgReference("org.springframework.security.filterChains");
fcpBldr.addPropertyValue("filterChainValidator", new RootBeanDefinition(DefaultFilterChainValidator.class));
AbstractBeanDefinition fcpBean = fcpBldr.getBeanDefinition();
pc.registerBeanComponent(new BeanComponentDefinition(fcpBean, "org.springframework.security.filterChainProxy"));
pc.getRegistry().registerAlias("org.springframework.security.filterChainProxy", "springSecurityFilterChain");
}
}
3.spring-security配置文件
<?xml version="1.0" encoding="UTF-8"?>
<beans:beans xmlns="http://www.springframework.org/schema/security"
xmlns:beans="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.2.xsd
http://www.springframework.org/schema/security
http://www.springframework.org/schema/security/spring-security-4.0.xsd ">
<!-- 静态资源,不用权限 -->
<http pattern="/resources/**" security="none"/>
<http pattern="/verify/**" security="none"/>
<http pattern="/user/login.htm" security="none"/>
<http pattern="/user/register.*" security="none"/>
<http pattern="/favicon.ico" security="none"/>
<http use-expressions="true" auto-config="false" entry-point-ref="authenticationProcessingFilterEntryPoint">
<intercept-url pattern="/**" access="authenticated"/>
<!--
<form-login login-page="/user/login.htm" login-processing-url="/login.json" username-parameter="userName"
default-target-url="/user/index.htm" always-use-default-target="true"
authentication-success-handler-ref="authenticationSuccessHandler"
authentication-failure-handler-ref="authenticationFailureHandler"/>
-->
<logout invalidate-session="true" logout-url="/logout" logout-success-url="/"/>
<csrf disabled="true"/>
<custom-filter ref="loginFilter" position="FORM_LOGIN_FILTER"/>
</http>
<beans:bean id="authenticationProcessingFilterEntryPoint" class="org.springframework.security.web.authentication.LoginUrlAuthenticationEntryPoint">
<beans:constructor-arg name="loginFormUrl" value="/user/login.htm" />
</beans:bean>
<authentication-manager alias="authenticationManager">
<authentication-provider ref="daoAuthenticationProvider" />
</authentication-manager>
<beans:bean id="daoAuthenticationProvider" class="org.springframework.security.authentication.dao.DaoAuthenticationProvider">
<!-- 是否顯示用戶名不存在信息 -->
<beans:property name="hideUserNotFoundExceptions" value="false"/>
<beans:property name="userDetailsService" ref="userDetailsService"/>
<beans:property name="passwordEncoder" ref="md5Encoder"/>
<beans:property name="saltSource" ref="saltSource"/>
</beans:bean>
<beans:bean id="md5Encoder" class="org.springframework.security.authentication.encoding.Md5PasswordEncoder" />
<!-- 配置自定义过滤器 -->
<beans:bean id="loginFilter" class="com.test.security.LoginFilter">
<beans:property name="filterProcessesUrl" value="/login.json"/>
<beans:property name="usernameParameter" value="userName"/>
<beans:property name="authenticationManager" ref="authenticationManager"/>
<beans:property name="authenticationSuccessHandler" ref="authenticationSuccessHandler"/>
<beans:property name="authenticationFailureHandler" ref="authenticationFailureHandler"/>
</beans:bean>
</beans:beans>
4、启动时候的配置文件解析-每个http解析为一个filterChain。
程序在启动的时候会遍历解析spring-security配置文件,当命名空间是<http>的时候就使用HttpSecurityBeanDefinitionParser类来解析。
private BeanReference createFilterChain(Element element, ParserContext pc) {
boolean secured = !"none".equals(element.getAttribute("security"));
if(!secured) {
if(!StringUtils.hasText(element.getAttribute("pattern")) && !StringUtils.hasText("request-matcher-ref")) {
pc.getReaderContext().error("The \'security\' attribute must be used in combination with the \'pattern\' or \'request-matcher-ref\' attributes.", pc.extractSource(element));
}
for(int var15 = 0; var15 < element.getChildNodes().getLength(); ++var15) {
if(element.getChildNodes().item(var15) instanceof Element) {
pc.getReaderContext().error("If you are using <http> to define an unsecured pattern, it cannot contain child elements.", pc.extractSource(element));
}
}
return this.createSecurityFilterChainBean(element, pc, Collections.emptyList());
}
else
{
BeanReference portMapper = this.createPortMapper(element, pc);
RuntimeBeanReference portResolver = this.createPortResolver(portMapper, pc);
ManagedList authenticationProviders = new ManagedList();
BeanReference authenticationManager = this.createAuthenticationManager(element, pc, authenticationProviders);
boolean forceAutoConfig = isDefaultHttpConfig(element);
HttpConfigurationBuilder httpBldr = new HttpConfigurationBuilder(element, forceAutoConfig, pc, portMapper, portResolver, authenticationManager);
AuthenticationConfigBuilder authBldr = new AuthenticationConfigBuilder(element, forceAutoConfig, pc, httpBldr.getSessionCreationPolicy(), httpBldr.getRequestCache(), authenticationManager, httpBldr.getSessionStrategy(), portMapper, portResolver, httpBldr.getCsrfLogoutHandler());
httpBldr.setLogoutHandlers(authBldr.getLogoutHandlers());
httpBldr.setEntryPoint(authBldr.getEntryPointBean());
httpBldr.setAccessDeniedHandler(authBldr.getAccessDeniedHandlerBean());
authenticationProviders.addAll(authBldr.getProviders());
ArrayList unorderedFilterChain = new ArrayList();
unorderedFilterChain.addAll(httpBldr.getFilters());
unorderedFilterChain.addAll(authBldr.getFilters());
unorderedFilterChain.addAll(this.buildCustomFilterList(element, pc));
Collections.sort(unorderedFilterChain, new OrderComparator());
this.checkFilterChainOrder(unorderedFilterChain, pc, pc.extractSource(element));
ManagedList filterChain = new ManagedList();
Iterator var13 = unorderedFilterChain.iterator();
while(var13.hasNext()) {
OrderDecorator od = (OrderDecorator)var13.next();
filterChain.add(od.bean);
}
return this.createSecurityFilterChainBean(element, pc, filterChain);
}
}
当发现security="none"的时候,则创建一个DefaultFilterChain添加到FilterChainProxy的filterChains属性中。
当没有security="none"则使用else中的代码。
特别注意HttpConfigurationBuilder httpBldr = new HttpConfigurationBuilder(element, forceAutoConfig, pc, portMapper, portResolver, authenticationManager);
最后添加到filterChains中。
5、运行时-根据请求url获得过滤器链--找到第一个匹配的filterChain处理请求?????????
spring-security执行则是依据请求的URL获得过滤器链。然后依次执行。
private void doFilterInternal(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException {
FirewalledRequest fwRequest = firewall
.getFirewalledRequest((HttpServletRequest) request);
HttpServletResponse fwResponse = firewall
.getFirewalledResponse((HttpServletResponse) response);
List<Filter> filters = getFilters(fwRequest);
if (filters == null || filters.size() == 0)
{
if (logger.isDebugEnabled())
{
logger.debug(UrlUtils.buildRequestUrl(fwRequest)+ (filters == null ? " has no matching filters": " has an empty filter list"));
}
fwRequest.reset();
chain.doFilter(fwRequest, fwResponse);
return;
}
VirtualFilterChain vfc = new VirtualFilterChain(fwRequest, chain, filters);
vfc.doFilter(fwRequest, fwResponse);
}
/**
* Returns the first filter chain matching the supplied URL.
*
* @param request the request to match
* @return an ordered array of Filters defining the filter chain
*/
private List<Filter> getFilters(HttpServletRequest request)
{
for (SecurityFilterChain chain : filterChains)
{
if (chain.matches(request))
{
return chain.getFilters();
}
}
return null;
}
public void doFilter(ServletRequest request, ServletResponse response)
throws IOException, ServletException {
if (currentPosition == size) {
if (logger.isDebugEnabled()) {
logger.debug(UrlUtils.buildRequestUrl(firewalledRequest)
+ " reached end of additional filter chain; proceeding with original chain");
}
// Deactivate path stripping as we exit the security filter chain
this.firewalledRequest.reset();
originalChain.doFilter(request, response);
}
else {
currentPosition++;
Filter nextFilter = additionalFilters.get(currentPosition - 1);
if (logger.isDebugEnabled()) {
logger.debug(UrlUtils.buildRequestUrl(firewalledRequest)
+ " at position " + currentPosition + " of " + size
+ " in additional filter chain; firing Filter: '"
+ nextFilter.getClass().getSimpleName() + "'");
}
nextFilter.doFilter(request, response, this);
}
}
整个spring-security理解起来其实并不难。但要融入到程序中合理使用,还需要多练习。
Spring Security 入门(1-6-1)Spring Security - 配置文件解析和访问请求处理的更多相关文章
- 【转】Spring Boot干货系列:(二)配置文件解析
转自:Spring Boot干货系列:(二)配置文件解析 前言 上一篇介绍了Spring Boot的入门,知道了Spring Boot使用"习惯优于配置"(项目中存在大量的配置,此 ...
- Spring Boot干货系列:(二)配置文件解析
Spring Boot干货系列:(二)配置文件解析 2017-02-28 嘟嘟MD 嘟爷java超神学堂 前言 上一篇介绍了Spring Boot的入门,知道了Spring Boot使用“习惯优于 ...
- Spring Security 入门(1-7)Spring Security - Session管理
参考链接:https://xueliang.org/article/detail/20170302232815082 session 管理 Spring Security 通过 http 元素下的子元 ...
- Spring Security 入门(1-3-5)Spring Security - remember me!
Remember-Me 功能 概述 Remember-Me 是指网站能够在 Session 之间记住登录用户的身份,具体来说就是我成功认证一次之后在一定的时间内我可以不用再输入用户名和密码进行登录了, ...
- Spring Security 入门(1-6-2)Spring Security - 内置的filter顺序、自定义filter、http元素和对应的filterChain
Spring Security 的底层是通过一系列的 Filter 来管理的,每个 Filter 都有其自身的功能,而且各个 Filter 在功能上还有关联关系,所以它们的顺序也是非常重要的. 1.S ...
- Spring Security 入门(1-3-2)Spring Security - http元素 - intercept-url配置
http元素下可以配置登录页面,也可以配置 url 拦截. 1.直接配置拦截url和对应的访问权限 <security:http use-expressions="false" ...
- Spring Security 入门(1-4-2)Spring Security - 认证过程之AuthenticationProvider的扩展补充说明
1.用户信息从数据库获取 通常我们的用户信息都不会向第一节示例中那样简单的写在配置文件中,而是从其它存储位置获取,比如数据库.根据之前的介绍我们知道用户信息是通过 UserDetailsService ...
- Spring Security 入门(1-3-1)Spring Security - http元素 - 默认登录和登录定制
登录表单配置 - http 元素下的 form-login 元素是用来定义表单登录信息的.当我们什么属性都不指定的时候 Spring Security 会为我们生成一个默认的登录页面. 如果不想使用默 ...
- Spring Security 入门(1-2)Spring Security - 从 配置例子例子 开始我们的学习历程
1.Spring Security 的配置文件 我们需要为 Spring Security 专门建立一个 Spring 的配置文件,该文件就专门用来作为 Spring Security 的配置. &l ...
随机推荐
- PHP实现KMP算法
KMP算法是一种比较高效的字符串匹配算法,关于其讲解,可参考文章 字符串匹配的KMP算法,本文只给出具体的PHP代码实现. /** * @desc构建next数组 * @param string $s ...
- C语言第十一次作业--函数嵌套调用
一.实验作业 1.1 PTA题目:递归法对任意10个数据按降序排序 设计思路 定义整型循环变量i,最小值下标min,中间变量t 若n==1,直接返回 否则 min=10-n 最小值下标赋初值 for ...
- curl/libcurl获取打开网页平均网速
CURL: curl -o /dev/null -s -w %{http_code}:%{http_connect}:%{content_type}:%{time_namelookup}:%{time ...
- gif文件解析
详细资料:http://blog.csdn.net/wzy198852/article/details/17266507 MD5:98206F88B84CCC399C840C8EEC902CCF GI ...
- Ubuntu 14.04下Hadoop2.4.1集群安装配置教程
一.环境 系统: Ubuntu 14.04 64bit Hadoop版本: hadoop 2.4.1 (stable) JDK版本: OpenJDK 7 台作为Master,另3台作为Slave. 所 ...
- pureftpd支持php实现图片上传
安装好php后,可安装pureftp工具 这里我给出一个rpm包可直接安装配置:http://pan.baidu.com/s/1i5OhS3r(包括启动脚本在内) FTP测试:安装ftp客户端,用户名 ...
- [css 揭秘]:CSS揭秘 技巧(一):半透明边框
我的github地址:https://github.com/FannieGirl/ifannie/ 源码都在上面哦 喜欢的给我一个星吧 半透明边框 css 中的半透明颜色,比如用 rgba() 和 h ...
- 分布式代码管理系统GIT
1.1Git安装 CentOS上 yum install -y epel-release; yum install git Ubuntu上 apt-get install git Windo ...
- Linux下的进程与线程(二)—— 信号
Linux进程之间的通信: 本文主要讨论信号问题. 在Linux下的进程与线程(一)中提到,调度器可以用中断的方式调度进程. 然而,进程是怎么知道自己需要被调度了呢?是内核通过向进程发送信号,进程才得 ...
- ECEF和大地坐标系的相互转化
在阅读 RTKLIB的源码时,发现了ECEF和大地坐标系的相互转换的函数,大地坐标系(φ,λ,h)转成ECEF(X,Y,Z)与所看书籍(GPS原理与接收机,谢刚,电子工业出版社)的公式是一样的,而EC ...