【ACCESS精品源码栏目提醒】:本文主要为网学会员提供“spring_security3.2_详细配置_培训笔记 - 其它资料”,希望对需要spring_security3.2_详细配置_培训笔记 - 其它资料网友有所帮助,学习一下!
Spring Security 3.x 出来一段时间了,跟 Acegi 是大不同了,与 2.x 的版本也有一些小小的区别,网上有一些文档,也有人翻译 Spring Security 3.x 的 guide,但通过阅读 guide,无法马上就能很容易的实现一个完整的实例。
我花了点儿时间,根据以前的实战经验,整理了一份完整的入门教程,供需要的朋友们参考。
1,建一个 web project,并导入所有需要的 lib,这步就不多讲了。
2,配置 web.xml,使用 Spring 的机制装载: ltxml versionquot1.0quot encodingquotUTF-8quotgt ltweb-app versionquot2.4quot xmlnsquothttp://java.sun.com/xml/ns/j2eequot xmlns:xsiquothttp://www.w3.org/2001/XMLSchema-instancequot xsi:schemaLocationquothttp://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsdquotgt ltcontext-paramgt ltparam-namegtcontextConfigLocationlt/param-namegt ltparam-valuegtclasspath:applicationContext.xmllt/param-valuegt lt/context-paramgt ltlistenergt ltlistener-classgt org.springframework.web.context.ContextLoaderListener lt/listener-classgt lt/listenergt ltfiltergt ltfilter-namegtspringSecurityFilterChainlt/filter-namegt ltfilter-classgt org.springframework.web.filter.DelegatingFilterProxy lt/filter-classgt lt/filtergt ltfilter-mappinggt ltfilter-namegtspringSecurityFilterChainlt/filter-namegt lturl-patterngt/lt/url-patterngt lt/filter-mappinggt ltwelcome-file-listgt ltwelcome-filegtlogin.jsplt/welcome-filegt lt/welcome-file-listgt lt/web-appgt这个文件中的内容我相信大家都很熟悉了,不再多说了。
2,来看看 applicationContext-security.xml 这个配置文件,关于 Spring Security 的配置均在其中:ltxml versionquot1.0quot encodingquotUTF-8quotgtltbeans:beans xmlnsquothttp://www.springframework.org/schema/securityquot xmlns:beansquothttp://www.springframework.org/schema/beansquot xmlns:xsiquothttp://www.w3.org/2001/XMLSchema-instancequot xsi:schemaLocationquothttp://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-3.0.xsdquotgt lthttp
access-denied-pagequot/403.jspquotgtlt-- 当访问被拒绝时,会转到 403.jsp --gt ltintercept-url patternquot/login.jspquot filtersquotnonequot /gt ltform-login login-pagequot/login.jspquot authentication-failure-urlquot/login.jsperrortruequot default-target-urlquot/index.jspquot /gt ltlogout logout-success-urlquot/login.jspquot /gt lthttp-basic /gt lt-- 增加一个 filter,这点与 Acegi 是不一样的,不能修改默认的 filter 了,这个 filter 位于 FILTER_SECURITY_INTERCEPTOR 之前 --gt ltcustom-filter beforequotFILTER_SECURITY_INTERCEPTORquot refquotmyFilterquot /gt lt/httpgt lt-- 一个自定义的 filter,必须包含 authenticationManageraccessDecisionManagersecurityMetadataSource 三个属性, 我们的所有控制将在这三个类中实现,解释详见具体配置 --gt ltbeans:bean idquotmyFilterquot classquotcom.robin.erp.fwk.security.MyFilterSecurityInterceptorquotgt ltbeans:property namequotauthenticationManagerquot refquotauthenticationManagerquot /gt ltbeans:property namequotaccessDecisionManagerquot refquotmyAccessDecisionManagerBeanquot /gt ltbeans:property namequotsecurityMetadataSourcequot refquotsecurityMetadataSourcequot /gt lt/beans:beangt lt-- 认证管理器,实现用户认证的入口,主要实现 UserDetailsService 接口即可 --gt ltauthentication-manager aliasquotauthenticationManagerquotgt ltauthentication-provider user-service-refquotmyUserDetailServicequotgt lt-- 如果用户的密码采用加密的话,可以加点“盐” ltpassword-encoder hashquotmd5quot /gt --gt lt/authentication-providergt lt/authentication-managergt ltbeans:bean idquotmyUserDetailServicequot classquotcom.robin.erp.fwk.security.MyUserDetailServicequot /gt lt-- 访问决策器,决定某个用户具有的角色,是否有足够的权限去访问某个资源 --gt ltbeans:bean idquotmyAccessDecisionManagerBeanquot classquotcom.robin.erp.fwk.security.MyAccessDecisionManagerquotgt lt/beans:beangt lt-- 资源源数据定义,即定义某一资源可以被哪些角色访问 --gt ltbeans:bean idquotsecurityMetadataSourcequot classquotcom.robin.erp.fwk.security.MyInvocationSecurityMetadataSourcequot /gt lt/beans:beansgt3,来看看自定义 filter 的实现: package com.robin.erp.fwk.security import java.io.IOException import javax.servlet.Filter import javax.servlet.FilterChain import javax.servlet.FilterConfig import javax.servlet.ServletException import javax.servlet.ServletRequest import javax.servlet.ServletResponse import org.springframework.security.
access.SecurityMetadataSource import org.springframework.security.
access.intercept.AbstractSecurityInterceptor import org.springframework.security.
access.intercept.InterceptorStatusToken import org.springframework.security.web.FilterInvocation import org.springframework.security.web.
access.intercept.FilterInvocationSecurityMetadataSource public class MyFilterSecurityInterceptor extends AbstractSecurityInterceptor implements Filter private FilterInvocationSecurityMetadataSource securityMetadataSource // Methods // / Method that is actually called by the filter chain. Simply delegates to the link invokeFilterInvocation method. param request the servlet request param response the servlet response param chain the filter chain throws IOException if the filter chain fails throws ServletException if the filter chain fails/public void doFilterServletRequest request ServletResponse response FilterChain chain throws IOException ServletException FilterInvocation fi new FilterInvocationrequest response chain invokefipublic FilterInvocationSecurityMetadataSource getSecurityMetadataSource return this.securityMetadataSourcepublic Classlt extends Objectgt getSecureObjectClass return FilterInvocation.classpublic void invokeFilterInvocation fi throws IOException ServletException InterceptorStatusToken token super.beforeInvocationfi try fi.getChain.doFilterfi.getRequest fi.getResponse finally super.afterInvocationtoken null public SecurityMetadataSource obtainSecurityMetadataSource return this.securityMetadataSourcepublic void setSecurityMetadataSource FilterInvocationSecurityMetadataSource newSource this.securityMetadataSource newSourceOverride public void destroy Override public void initFilterConfig arg0 throws ServletException 最核心的代码就是 invoke 方法中的 InterceptorStatusToken token super.beforeInvocationfi这一句,即在执行 doFilter 之前,进行权限的检查,而具体的实现已经交给 accessDecisionManager 了,下文中会讲述。
4,来看看 authentication-provider 的实现: package com.robin.erp.fwk.security import java.util.ArrayList import java.util.Collection import org.springframework.dao.DataAccessException import org.springframework.security.core.GrantedAuthority import org.springframework.security.core.authority.GrantedAuthorityImpl import org.springframework.security.core.userdetails.User import org.springframework.security.core.userdetails.UserDetails import org.springframework.security.core.userdetails.UserDetailsService import org.springframework.security.core.userdetails.UsernameNotFoundException public class MyUserDetailService implements UserDetailsService Override public UserDetails loadUserByUsernameString username throws UsernameNotFoundException DataAccessException CollectionltGrantedAuthoritygt authsnew ArrayListltGrantedAuthoritygt GrantedAuthorityImpl auth2new GrantedAuthorityImplquotROLE_ADMINquot auths.addauth2 ifusername.equalsquotrobin1quot authsnew ArrayListltGrantedAuthoritygt GrantedAuthorityImpl auth1new GrantedAuthorityImplquotROLE_ROBINquot auths.addauth1 // UserString username String password boolean enabled boolean accountNonExpired // boolean credentialsNonExpired boolean accountNonLocked CollectionltGrantedAuthoritygt authorities User user new Userusername quotrobinquot true true true true auths return user 在这个类中,你就可以从数据库中读入用户的密码,角色信息,是否锁定,账号是否过期等,我想这么简单的代码就不再多解释了。
5,对于资源的访问权限的定义,我们通过实现 FilterInvocationSecurityMetadataSource 这个接口来初始化数据。
package com.robin.erp.fwk.security import java.util.ArrayList import java.util.Collection import java.util.HashMap import java.util.Iterator import java.util.Map import org.springframework.security.
access.ConfigAttribute import org.springframework.security.
access.SecurityConfig import org.springframework.security.web.FilterInvocation import org.springframework.security.web.
access.intercept.FilterInvocationSecurityMetadataSource import org.springframework.security.web.util.AntUrlPathMatcher import org.springframework.security.web.util.UrlMatcher / 此类在初始化时,应该取到所有资源及其对应角色的定义 author Robin / public class MyInvocationSecurityMetadataSource implements FilterInvocationSecurityMetadataSource private UrlMatcher urlMatcher new AntUrlPathMatcher private static MapltString CollectionltConfigAttributegtgt resourceMap null public MyInvocationSecurityMetadataSource loadResourceDefine private void loadResourceDefine resourceMap new HashMapltString CollectionltConfigAttributegtgt CollectionltConfigAttributegt atts new ArrayListltConfigAttributegt ConfigAttribute ca new SecurityConfigquotROLE_ADMINquot atts.addca resourceMap.putquot/index.jspquot atts resourceMap.putquot/i.jspquot atts // According to a URL Find out permission configuration of this URL. public CollectionltConfigAttributegt getAttributesObject object throws IllegalArgumentException // guess object is a URL. String url FilterInvocationobject.getRequestUrl IteratorltStringgt ite resourceMap.keySet.iterator while ite.hasNext String resURL ite.next if urlMatcher.pathMatchesUrlresURL url return resourceMap.getresURL return null public boolean supportsClassltgt clazz return true public CollectionltConfigAttributegt getAllConfigAttributes return null 看看 loadResourceDefine 方法,我在这里,假定 index.jsp 和 i.jsp 这两个资源,需要 ROLE_ADMIN 角色的用户才能访问。
这个类中,还有一个最核心的地方,就是提供某个资源对应的权限定义,即 getAttributes 方法返回的结果。
注意,我例子中使用的是 AntUrlPathMatcher 这个 path matcher 来检查 URL 是否与资源定义匹配,事实上你还要用正则的方式来匹配,或者自己实现一个 matcher。
6,剩下的就是最终的决策了,make a decision,其实也很容易,呵呵。
package com.robin.erp.fwk.security import java.util.Collection import java.util.Iterator import org.springframework.security.
access.AccessDecisionManager import org.springframework.security.
access.AccessDeniedException import org.springframework.security.
access.ConfigAttribute import org.springframework.security.
access.SecurityConfig import org.springframework.security.authentication.InsufficientAuthenticationException import org.springframework.security.core.Authentication import org.springframework.security.core.GrantedAuthority public class MyAccessDecisionManager implements AccessDecisionManager //In this method need to compare authentication with configAttributes. // 1 A object is a URL a filter was find permission configuration by this URL and pass to here. // 2 Check authentication has attribute in permission configuration configAttributes // 3 If not match corresponding authentication throw a AccessDeniedException. public void decideAuthentication authentication Object object CollectionltConfigAttributegt configAttributes throws AccessDeniedException InsufficientAuthenticationException ifconfigAttributes null return System.out.printlnobject.toString //object is a URL. IteratorltConfigAttributegt iteconfigAttributes.iterator whileite.hasNext ConfigAttribute caite.next String needRoleSecurityConfigca.getAttribute forGrantedAuthority ga:authentication.getAuthorities ifneedRole.equalsga.getAuthority //ga is users role. return throw new AccessDeniedExceptionquotno rightquot Override public boolean supportsConfigAttribute attribute // TODO Auto-generated method stub return true Override public boolean supportsClassltgt clazz return true 在这个类中,最重要的是 decide 方法,如果不存在对该资源的定义,直接放行;否则,如果找到正确的角色,即认为拥有权限,并放行,否则 throw new AccessDeniedExceptionquotno rightquot这样,就会进入上面提到的 403.jsp 页面。
Spring Security3 的使用方法有 4 种:一种是全部利用配置文件,将用户、权限、资源url硬编码在 xml 文件中。
二种是用户和权限用数据库存储,而资源url和权限的对应采用硬编码配置。
三种是细分角色和权限,并将用户、角色、权限和资源均采用数据库存储,并且自定义过滤器,代替原有的 FilterSecurityInterceptor 过滤器,并分别实现 AccessDecisionManager、InvocationSecurityMetadataSourceService 和 UserDetailsService,并在配置文件中进行相应配置。
四是修改 spring security 的源代码,主要是修改 InvocationSecurityMetadataSourceService和 UserDetailsService 两个类。
前者是将配置文件或数据库中存储的资源url提取出来加工成为 url 和权限 列表的 Map 供 Security 使用 ,后者 提取 用户 名和权 限组 成 一个完 整的UserDetailsUser 对象,该对象可以提供用户的详细信息供 AuthentationManager 进行认证与授权使用。
该方法理论上可行,但是比较暴力,不推荐使用。
本文有两个例子,我在简单例子章节实现了第一种方法。
在复杂例子章节实现了第二种和第三种方法组合使用的例子。
简单例子通俗易懂,不再赘述。
复杂例子及其使用和扩展,我将穿插详细的配置注释和讲解,包括整个程序的执行过程。
简单例子创建 web 工程如下图所示:配置如下图所示:单击 Finish 即可。
把 从 spring 网 站 下 载 的 spring-security-3.1.0.RELEASE 解 压 , 并 将 其 中 的spring-security-samples-contacts-3.1.0.RELEASE.war 解压,把 WEB-INFlib 中的 jar 包拷贝到如下图所示:修改配置 web.xml 如下:ltxmlversionquot1.0quotencodingquotUTF-8quotgtltweb-appversionquot2.5quotxmlnsquothttp://java.sun.com/xml/ns/javaeequot xmlns:xsiquothttp://www.w3.org/2001/XMLSchema-instancequot xsi:schemaLocationquothttp://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsdquotgt lt--加载Spring XML配置文件 --gt ltcontext-paramgt ltparam-namegtcontextConfigLocationlt/param-namegt ltparam-valuegt classpath:securityConfig.xml lt/param-valuegt lt/context-paramgt lt-- Spring Secutiry3.1的过滤器链配置 --gt ltfiltergt ltfilter-namegtspringSecurityFilterChainlt/filter-namegt ltfilter-classgtorg.springframework.web.filter.DelegatingFilterProxylt/filter-classgt lt/filtergt ltfilter-mappinggt ltfilter-namegtspringSecurityFilterChainlt/filter-namegt lturl-patterngt/lt/url-patterngt lt/filter-mappinggt lt-- Spring 容器启动监听器 --gt ltlistenergt ltlistener-classgtorg.springframework.web.context.ContextLoaderListenerlt/listener-classgt lt/listenergt lt--系统欢迎页面--gt ltwelcome-file-listgt ltwelcome-filegtindex.jsplt/welcome-filegt lt/welcome-file-listgtlt/web-appgt在 src 中创建 securityConfig.xml 内容如下:ltxmlversionquot1.0quotencodingquotUTF-8quotgtltb:beansxmlnsquothttp://www.springframework.org/schema/securityquotxmlns:bquothttp://www.springframework.