Spring Security优略只见.docx
《Spring Security优略只见.docx》由会员分享,可在线阅读,更多相关《Spring Security优略只见.docx(11页珍藏版)》请在冰豆网上搜索。
![Spring Security优略只见.docx](https://file1.bdocx.com/fileroot1/2023-2/24/46af9bc4-029b-4e1f-b513-8739053c9266/46af9bc4-029b-4e1f-b513-8739053c92661.gif)
SpringSecurity优略只见
SpringSecurity优劣之我见
拜读了SpringSecurity相关帖子和SpringSecurity参考文档。
现将我理解的SpringSecurity写下来和大家共享。
本文目的是从SpringSecurity能够提供的功能、以及基本原理角度分析,并不深入到如何编码。
然后反过来,审查我们的软件系统需要哪些权限控制。
进而评审SpringSecurity的适用性。
本文力求文字简单,概念也简单。
--------------------------------------------------------------
文章大纲:
SpringSecurity如何控制权限
概要
与WEB系统的集成
控制内容
细粒度权限控制
我们理想中的权限管理
客户对权限管理的需求
开发中遇到的难点
我们理想的权限管理
SpringSecurity的评价
优点
缺点
--------------------------------------------------------------
SpringSecurity如何控制权限
概要
Spring使用由Filter组成的Chain,来判断权限。
如下图所示:
Spring预定义了很多out-of-boxedfilter供开发者直接使用。
每个Filter一般情况下(有些Filter是abstract的),都和配置文件的一个元素(有的情况下可能是属性)对应。
比如:
AUTHENTICATION_PROCESSING_FILTER,对应配置文件里面的:
http/form-login元素。
如果Spring提供的Filter不能满足系统的权限功能,开发者可以自定义Filter,然后把Filter放在某个FilterChain的某个位置。
可以替换掉原有FilterChain的某个Filter,也可以放在某个Filter之前或者之后。
总之,SpringSecurity采用FilterChain模式判断权限,Spring提供了一些Filter,也支持开发者自定义Filter。
与WEB系统的集成
使用JavaEE的Filter(非Spring的Filter)机制,将需要权限判断的url,“牵引”给Spring的FilterChain即可。
一般情况下,将所有的url都引入FilterChain。
当然也可以在web.xml配置需要权限判断的url(配置filter-mapping/url-pattern)。
Spring的配置文件也支持过滤掉不需要权限判断的url(配置http/intercept-url元素)。
控制内容
SpringSecurity提供了如下内容的控制:
1. url;
2. beanmethod;
3. httpsession。
url:
可以分为需要权限判断的url,不需要权限判断的url,登录表单url。
通过我对spring相关帖子和参考文档的阅读,需要权限判断的url。
仅限于做角色判断,就是说判断当前用户是否具有指定的角色。
beanmethod:
Spring支持对Servicelayermethod做权限判断。
通过我对spring相关帖子和参考文档的阅读,也仅限于做角色判断。
配置方式有2种:
1. 写在Java源代码里面,如:
@Secured("ROLE_TELLER")(该方法只有具有TELLER角色的用户能够访问,否则抛出异常);
2. 写在配置文件里面,如:
(该bean的所有set方法,只有具有ADMIN角色的用户能够访问,否则抛出异常)。
3.httpsession:
控制一个用户名是否能重复登录,以及重复登录次数,并非重试密码次数。
另外,SpringSecurity还提供了如下一些功能:
1. rememberme,记住我;
2. form-login登录控制;
3. 多种身份认证功能;
4. 用户密码加密和“salt”功能;
5. http协议控制;
6. 访问端口控制;
7. Pre-Invocation&After-Invocation。
rememberme,记住我:
还记得浏览器采用cookie记住用户名和密码自动登录吗?
好像就是这个(不知道我理解错了没有,应该没有。
只是我不大敢相信)。
使用这个功能,开发者在登录页面,使用spring自定义的标签。
form-login登录控制:
有些页面不允许匿名访问,那么当匿名访问这些页面的时候,将弹出(或者转到)form-login窗口(或者页面)。
这里又牵引出2个问题:
1,输入用户名和密码后怎样验证;2,密码是否需要加密,怎么加密。
多种身份认证功能:
Spring提供了丰富的用户身份认证功能。
身份认证是什么意思?
比如您告诉我“我是神仙”。
那么我会问您“凭什么证明您是神仙”。
这就是身份认证。
认证手段一般是保存到数据库表的用户名/密码,usbkey,ldap等。
一般情况下,我们都使用用户名/密码的。
用户密码加密和“salt”功能:
密码采用md5,还是sha加密算法。
如果我们对密码加密的时候,不想仅仅对密码加密,还想把用户名和密码放在一起加密做为加密后的密码。
那么使用salt吧。
salt支持也读取用户的其他属性,不仅是用户名。
http协议控制:
哪些url,必须采用https访问呢?
哪些url必须采用http访问呢?
哪些又两者都可以呢?
通过这个配置。
访问端口控制:
类似http协议控制,控制url和访问端口之间的关系。
Pre-Invocation&After-Invocation:
在方法调用之前做权限判断,还是方法调用之后做权限判断呢?
一般情况下是之前调用。
也有情况下是之后调用。
具体例子可以看官方文档(22.3小节)。
细粒度权限控制
由上面分析,我们看到url、method的权限判断,都仅限于用户角色权限判断。
事实上Spring使用投票(Voter)机制,来做权限判断。
用户角色权限也是一种投票。
投票这个词,听起来不容易懂。
举例:
董事会开会,各个股东投票以表决决议是否通过。
Spring的角色投票器,只会投出一票。
我们平时所说的投票至少要2张票吧,一张还叫什么投票。
Spring的投票有3种结果:
允许、拒绝和弃权。
弃权?
真的有点晕。
呵呵,这种情况下还弃权。
那么投票器,如何集成到Spring的Filter里面呢?
Spring的Filter一般都由一个Manager支撑着。
比如accessDecisionManager,可以由RoleVoter和BasicAclEntryVoter提供投票。
accessDecisionManager根据RoleVoter,BasicAclEntryVoter投票结果,做出决策判断。
细粒度(数据级)的权限控制,SpringSecurity提供了一种模型以及相关实现。
下面我简要说说这个模型。
举例:
张三授权查询华北区域客户资料,李四授权查询华南区域客户资料。
那么,首先会对所有客户记录做个标示(相当于取个id),然后在acl-entry表给张三授权华北所有客户访问权限;给李四华南区域所有客户权限。
表记录大致是这样的:
访问用户
被访问数据
授权操作
张三
华北电力客户1
读取
张三
华北电力客户2
读取
李四
华南电力客户1
读取
…
…
…
这个模型的缺点是非常明显的:
1. 和业务数据绑定死了,业务数据的增/删,需要维护该权限表;
2. 在大数据量的情况下,系统效率低下。
因此,开发者需要自己书写投票器了。
我们理想中的权限管理
客户对权限管理的需求
这里是指我们服务的最终用户,而不是软件开发者。
客户对权限管理的需求,大体可以概括如下:
1. 自主灵活地管理角色、角色权限,并将角色赋予系统相关用户;
2. 数据安全。
系统展现数据是满足权限的,在系统内部搜索数据也必须在相应权限访问内,对系统数据进行增加、修改、删除必须是满足权限的;
3. 没有功能的按钮、菜单、数据等等,就不要在界面上出现了。
开发中遇到的难点
管理用户、角色、权限,以及三者之间的关系,这种典型的RBAC模型,非常容易,没有任何困难。
困难的是,数据级权限控制。
这是和业务直接挂钩的,最复杂,而且会经常因为客户需求表达不到位、开发人员需求理解不到位、系统框架库表结构发生变化,而不断变化的。
这种变化,不仅需要编码,而且还需要重新测试。
甚至这种变化会波及到其他模块,甚至整个系统。
系统开发经历几次变化下来,代码里面散布着if/else,散布着sql语句。
导致badsmell。
我们理想的权限管理
我们期望的权限管理,应该具有这么几个特性:
1. 能实现角色级权限;能实现数据级权限;
2. 简单、易操作,能够应对各种需求;
3. 应对需求变更能力强;
4. 最好有相关界面,比如权限管理界面、角色管理界面,角色和权限关系维护界面,用户和角色关系维护界面。
如果没有界面,也是可以接受的。
毕竟这些页面需要最终用户来使用,不同用户对系统的界面要求不同。
因此我们并不期望统一的管理界面。
SpringSecurity的评价
在SpringSecurity世界里,可以区分出哪些资源可以匿名访问,哪些需要角色权限,又是哪个页面提供登录功能;怎样进行用户身份认证,用户的密码如何加密。
哪些资源必须使用https协议,资源和访问端口有怎样的对应关系。
下面就优点和缺点对SpringSecurity进行点评。
优点
总体说来SpringSecurity具有以下几个优点:
1. 提供了一套权限框架,这套框架是可行的;
2. 提供了很多用户身份认证功能,可以节约大量开发工作;
3. 提供了角色判断功能,这点既是优点又是缺点;
4. 提供了form-login、rememberme等控制。
其中2、4两点,对于我们中国开发者(我对国外系统不大了解),可用性并不大。
我们的系统大多采用用户名/密码身份认证模式,大多公司都有可复用代码。
form-login、rememberme等这些功能,并不是难以开发,而且可用之处也并不多。
缺点
我个人认为SpringSecurity存在以下几个硬伤:
1.角色被“编码”到配置文件和源文件,这样最终用户就不能创建角色了。
但最终用户期望自己来控制角色。
因为在项目实施过程中,客户可能并不能确定有哪些角色,以及角色怎么分配给系统用户。
角色大多需要等到系统上线后,才能确定。
这些编码有:
a) url的权限控制,;
b) java方法的权限控制,@Secured("IS_AUTHENTICATED_ANONYMOUSLY");
c) java方法的权限控制,;
2. RBCA这种被广泛运用的模型,没有在SpringSecurity体现出来;
3. SpringSecurity没有提供好的细粒度(数据级)权限方案,提供的缺省实现维护工作量大,在大数据量情况下,几乎不可用;
4. SpringSecurity对于用户、角色、权限之间的关系,没有提供任何一种维护界面。
不过从SpringSecurity角度看,确实没有必要有界面。
角色创建、角色和权限直接的关系,都被“编码”到配置文件和源文件了;
5. SpringSecurity学习难度大,配置文件还是很多。
我承认有很多高手,但我们也看到有很多新人加入软件开发领域。
付出如此大的学习代价,获得这么一点点好处,个人觉得并不值得。
附言:
本人在JavaEye创建“权限管理”圈子快2周了,吸引不少网友进来。
我感到很高兴,也很荣幸。
由于SpringSecurity运用范围还是比较广的,所以我打算好好学习一下,把学习经验和大家分享一下。
欢迎大家加入“权限管理”圈子讨论,探讨对权限管理的认识、看法、建议等等。
论坛帖子:
我们公司从以前的acegi一直到现在的springsecurity都在用,但有点建议就是,不要按官方例子去做(官方例子太烂而且某些地方有误导之嫌,还有bug呵呵),不要用命名空间xml方式去配置,springsecurity是我用过的关于权限管理的最强大框架,但用好并不是易事,可以说springsecurity只是半成品,他的很多东西都需要自己去实现和修改才能真正发挥出他的威力,如果你们公司有一定的研发能力的话,在它的基础上做些改进,甚至可以做到字段级的权限管理粒度,我们就这么做了,效果相当的完美
强调一点,springsecurity和spring结合是非常密切的,要想用好springsecurity,你们的架构中至少要引入spring容器来管理所有需要管理权限的东西,比如数据层、服务层等,虽然按官方的声明是可以脱离spring容器独立使用springsecurity,但那样实现起来相对比较耗费精力,并且需要自己去做部分权限判断。
按你所举的例子里,我不确定你们是否后台只用servlet来处理数据,请告诉我你们准确的架构。
springsecurity 的官方demo写的有点烂,甚至可以说是不值一看,尤其是它的基于SpringXMLschema的简化配置和硬编码的应用方式误导了很多想在产品化中应用它的人,严中掩盖了它本身强大的设计思想。
springsecurity本身可以说只是一个半成品,而它的demo也是基于这个半成品将就着写出来的,当然不适合产品化的灵活应用。
不过对付简单网站或入门学习还是够用的。
从某中程度上来说demo只是提供了springsecurity 最原始的一种应用方式。
另一方面springsecurity 是完全能应付产品化应用的:
适用架构
功能
权限模式
1
提供各种认证方式
2
B/S
基于过滤器链方式的url访问控制。
基于ss提供的tag控制ui视图组件的显/隐
RBAC
3
B/S、C/S
基于spring容器提供的AOP方式的切面实现method访问控制
RBAC
4
B/S、C/S
基于spring容器提供的AOP方式的切面实现事后数据审查和过滤
ACL、RBAC
5
B/S、C/S
基于spring容器提供的AspectJ方式的切面实现 对任意bean的字段控制
RBAC
其中第4点能实现你例子中所说的对各个单据授权,即对象(记录)级授权控制
(最好用JPA方式实现,这样可以避免JDBC的一些通用性问题)
如果你要实现完全基于数据库的动态权限定义,安全对象资源定义、授权、角色定义、用户组、角色分层、记录级授权、字段级授权,基于分层组织架构权限等,并且使权限管理模块完全可插拔到不同的项目中,你必须完全抛弃demo的那种配置方式,并结合spring使用java代码编程式去配置。
这就需要你对spring容器、面向切面编程(AOP和AspectJ)、RBAC模型、ACL模型、都要有比较深入的理解。
还强调一点,springsecurity是我目前见到过的最强大的安全框架,几乎能实现目前企业应用中所有的权限管理需求并且可以完全和项目解耦。
但springsecurity入门相对其他框架难度要大很多,不是因为它本身就难,而是因为权限管理涉及的知识点太多。
只要你琢磨透彻了,它也会给你其他框架无法比拟的好处。
而且权限管理就像数据库一样重要而且基础的一块,基本上什么项目都需要。
以后在任何项目中,只要修改数据库中的权限定义,就都能重用到几乎所有的项目了。
目前网上能找到的关于springsecurity的中英文文章都不少,但大部分都比较老旧而且一般只涉及URL拦截和简单的方法拦截的垃圾文章,而对于ACL结合方法拦截或RBAC模式实现记录级授权还比较少有价值的文章,对于字段级授权实现就几乎没有。
另一方面,对于springsecurity和各种主流数据交换应用框架的无缝整合,如Flex(BlazeDS、LCDS),Ajax(dwr、Extjs)等等的文章更是罕见。
(可能是我没找到,开源框架很多东西得自己研究,呵呵)
我是springsecurity的忠实用户,从acegi到springsecurity2.0.4已经用了4年多了,在它的基础上做了很多实现和扩展,现在已经能实现到项目中springsecurity完全不用一行xml配置,完全能基于任何数据库定义和管理所有权限和授权。
并且支持字段级粒度授权,所有的这一切都只是数据库中的一些记录定义而已,这样就可以完全的动态定义和权限相关的一切东西了。
呵呵