数据库表设计:管理员,角色,页面,模块
(1)、模块是属于页面,模块可以是页面上的一个按钮或某一块内容
(2)、页面分为一级页面和二级页面,一级页面作为导航页面,二级页面是导航下的子页面
(3)、角色可以根据需要来选择页面和页面上的模块的权限,读,写,无读无写
(4)、管理员来选择角色,角色之间的权限可以合并,以大的权限为准
将权限在spring容器启动的时候加载进缓存,在更新管理员角色或修改角色权限时刷新缓存。
当然把权限放入缓存的时候是已经根据管理员来区分好了具体拥有的权限,在需要的时候只需要取就可以了。
放入Spring缓存中的权限是一个Map<String,Map<String,String>>,外面的Map的key是管理员的id,value即Map<String,String>是具体的页面和模块的读写权限
用struts2的拦截器来控制所拥有的页面权限,然后在具体的action中从spring缓存中获取该页面所拥有的模块权限。
初始化权限,当管理员登陆时,由struts2的拦截器来初始化所拥有的导航页面权限,进入到具体的页面时,从spring的缓存中去该管理员该页面的权限,然后进行权限控制
如何控制页面按钮等这些细小元素的权限
权限管理并不只是一些功能的权限管理,比如查询订单、修改订单等权限。还包括一些细小元素,比如:
1,下拉框:当总公司人员登录的时候,下拉框里面显示各个分公司名称;当分公司人员登录的时候,显示该分公司下属子公司名称。
2,按钮、链接等:查询数据列表每行记录尾部都有一个操作链接“删除”和“修改”。该链接只在当用户具有对该数据有操作权限的时候,才显示,否则不予显示。
Ralasafe-demo就给了这样的例子。总公司人可以查询所有数据,但总公司人只能删除总公司数据。所以,在非公公司数据后面,我们不显示“删除”、“修改”链接。
Ralasafe中间件,将这种权限命名为:非角色权限。因为,这些细小元素,不需要向查询订单、修改订单这些功能那样,需要设置角色权限。只要控制其数据权限即可。
今天说的登录控制,内容主要有:哪些页面需要登录控制、登录验证逻辑、登录后页面转向哪里,以及权限菜单等问题。虽然本系列讲解权限管理,尤其是数据级权限管理。但严格意义来说,登录控制,并不属于权限管理内容。它属于用户身份认证内容。权限基本都与用户相关,用户首先就涉及到用户名密码验证。所以我们从这里开始说起。
需求考察
仔细考察登录控制,无外乎这些需求:
- 哪些页面需要登录后才能查看,而且哪些页面还需要进一步验证角色权限;
- 登录页面在哪里?
- 登录用户名、密码验证;
- 登录后转向哪个页面?
解决方案
- 登录界面和登录转向后页面,由开发人员编写,这属于个性化内容,有CSS、页面布局等;
- 哪些页面需要登录才能查看,可以通过Filter来控制:哪些页面需要控制,使用web.xml里面的url-pattern,是否登录使用Filter验证session;
- 哪些页面还需要进行角色权限验证,这个我们拆分出去,做为功能权限验证,以后再谈;
- 用户名、密码验证可以共用:就是从request中读取用户名、密码值,或许可能还要对密码进行加密,然后与数据库用户表相关字段进行比对。
- 登录后页面转向:通过给session添加一个gotoPage属性,验证成功后转向该页面即可。
实例说明
配置LoginFilter
我们先将LoginFilter配置到web.xml文件:
- <filter>
- <filter-name>ralasafe/LoginFilter</filter-name>
- <filter-class>org.ralasafe.webFilter.LoginFilter</filter-class>
- <init-param>
- <param-name>loginPage</param-name>
- <param-value>/ralasafe/demo/login.jsp</param-value>
- </init-param>
- <init-param>
- <param-name>uniqueFieldsParams</param-name>
- <param-value>loginName</param-value>
- </init-param>
- <init-param>
- <param-name>passwordParam</param-name>
- <param-value>password</param-value>
- </init-param>
- <!--init-param>
- <param-name>encryptMethod</param-name>
- <param-value>shahex</param-value>
- </init-param-->
- </filter>
- <filter>
- <filter-name>ralasafe/LoginFilter</filter-name>
- <filter-class>org.ralasafe.webFilter.LoginFilter</filter-class>
- <init-param>
- <param-name>loginPage</param-name>
- <param-value>/ralasafe/demo/login.jsp</param-value>
- </init-param>
- <init-param>
- <param-name>uniqueFieldsParams</param-name>
- <param-value>loginName</param-value>
- </init-param>
- <init-param>
- <param-name>passwordParam</param-name>
- <param-value>password</param-value>
- </init-param>
- <!--init-param>
- <param-name>encryptMethod</param-name>
- <param-value>shahex</param-value>
- </init-param-->
- </filter>
这里有几个属性上面没有提到。uniqueFieldsParams表示页面的哪些字段可以唯一确定用户,一般情况下只有一个参数。这里配置是loginName(Login页面的字段input name属性),那么login.jsp里面就有这样的代码:
- <input name="<SPAN style="COLOR: #ff0000"><STRONG>loginName</STRONG></SPAN>" type="text" class="username">
- <input name="<span style="color: #ff0000;"><strong>loginName</strong></span>" type="text" class="username">
如果需要多个字段确定一个用户,比如需要用户名+机构唯一确定,那么web.xml可以配置成:
- <init-param>
- <param-name>uniqueFieldsParams</param-name>
- <param-value>loginName,<SPAN style="COLOR: #ff0000"><STRONG>unitId</STRONG></SPAN></param-value>
- </init-param>
- <init-param>
- <param-name>uniqueFieldsParams</param-name>
- <param-value>loginName,<span style="color: #ff0000;"><strong>unitId</strong></span></param-value>
- </init-param>
passwordParam表示页面哪个字段是密码字段;encryptMethod表示密码使用什么加密方法,ralasafe提供了base64,md5hex,shahex加密方法。你也可以自行开发加密方法,详见LoginFilter javadoc。
哪些页面需要登录验证
我们只要将需要验证的页面,安装该Filter即可。配置web.xml:
- <filter-mapping>
- <filter-name>ralasafe/LoginFilter</filter-name>
- <url-pattern>/ralasafe/demo/*</url-pattern>
- </filter-mapping>
- <filter-mapping>
- <filter-name>ralasafe/LoginFilter</filter-name>
- <url-pattern>/ralasafe/demo/*</url-pattern>
- </filter-mapping>
表示ralasafe/demo下的所有URL资源都需要经过LoginFilter过滤。
验证逻辑
验证逻辑全部在LoginFilter里面。LoginFilter主要做这些事情:
- 首先判断客户端是否在请求登录页面,如果是,那么转向登录页面,以免造成死循环;
- 然后如果是请求登录,那么读取用户名、密码(可能密码还要加密)进行验证;
- 如果不是请求登录,那么这时需要查看session用户是否登录了。如果没有登录,那么转到登录页面;如果已经登录继续doChain。
登录页面转向
如果客户端在没有登录的情况下,请求/ralasafe/demo/employMng路径,那么登录成功后,系统最好直接转到该路径。LoginFilter会将该路径采集下来,以“gotoPage”属性保存到session。登陆成功后,会移除掉该属性(不占用session资源)。
此时,LoginFilter的form action是这么编写的:
- <%
- String gotoPage = (String) session.getAttribute("gotoPage");
- if (StringUtil.isEmpty(gotoPage)) {
- gotoPage = "main.jsp";
- }
- %>
- <form name="" action="<%=gotoPage%>" method="post">
- <%
- String gotoPage = (String) session.getAttribute("gotoPage");
- if (StringUtil.isEmpty(gotoPage)) {
- gotoPage = "main.jsp";
- }
- %>
- <form name="" action="<%=gotoPage%>" method="post">
至此,我相信一切你都明白了。
------------------------分隔线----------------------------
毕竟我们搞ralasafe很多年了(04年开始的),所以很难更好地站在使用者角度(虽然,我们在努力,一直在努力),内容肯定有欠缺和错误。欢迎大家提出宝贵建议,欢迎大家努力拍砖!
我们也将继续保持开源,为大家贡献好的软件。也恳请大家支持我们!
注:下期讲解 2, URL权限控制:哪些页面访问需要进行角色权限验证,怎样验证最简单有效,如何处理验证失败情况;
Struts Plus, Struts + 项目, 计划包含极速表单验证框架, 权限管理等子模块. 目前主要关注于 Struts 2 方面的生产力提高项目, 主要基于注解方式进行增强, 并提供抽象层, 使项目仅仅依赖于 Struts 本身, 而不需要强制您使用某种业务层和数据层框架.
子模块1:Struts 2 极速表单验证框架 Struts 2 QuickFormValidation (已推出)¶
- 最快速的后台表单验证框架
- 简洁,快速的验证语法
- 无需编写验证提示信息
- 错误消息在指定地方显示
- 支持组合验证
- 易于扩展
- 基于标准的Java Annotaction添加验证,易于和现有项目的无缝集成
- 特殊应用场景支持,如:密码确认,结束日期必须大于开始日期
- 支持前后台一致的验证规则
-------------------------------------------- 总大纲 --------------------------------------
Ralasafe开源有段时间了,大约有2个月了。根据社区的反馈,我打算围绕Ralasafe最佳实践,书写一系列BLOG。
大体内容有:
1, 登录控制: 哪些页面需要登录后才能访问,登录用户名、密码验证,登录转向页面;
2, URL权限控制:哪些页面访问需要进行角色权限验证,怎样验证最简单有效,如何处理验证失败情况;
3, 数据级权限管理方案探讨:选择中间件呢还是框架?
4, Ralasafe体系结构: 用户怎么读取,用户有哪些字段,怎样与应用基础;
5, 数据级查询权限管理: 如何给不同的人分配不同的查询数据权限,返回where条件呢,还是直接返回结果集?
6, 数据级决策权限管理: 如何给不同的人分配不同的数据操作权限,当用户不具备权限怎么办?
7, 其他细小的权限控制: 如下拉框显示内容;按钮、链接是否显示,图片是否显示等。
-------------------------------------------- ------- --------------------------------------