注册 登录  
 加关注
   显示下一条  |  关闭
温馨提示!由于新浪微博认证机制调整,您的新浪微博帐号绑定已过期,请重新绑定!立即重新绑定新浪微博》  |  关闭

我的博客

 
 
 

日志

 
 

Spring Security  

2011-08-20 17:51:43|  分类: JAVA |  标签: |举报 |字号 订阅

  下载LOFTER 我的照片书  |
http://www.blogjava.net/wzl002/MyArticles.html

 Spring Security使用一组过滤器链来对用户进行身份验证和授权。首先,在web.xml文件中添加FilterToBeanProxy过滤器配置:
 1 <filter>   
 2       <filter-name>springSecurityFilterChain</filter-name>
 3      <filter-class>
 4         org.springframework.security.util.FilterToBeanProxy
 5      </filter-class>
 6      <init-param>       
 7           <
param-name>targetClass</param-name>
 8          <param-value>           
 9               org.springframework.security.util.FilterChainProxy
10          </param-value>
11       </init-param>
12 </filter>
13
        org.springframework.security.util.FilterToBeanProxy实现了Filter接口,它通过调用WebapplicationContextUtils类的getWebApplicationnContext(servletContext)方法来获取Spring的应用上下文句柄,并通过getBean(beanName)方法来获取Spring受管Bean的对象,即这里targetClass参数配置的Bean,并通过调用FilterChain Proxy的init()方法来启动Spring Security过滤器链进行各种身份验证和授权服务(FilterChainProxy类也是实现了Filter接口),从而将过滤功能委托给Spring的FilterChainProxy受管Bean(它维护着一个处理验证和授权的过滤器列表,列表中的过滤器按照一定的顺序执行并完成认证过程),这样即简化了web.xml文件的配置,又能充分利用 Spring的IoC功能来完成这些过滤器执行所需要的其它资源的注入。

        当用户发出请求,过滤器需要根据web.xml配置的请求映射地址来拦截用户请求,这时Spring Security开始工作,它会验证你的身份以及当前请求的资源是否与你拥有的权限相符,从而达到保护Web资源的功能,下面是本例所要过滤的用户请求地址:
 1 <filter-mapping>
 2 
 3        <filter-name>springSecurityFilterChain</filter-name>

 5        <url-pattern>/j_spring_security_check</url-pattern>
 6 
 7     </filter-mapping>
 8 
 9     <filter-mapping>
