【spring-security】spring-security4安全框架配置详解
2016-02-15 13:46
591 查看
Spring Security是一个能够为基于Spring的企业应用系统提供声明式的安全访问控制解决方案的安全框架。它提供了一组可以在Spring应用上下文中配置的Bean,充分利用了Spring IoC,DI(控制反转Inversion of Control ,DI:Dependency Injection 依赖注入)和AOP(面向切面编程)功能,为应用系统提供声明式的安全访问控制功能,减少了为企业系统安全控制编写大量重复代码的工作。
下面将为大家讲解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时,会获取filter-name,然后通过fi
f85d
lter-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> <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="authenticationProcessingFilterEntryPoint" class="org.springframework.security.web.authentication.LoginUrlAuthenticationEntryPoint"> <beans:constructor-arg name="loginFormUrl" value="/user/login.htm" /> </beans:bean> <!-- 配置自定义过滤器 --> <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>
程序在启动的时候会遍历解析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中。
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理解起来其实并不难。但要融入到程序中合理使用,还需要多多运用。多多练习。
相关文章推荐
- java spring 3.2 java.lang.ClassNotFoundException: org.aopalliance.aop.Advice
- SpringMVC 入门基础和基本配置
- Android+struts2实现文件的上传
- Java类中代码的加载顺序
- Spring IoC AOP详解
- 一句话总结java23种设计模式
- JAVA应用程序获取当前路径
- springmvc-servlet.xml中use-default-filters的作用
- Java Raw Type(Java泛型)
- eclipse使用svn
- 快速搭建Spring MVC 4开发环境
- Java陷阱之assert关键字
- java 换行
- SSH之JDK1.8遇错The type java.util.Map$Entry cannot be resolved.
- HashSet的实现原理
- 解决MyEclipse "Your MyEclipse subscription has expired" 提示
- 解决Listview页脚RemoveFooterView报java.lang.ClassCastException错问题
- RxJava 平常使用
- [Java] 通过XPath获取XML中某个节点的属性
- JDK设置环境变量(classpath)时:dt.jar ,tool.jar,rt.jar的作用