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 ...
随机推荐
- pdf文件中截取eps图片并压缩
最近遇到了一个问题,需要从pdf裁剪出其中部分的矢量图格式的图片,并保存为eps格式,方便使用. 最简单的方法就是先用acrobat pro将pdf进行页面抽取,并裁剪,剩下所需要的图片部分,然后另存 ...
- ie8兼容圆角
ie8兼容圆角 PIE.HTC下载地址:http://css3pie.com/ 兼容ie8 代码如下: <!DOCTYPE html> <html> <head> ...
- 笔记:JDBC 数据库
数据库 URL 在连接数据库时,我们必须使用各种与数据库类型相关的参数,例如主机名.端口号和数据库名称等,JDBC使用了一种与普通URL相类似的语法来描述数据库,JDBC URL 一般语法为: jdb ...
- CXF 开发 REST 服务
今天我们将视角集中在 REST 上,它是继 SOAP 以后,另一种广泛使用的 Web 服务.与 SOAP 不同,REST 并没有 WSDL 的概念,也没有叫做"信封"的东西,因为 ...
- Linux chgrp命令
在lunix系统里,文件或目录的权限的掌控以拥有者及所诉群组来管理.可以使用chgrp指令取变更文件与目录所属群组,这种方式采用群组名称或群组识别码都可以.Chgrp命令就是change group的 ...
- 【JS】 Javascript与HTML DOM的互动 寻路
JS HTML DOM DOM的全程是Document Object Module,即文档对象模型.一般来说,当一个页面被加载时,浏览器会在内部创建一个当前文档的DOM.就像用python的Etree ...
- zabbix自定义key监控memcache状态及其他服务进程
一.在客户端 1.到/usr/loca/zabbix/conf/zabbix_agentd.conf里添加 UserParameter=memcached_stats[*],(echo ...
- Spring MVC的handlermapping之BeanNameUrlHandlerMapping初始化
先介绍一下: BeanNameUrlHandlerMapping是基于配置文件的方式; 所有处理器需要在XML文件中,以Bean的形式配置. 缺点:配置繁琐; 如果多个URL对应同一个处理器,那么需要 ...
- HTTP缓存带来的“bug”--HTTP 协议 Cache-Control
问题描述 先说背景.网站是用PHP开发的,未用任何框架,代码结构也非常简单.运行于阿里云服务器,并采用其CDN来做分发.根据业务需求,有的页面会判断用户浏览器类型,依此来选择PC或者手机端内容. 在一 ...
- RabbitMQ 发布订阅持久化
RabbitMQ是一种重要的消息队列中间件,在生产环境中,稳定是第一考虑.RabbitMQ厂家也深知开发者的声音,稳定.可靠是第一考虑,为了消息传输的可靠性传输,RabbitMQ提供了多种途径的消息持 ...