10 
11        <filter-name>springSecurityFilterChain</filter-name>
12 
13        <url-pattern>/*</url-pattern>
14 
15 </filter-mapping>

提示:
/j_spring_security_check是Spring Security默认的进行表单验证的过滤地址,你也可以修改为别的名称,但是需要和
applicationContext-security.xml中相对应,当然还会涉及到其它一些默认值(可能是一个成员变量,也可能是别的请
求地址),在下文我们将看到,建议你在阅读此文的同时,应该参照Spring Security项目的源代码,便于你更好的理解。


3 配置applicationContext-security.xml

    3.1 FilterChainProxy过滤器链

    FilterChainProxy会按顺序来调用一组filter,使这些filter即能完成验证授权的本质工作,又能享用Spring Ioc的功能来方便的得到其它依赖的资源。FilterChainProxy配置如下:

 1 <bean id="filterChainProxy"   
        class
="org.springframework.security.util.FilterChainProxy">
 2      <property name="filterInvocationDefinitionSource">
 3         <value><![CDATA[         
                CONVERT_URL_TO_LOWERCASE_BEFORE_COMPARISON 
 4              PATTERN_TYPE_APACHE_ANT         
                /**=httpSessionContextIntegrationFilter,logoutFilter,
 5              authenticationProcessingFilter,securityContextHolderAwareRequestFilter,
 6              rememberMeProcessingFilter,anonymousProcessingFilter,exceptionTranslationFilter,
 7              filterSecurityInterceptor 
 8         ]]></value>
 9      </property>
10 </bean>

    CONVERT_URL_TO_LOWERCASE_BEFORE_COMPARISON 定义URL在匹配之前必须先转为小写,PATTERN_TYPE_APACHE_ANT 定义了使用Apache ant的匹配模式,/**定义的将等号后面的过滤器应用在那些URL上,这里使用全部URL过滤,每个过滤器之间都适用逗号分隔,它们按照一定的顺序排列。

 

提示:
特别需要注意的是,即使你配置了系统提供的所有过滤器,这个过滤器链会很长,但是千万不要使用换行,否则它们不会正常工作,
容器甚至不能正常启动。
 

    下面根据FilterChainProxy的配置来介绍各个过滤器的配置,各个过滤器的执行顺序如以上配置。

    首先是通道处理过滤器,如果你需要使用HTTPS,这里我们就使用HTTP进行传输,所以不需要配置通道处理过滤器,然后是集成过滤器,配置如下:

1 <bean id="httpSessionContextIntegrationFilter"
2 
3 class="org.springframework.security.context.HttpSessionContextIntegrationFilter"/>

    httpSessionContextIntegrationFilter是集成过滤器的一个实现,在用户的一个请求过程中,用户的认证信息通过SecurityContextHolder(使用ThreadLoacl实现)进行传递的,所有的过滤器都是通过SecurityContextHolder来获取用户的认证信息,从而在一次请求中所有过滤器都能共享Authentication(认证),减少了HttpRequest参数的传送,下面的代码是从安全上下文的获取Authentication对象的方法:

1 SecurityContext context = SecurityContextHolder.getContext();
2 
3 Authentication authentication = context.getAuthentication();

    但是,ThreadLoacl不能跨越多个请求存在,所以,集成过滤器在请求开始时从Http会话中取出用户认证信息并创建一个SecurityContextHolder将Authentication对象保存在其中,在请求结束之后,在从SecurityContextHolder中获取Authentication对象并将其放回Http会话中,共下次请求使用,从而达到了跨越多个请求的目的。集成过滤器还有其它的实现,可以参考相关文档。

提示:
集成过滤器必须在其它过滤器之前被使用。
 

    logoutFilter(退出过滤器) ,退出登录操作:

 1 <bean id="logoutFilter"
 2 
 3     class="org.springframework.security.ui.logout.LogoutFilter">
 4 
 5     <constructor-arg value="/index.jsp"/>
 6 
 7     <constructor-arg>
 8 
 9        <list>
10 
11            <!-- 实现了LogoutHandler接口(logout方法) -->
12 
13            <ref bean="rememberMeServices"/>
14 
15            <bean class="org.springframework.security.ui.logout.SecurityContextLogoutHandler"/>
16 
17        </list>
18 
19     </constructor-arg>
20 
21 </bean>


posted @ 2009-04-21 16:11 wesley1987 阅读(61) | 评论 (0)编辑 收藏

2008年12月23日

 

                  项目实训心得

             在这一个多月的项目实训过程,我感到是我专业学习中收获非常大的一个月。在这个月里,我体验到了团队合作的经验,编程过程中的乐趣,以及将学习应用到实际、从实践中学习的丰收感。

              这一个月里,得到了二个最宝贵体验:一是参与了一个团队合作的、有很强多同模块相互性、和一套完整生命周期流程的工程项目。这一套项目按照软件工程的流程一步步走下来,经历了需求分析,详细设计,实际编码和测试这一系列阶段。一步一步慢慢的走下来。虽然对于真实的项目来说,这个项目的复杂度和规模并不是很大,逻辑要求也不是太严格。但是对于只参加一些3-4人的项目编程的我来说,已经第一次让我体真正的体验到将编程作为一项工程来执行的难得经验。

              第二个体验是详细设计中,将软件架构和分层的思想以及简单的工程模式等应用到了项目中。使用框架等方式,非常有效的提高了代码的复用和工程的可维护性,虽然多层结构看似麻烦,但实际上它很大的降低了设计的复杂度,在实际的体验中感到,使用了框架后的模块,维护起来清晰了很多,容易了很多,降低了耦合,同时增强了模块间的交互和重用。

              随着整个工程的流程一步步进行,我们看到了一个工程的一次次成长。项目伊始,我们得到了项目需求文档(我想这一步在实际中也应该是由项目人员精心设计才完成的),对于工程的不同用例,将工程分为了六个模块,并对应的将组员分为了六组。我们的第一步是完成对需求文档的理解,而成果就是对应了各个模块的实际功能的静态页面,因为软件客户最后体验所有需求的功能实现就是通过操作页面来实现,所以页面要在客户需求的角度去考虑,同时要将需求的功能都赋予体现。在这个过程中,大家除了按功能分化出页面分类外,大部分时间还用来精心设计页面的风格。页面布局和菜单中大量用到了JavaScriptCSS。和以我往设计页面时不同的是,为了让大家可以公用这些设计,在页面的布局中不能太复杂,甚至几乎是不能在需要统一的地面对整体的布置有任何复杂的干预。所有希望统一的部分都要在公共的CSSJavaScript中做出方便统一使用的类或方法,在页面本身的代码中几乎看不到布局设计,只有功能组件。

              在页面设计通过审核之后就是详细设计阶段了,在这阶段的前几天我们犯了一个顺序错误,直接从数据库着手。结果由于项目的功能的复杂性和模块之间太多需要交互的地方,使得数据库的设计进行的很缓慢。经过老师的提点我们改为从程序编码的框架开始着手。联系各功能的具体实现来设计编码的层次结构(框架详细设计在下一节),划分出公共平台。这样再从各模块的功能及其交互划分来联系设计数据库就变的清晰了很多。在设计过程中我们还使用了E-R图来设计出关系数据库,即从参与的对象和对象之间的关系最终设计出数据库的方法。在这次设计中发现自己在利用一些系统的理论进行整体的数据库模型设计方面还存在很多不足。数据库完成后,对框架的设计也基本完成,公共的分页设计,数据库连接与关闭,工程的文件结构和工程的环境也在几次讨论后完成统一设计。

              由于之前对struts有了一定的了解,所以我在需求分析阶段就开始尝试着着手对几个简单模块的实现编码,之后在详细设计阶段中,每次讨论后新加的内容都需要对已经完成的代码进行一次大的修改。随着代码的增长,尝试了很多种文件结构。之后引入项目的框架也经历了很大的修改和许多次的尝试。此外的修改还包括BaseAction的引入,DispatchAction的引入,使用struts异常处理等,并做好工程备份及将修改记录在日报中。在这一次次的修改中让我受益匪浅,对这些设计和修改有了更深刻的体会。这样在详细设计阶段的过程中,框架设计都已经在编码中事先进行了实现和测试,一些功能在写好后被分离出来作为公共平台。终于在小组开始编码时确定出了统一并详细完整的的工程的全部环境,项目的框架结构和整体编码方式。我的编码实现和单元测试也基本完成。

              在两周的编码过程中,我主要是和吉利一起协助各模块编码,增加各模块间交流,在这期间也解决问题的过程中学到知识。经过全体组员两周的努力工作,终于进入了测试阶段。我和吉利负责整体测试,测试联结了所有模块之后,可以顺利的完成全套的流程。让整个设计可以在6个流程中一步步的走下去,同时保证数据库中所有数据和状态的正确性。随着测试一次次的进行,问题渐渐被全部排除,经过3次测试之后,基本可以完全顺利的走完全套流程。

              < XMLNAMESPACE PREFIX ="V" /> < XMLNAMESPACE PREFIX ="O" />

              我们这次工程中使用的是四层结构的框架,即将MVC三层结构的同时,将model模型层分成了model模型层和DAO持久层。其中又根据工厂模式分出DAO接口,beanfactoryservicemanager)提供DAO实现。

              结构实现:首先我们根据框架,设计出相应的文件结构。视图层即所有JSP文件,和配置文件一起由eclipse的自动生成单独分在WebRoot下,六模块的页面分别分于六个子目录下。所有的公共页面和jscss目录也放入WebRoot下。由于这次项目中模块间的功能页面基本是完全相互独立的,这为在实现视图层和控制层之间的页面跳转控制带来很大的方便。代码目录(src)下为六个模块的六个目录,公共代码目录(platform),以及后加入的验证模块的目录(validate)。除公共目录外,各模块下代码分为5个目录:ActionmodelFormmanagerdao。(这里有两个命名的失误,根据实际的使用,model的名字应该叫bean更合适,而这里manager一般在框架中称为service。但我们已经有了称为service的模块名称。)这里的ActionForm对应了struts中的组件,DAO层和model-bean一起完成了操作的具体实现,

              视图层view:总体框架上,我们使用的是frameset来实现,不过听老师说现在流行的使用japinclude结合div等来实现页面框架。在之后编码中,因为frameset出现了一个问题,就是用来验证拦截的过滤器无法刷新整个框架,使得拦截后的页面只能显示在被操作的frame中。但是frameset的好处是框架分离的很好,在实现jsp编码中几乎完全不用去考虑框架。我不知道用include是否能做到。以前虽然都使用的include,但是是在每个页面中都要加入include。有时还会影响布局。在编码过程中,我们用JavaScript实现了很多很好用的效果,比如选择时间的窗口,表单的正则表达式验证,表格的变色效果等,封装到公共的js文件中,调用起来很方便。在这次jap编程中,我终于由最初的在页面中堆满java代码,转变为只使用一些JSTLEL语句和struts标签处理逻辑,美观了页面编码,同时让页面更专注于显示层。但这里我对EL语句和纯标签语句又有些难以取舍。EL语句在页面代码中虽然不如单用标签显得纯粹美观,但是EL表达式简约的表现风格让实现和维护变得容易了很多。

              控制层Action的设计一是使用了DispatchAction,将多个Action类合并,方便了管理。二在公共部分中定义了BaseAction,由这个类去继承strutsDispatchAction。之后我们的所有Action都去继承这个BaseAction。这样在需要对Action进行统一处理,以及定义一些供Action公共使用的方法时就可以在这个BaseAction中修改。虽然在这次项目中,BaseAction只定义了个用于处理字符乱码的方法公共使用,但由此即可瞥见对于更复杂的Action统一处理这种设计也能从容应对。由于是分模块进行,于是我们将strutsxml配置文件也分为对应各个模块,使用多xml的配置方式,而这也需要对命名规则等很多方面有更好的协调和统一。在这次控制层的实现中,我起初还是像以前一样对很多不同的验证,模型层返回的异常都在Action中处理并跳转。在之后的修改中,逐渐将这些处理都改至模型层Manager中,由Manager取用持久层的操作方法,实现所有业务逻辑处理。

              具体实现功能的模型层中,我们为每个DAO定义了接口和实现类,这也是我第一次将接口真正应用到程序中。同时我们在每个模块的DAO中应用了工厂模式,由一个factory类实现所有DAO的单例生成。之后在Manager中调用这个实例实现操作。而这个Manager同时本身也是单例实现的,由Action进行静态调用。可见其中实现Action控制层和DAO持久层交互的就是Manager模型层,并将两者严格的分离开来。同时在Manager中还集合处理了所有来至业务功能逻辑和底部数据库的所有异常。因为数据库的连接也是在Manager中创建的,但这不影响持久层的独立性,因为这是考虑到有时一次业务操作会进行多个数据库操作、调用多个数据库方法,将连接在模型层中创建更便于数据库的高效使用。模型层中对异常的集中处理,更简化了上下控制层和模型层的实现,使其更专注于各自的业务实现。在异常处理上,使用了struts的一种异常处理机制,在xml配置文件中进行异常配置。这样在Manager中将异常抛出,由struts实现异常跳转和提示。同时我们还将自定义的异常处理类也作为公共类公用,这样就可以在需要的时候对异常进行统一的处理。

              在持久层的实现上,我们使用了tomcat数据库连接池,在编码中将数据库连接等方法封装到公共类中,并且将连接数据源作静态单例实现,以提高数据库调用的效率。在DAO的设计方面,我们主要针对实际的操作对象和对应的数据库进行DAO层方法的封装。每个方法尽量实现一些简单的操作。这样在不同模块直接有数据和操作交互的时候,只在模型层只要去各个模块的DAO中取得需要的方法加以组合,实现自己的业务处理。很好的提高了代码的复用性和可维护性,降低了各个模块间数据交互处理的设计复杂度。

    //文采太烂, 结尾的感慨段就不发了

  评论这张
 
阅读(857)| 评论(0)
推荐 转载

历史上的今天

评论

<#--最新日志,群博日志--> <#--推荐日志--> <#--引用记录--> <#--博主推荐--> <#--随机阅读--> <#--首页推荐--> <#--历史上的今天--> <#--被推荐日志--> <#--上一篇,下一篇--> <#-- 热度 --> <#-- 网易新闻广告 --> <#--右边模块结构--> <#--评论模块结构--> <#--引用模块结构--> <#--博主发起的投票-->
 
 
 
 
 
 
 
 
 
 
 
 
 
 

页脚

网易公司版权所有 ©1997-2017