首页 诗词 字典 板报 句子 名言 友答 励志 学校 网站地图
当前位置: 首页 > 教程频道 > 开发语言 > 编程 >

Spring Security2

2012-09-19 
Spring Security二?????????? SpringSide(你可以去官网了解更多信息,我也是从这里开始了解和学习Spring Se

Spring Security二

?????????? SpringSide(你可以去官网了解更多信息,我也是从这里开始了解和学习Spring Security的)

前一篇文章里介绍了Spring Security的一些基础知识,相信你对Spring Security的工作流程已经有了一定的了解,如果你同时在读源代码,那你应该可以认识的更深刻。在这篇文章里,我们将对Spring Security进行一些自定义的扩展,比如自定义实现UserDetailsService,保护业务方法以及如何对用户权限等信息进行动态的配置管理。

提示:
两个抽象类实现了各自接口的 getAttributes(Object object)方法并在此方法中调用lookupAttributes
(Method method)方法,而实际该方法在抽象类中并没有具体的实现,而是留给了子类去实现。 ?

在Acegi Seucrity 1.x版本中,系统为我们提供了默认的实现,MethodDefinitionMap类用于返回方法的权限信息,而PathBasedFilterInvocationDefinitionMap类和RegExpBasedFilterInvocationDefinitionMap类用于返回URL资源对应的权限信息,也就是ConfigAttributeDefinition对象,现在也许明白一点儿了吧,我们只要按照这三个类的实现方式(也就是”模仿”,从后面的代码中你可以看到)从数据库中获取用户信息和权限信息然后封装成一个ConfigAttributeDefinition对象返回即可(其实就是一个List列表,前面已经介绍过了),相信通过Hibernate从数据库中获取一个列表应该是再容易不过的了。

回到Spring Security,系统为我们提供的默认实现有些变化,DefaultFilterInvocationDefinitionSource和DelegatingMethodDefinitionSource两个类,从名字也可以看出来它们分别是干什么的了。这两个类分别实现了FilterInvocationDefinitionSource和MethodDefinitionSource接口,而这两个接口都继承自ObjectDefinitionSource接口并实现了其中的方法,这和1.x版本中一样。它们都是从配置文件中得到资源和相应权限的信息。

通过上面的介绍,你或许更名白了一些,那我们下面要做的就是实现系统的FilterInvocationDefinitionSource和MethodDefinitionSource接口,只是数据源不是从配置文件中读取配置信息是数据库而已。

我们这里对比着Acegi Seucrity 1.x版本中的实现,我个人认为它更好理解,还是请你好好看看源代码。

1 自定义FilterInvocationDefinitionSource

在2.0中,系统没有在系统抽象类,所以我们还是使用1.x中的实现方式,首先通过一个抽象类来实现ObjectDefinitionSource接口。代码如下:

<!--<br /> <br /> Code highlighting produced by Actipro CodeHighlighter (freeware)<br /> http://www.CodeHighlighter.com/<br /> <br /> -->?1?public?ConfigAttributeDefinition?getAttributes(Object?object)
?2?
?3????????????throws?IllegalArgumentException?{
?4?
?5????????if?(object?==?null?||?!(this.supports(object.getClass())))?{
?6?
?7????????????thrownew?IllegalArgumentException("Object?must?be?a?FilterInvocation");
?8?
?9????????}
10?
11????????String?url?=?((FilterInvocation)object).getRequestUrl();
12?
13????????returnthis.lookupAttributes(url);
14?
15?????}
16?
17?publicabstract?ConfigAttributeDefinition?lookupAttributes(String?url);
18?
19?@SuppressWarnings("unchecked")
20?
21?publicabstract?Collection?getConfigAttributeDefinitions();
22?
23?@SuppressWarnings("unchecked")
24?
25?publicboolean?supports(Class?clazz)?{
26?
27?????return?FilterInvocation.class.isAssignableFrom(clazz);
28?
29?}

这段代码你也可以在1.0中找到,getAttributes方法的入口参数是一个Object对象,这是由系统传给我们的,因为是URL资源的请求,所有可以将这个Object对象强制转换为FilterInvocation对象,并通过调用它的getRequestUrl()方法来获取用户当前请求的URL地址,然后调用子类需要实现的lookupAttributes方法并将该URL地址作为参数传给该方法,下面是具体的实现类DataBaseFilterInvocationDefinitionSource类的代码,也就是我们需要实现抽象父类的lookupAttributes方法:

?

<!--<br /> <br /> Code highlighting produced by Actipro CodeHighlighter (freeware)<br /> http://www.CodeHighlighter.com/<br /> <br /> -->??1?@Override
??2?
??3?public?ConfigAttributeDefinition?lookupAttributes(String?url)?{
??4?
??5????????//?TODO?Auto-generated?method?stub
??6?
??7????????//初始化数据,从数据库读取
??8?
??9?????cacheManager.initResourceInCache();
?10?
?11?????if?(isUseAntPath())?{
?12?
?13????????int?firstQuestionMarkIndex?=?url.lastIndexOf("?");
?14?
?15????????if?(firstQuestionMarkIndex?!=?-1)?{
?16?
?17????????????url?=?url.substring(0,?firstQuestionMarkIndex);
?18?
?19????????}
?20?
?21?????}
?22?
?23?????//将URL在比较前都转换为小写
?24?
?25?????if?(isConvertUrlToLowercaseBeforeComprison())?{
?26?
?27????????url?=?url.toLowerCase();
?28?
?29?????}
?30?
?31?????//获取所有的URL
?32?
?33?????List<String>?urls?=?cacheManager.getUrlResources();
?34?
?35?????//倒叙排序--如果不进行排序,如果用户使用浏览器的导航工具访问页面可能出现问题
?36?
?37?????//例如:访问被拒绝后用户刷新页面
?38?
?39?????Collections.sort(urls);
?40?
?41?????Collections.reverse(urls);
?42?
?43?????GrantedAuthority[]?authorities?=?new?GrantedAuthority[0];
?44?
?45?????//将请求的URL与配置的URL资源进行匹配,并将正确匹配的URL资源对应的权限
?46?
?47?????//取出
?48?
?49?????for?(String?resourceName_url?:?urls)?{
?50?
?51????????boolean?matched?=?false;
?52?
?53????????//使用ant匹配URL
?54?
?55????????if?(isUseAntPath())?{
?56?
?57????????????matched?=?pathMatcher.match(resourceName_url,?url);
?58?
?59????????}?else?{//perl5编译URL
?60?
?61????????????Pattern?compliedPattern?=?null;
?62?
?63????????????Perl5Compiler?compiler?=?new?Perl5Compiler();
?64?
?65????????????try?{
?66?
?67???????????????compliedPattern?=?compiler.compile(resourceName_url,?Perl5Compiler.READ_ONLY_MASK);
?68?
?69????????????}?catch?(MalformedPatternException?e)?{
?70?
?71???????????????e.printStackTrace();
?72?
?73????????????}
?74?
?75????????????matched?=?matcher.matches(url,?compliedPattern);
?76?
?77????????}
?78?
?79????????//匹配正确,获取响应权限
?80?
?81????????if?(matched)?{
?82?
?83????????????//获取正确匹配URL资源对应的权限
?84?
?85????????????ResourcDetail?detail?=?cacheManager.getResourcDetailFromCache(resourceName_url);
?86?
?87????????????authorities?=?detail.getAuthorities();
?88?
?89????????????break;
?90?
?91????????}
?92?
?93?}
?94?
?95????????//将权限封装成ConfigAttributeDefinition对象返回(使用ConfigAttributeEditor)
?96?
?97????????if?(authorities.length?>?0)?{
?98?
?99????????????String?authTemp?=?"";
100?
101????????????for?(GrantedAuthority?grantedAuthority?:?authorities)?{
102?
103???????????????authTemp?+=?grantedAuthority.getAuthority()?+?",";
104?
105????????????}
106?
107????????????String?authority?=?authTemp.substring(0,?(authTemp.length()?-?1));
108?
109????????????System.out.println(authority);
110?
111????????????ConfigAttributeEditor?attributeEditor?=?new?ConfigAttributeEditor();
112?
113????????????attributeEditor.setAsText(authority.trim());
114?
115????????????return?(ConfigAttributeDefinition)attributeEditor.getValue();
116?
117????????}
118?
119????????returnnull;
120?
121??}

我们这里同样使用了缓存,它参考自系统的UseCache接口的实现,这里不在介绍,你可以查看本例的源代码和系统的实现和本例的配置文件。这里将用户请求的URL地址与从数据库中获取的受保护的URL资源使用ant和perl5匹配(这取决与你的配置),如果匹配成功则从缓存中获取访问该资源需要的权限信息,并将其封装成ConfigAttributeDefinition对象返回,这里使用org.springframework.security.ConfigAttributeEditor类,该类提供了一个setAsText(String s),该方法收取一个字符串作为参数,在该方法中创建ConfigAttributeDefinition对象并将字符串参数传递给ConfigAttributeDefinition类的构造函数来初始化该对象。详细的实现还是请你看源代码。现在我们在配置文件添加自己的实现,如下:

<!--<br /> <br /> Code highlighting produced by Actipro CodeHighlighter (freeware)<br /> http://www.CodeHighlighter.com/<br /> <br /> -->1?<bean?id="objectDefinitionSource"
2????? class="org.security.intercept.web.DataBaseFilterInvocationDefinitionSource"
3????? p:convertUrlToLowercaseBeforeComprison="true"
4??????p:useAntPath="true"
5??????p:cacheManager-ref="securityCacheManager"/>

??? convertUrlToLowercaseBeforeComprison属性定义了在匹配之前将URL都转换为小写,useAntPath属性定义使用Ant方式匹配URL,cacheManager属性定义了指向另一个Bean的引用,我们使用它从缓存中获取相应的信息。

2 自定义MethodDefinitionSource

将方法资源存放在数据库中的实现与URL资源类似,这里不在累述,下面是DataBaseMethodInvocationDefinitionSource的源代码,读者可以参考注释进行阅读(该类也是继承自一个自定义的抽象类AbstractMethodDefinitionSource):

<!--<br /> <br /> Code highlighting produced by Actipro CodeHighlighter (freeware)<br /> http://www.CodeHighlighter.com/<br /> <br /> -->?1?public?ConfigAttributeDefinition?lookupAttributes(Method?method,?Class?targetClass)?{
?2?
?3????????//?TODO?Auto-generated?method?stub
?4?
?5????????//初始化资源并缓存
?6?
?7????????securityCacheManager.initResourceInCache();
?8?
?9????????//获取所有方法资源
10?
11????????List<String>?methods?=?securityCacheManager.getMethodResources();
12?
13????????//权限集合
14?
15????????Set<GrantedAuthority>?authSet?=?new?HashSet<GrantedAuthority>();
16?
17????????//遍历方法资源,并获取匹配的资源名称,然后从缓存中获取匹配正确
18?
19????????//的资源对应的权限(ResourcDetail对象的GrantedAuthority[]对象数据)
20?
21????????for?(String?resourceName_method?:?methods)?{
22?
23????????????if?(isMatch(targetClass,?method,?resourceName_method))?{
24?
25???????????????ResourcDetail?detail?=?securityCacheManager.getResourcDetailFromCache(resourceName_method);
26?
27???????????????if?(detail?==?null)?{
28?
29???????????????????break;
30?
31???????????????}
32?
33???????????????GrantedAuthority[]?authorities?=?detail.getAuthorities();
34?
35???????????????if?(authorities?==?null?||?authorities.length?==?0)?{
36?
37???????????????????break;
38?
39???????????????}
40?
41???????????????authSet.addAll(Arrays.asList(authorities));
42?
43????????????}
44?
45????????}
46?
47????????if?(authSet.size()?>?0)?{
48?
49????????????String?authString?=?"";
50?
51????????????for?(GrantedAuthority?grantedAuthority?:?authSet)?{
52?
53???????????????authString?+=?grantedAuthority.getAuthority()?+?",";
54?
55????????????}
56?
57????????????String?authority?=?authString.substring(0,?(authString.length()?-?1));
58?
59????????????System.out.println(">>>>>>>>>>>>>>>"?+?authority);
60?
61????????????ConfigAttributeEditor?attributeEditor?=?new?ConfigAttributeEditor();
62?
63????????????attributeEditor.setAsText(authority.trim());
64?
65????????????return?(ConfigAttributeDefinition)attributeEditor.getValue();
66?
67????????}
68?
69????????returnnull;
70?
71?}

??? isMatch方法用于对用户当前调用的方法与受保护的方法进行匹配,与URL资源类似,请参考代码。下面是applicationContext-security.xml文件中的配置,请查看该配置文件。

<!--<br /> <br /> Code highlighting produced by Actipro CodeHighlighter (freeware)<br /> http://www.CodeHighlighter.com/<br /> <br /> -->1?<bean?id="methodDefinitionSource"
2???? class="org.security.intercept.method.DataBaseMethodInvocationDefinitionSource"
3?????p:securityCacheManager-ref="securityCacheManager"/>

securityCacheManager属性定义了指向另一个Bean的引用,我们使用它从缓存中获取相应的信息。这个Bean和前一节中介绍的一样。只是这里我们获取的是方法保护定义资源。

??? 本文到此也结束了,还请各位多指教。

?来自http://www.blogjava.net/redhatlinux/archive/2008/09/01/226010.html

热点排行