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 - 配置文件解析和访问请求处理的更多相关文章

  1. 【转】Spring Boot干货系列:(二)配置文件解析

    转自:Spring Boot干货系列:(二)配置文件解析 前言 上一篇介绍了Spring Boot的入门,知道了Spring Boot使用"习惯优于配置"(项目中存在大量的配置,此 ...

  2. Spring Boot干货系列:(二)配置文件解析

    Spring Boot干货系列:(二)配置文件解析 2017-02-28 嘟嘟MD 嘟爷java超神学堂   前言 上一篇介绍了Spring Boot的入门,知道了Spring Boot使用“习惯优于 ...

  3. Spring Security 入门(1-7)Spring Security - Session管理

    参考链接:https://xueliang.org/article/detail/20170302232815082 session 管理 Spring Security 通过 http 元素下的子元 ...

  4. Spring Security 入门(1-3-5)Spring Security - remember me!

    Remember-Me 功能 概述 Remember-Me 是指网站能够在 Session 之间记住登录用户的身份,具体来说就是我成功认证一次之后在一定的时间内我可以不用再输入用户名和密码进行登录了, ...

  5. Spring Security 入门(1-6-2)Spring Security - 内置的filter顺序、自定义filter、http元素和对应的filterChain

    Spring Security 的底层是通过一系列的 Filter 来管理的,每个 Filter 都有其自身的功能,而且各个 Filter 在功能上还有关联关系,所以它们的顺序也是非常重要的. 1.S ...

  6. Spring Security 入门(1-3-2)Spring Security - http元素 - intercept-url配置

    http元素下可以配置登录页面,也可以配置 url 拦截. 1.直接配置拦截url和对应的访问权限 <security:http use-expressions="false" ...

  7. Spring Security 入门(1-4-2)Spring Security - 认证过程之AuthenticationProvider的扩展补充说明

    1.用户信息从数据库获取 通常我们的用户信息都不会向第一节示例中那样简单的写在配置文件中,而是从其它存储位置获取,比如数据库.根据之前的介绍我们知道用户信息是通过 UserDetailsService ...

  8. Spring Security 入门(1-3-1)Spring Security - http元素 - 默认登录和登录定制

    登录表单配置 - http 元素下的 form-login 元素是用来定义表单登录信息的.当我们什么属性都不指定的时候 Spring Security 会为我们生成一个默认的登录页面. 如果不想使用默 ...

  9. Spring Security 入门(1-2)Spring Security - 从 配置例子例子 开始我们的学习历程

    1.Spring Security 的配置文件 我们需要为 Spring Security 专门建立一个 Spring 的配置文件,该文件就专门用来作为 Spring Security 的配置. &l ...

随机推荐

  1. BZOJ1565 植物大战僵尸 题解

    题目内容: 题目分析:有选A则必须选B这样的限制条件,可以发现这是最大权闭合子图模型,考虑环的情况,可以推测需要拓扑判环. 代码: #include<bits/stdc++.h> usin ...

  2. 温故而知新—heap

    堆:堆不是STL中的容器组件,堆有分为大根堆和小根堆,堆的底层实现可以用优先队列进行实现.底层的容器实际上是一个vector.在C++数据结构中,堆也可用数组来实现.对于使用C++的开发人员来说,st ...

  3. docker初次体验-管理MySQL+tomcat镜像

    引言 平时经常用linux,我没少吃苦后悔linux没好好研究研究.装一些软件配一些环境时很是害怕,多亏有了docker.docker是一个应用容器引擎,可以管理很多的软件镜像,这些镜像被官方放在了d ...

  4. [POJ 2226] Muddy Fields

    题目 Description 如何放木板保证只覆盖到 '*' 而没有覆盖到 '.' Solution (我太废了竟然想这题想了一个小时)考虑当前需要被覆盖的点 (x,y),假设有一块横着铺的木板 i ...

  5. spring-boot 多模块化项目和EurekaServer的搭建

    Spring boot由于其 1.易于开发和维护.2.单个微服务启动快.3.局部修改部署容易.4.技术栈不受语言限制等优点受到越来越多公司的重视.spring-boot还集成了许多关于微服务开发的框架 ...

  6. 【Python】 获取MP3信息replica

    replica 初衷是想要整理iphone中的音乐.IOS(我自己的手机还是IOS8.3,新版本的系统可能有变化了)自带的音乐软件中所有音乐文件都存放在/var/mobile/Media/iTunes ...

  7. 设计模式 --> MVC,MVP 和 MVVM 的图示

    MVC,MVP 和 MVVM 的图示 复杂的软件必须有清晰合理的架构,否则无法开发和维护.MVC(Model-View-Controller)是最常见的软件架构之一,业界有着广泛应用. 一.MVC M ...

  8. nodejs利用superagent爬取数据的简单例子

    爬取世界银行统计数据 安装:npm install superagent /** * Created by zh on 16-9-7. */ var request = require('supera ...

  9. 蓝牙4.0模块控制LED彩灯调光调色经验之谈

    基于蓝牙模块的智能LED彩灯调光调色控制思路如下: 在此,找一个低功耗蓝牙模块内嵌接入LED灯的控制电路板,接入LED彩灯的控制电路中. 蓝牙模块彩灯控制方式如下,本文两类来解说led灯的控制方式: ...

  10. SQL语法语句总结

    一.SQL语句语法 ALTER TABLE ALTER TABLE 用来更新已存在表的结构. ALTER TABLE tablename (ADD|DROP column datatype [NULL ...