看了网上一些关于权限控制的帖子,越看越迷糊,什么用aop(aspect oriented programming,面向方面编程),用容器,rbac(基于角色的访问控制方法),sso,jive的proxy模式等等等等,且又是role又是group,真是头都大了,先写个简单的实现方法,以后再研究高深的。
此方法不依赖容器 框架,适用于小系统(主要jsp页面要少于100,因为是硬编码到jsp),适用于要精确控制页面field的情况较多的系统。
(插句话:要分清权限控制与业务逻辑,业务逻辑就是情况由系统运行时的某些条件决定,如学生管理系统中,某一学生进入系统,只能看自己的记录,因为可看的记录是由学号来决定的,所以这是业务逻辑,而又如学生不能看老师的记录,这是有学生的身份来决定的,所以这是权限控制。)
好了,进入正题!
建表:
| user(user信息: userid userpassword 等) role(role描述:roleid roledesc) permission(permission描述:permissionid permissiondesc) user-role(user role对应关系表:userid roleid) role-permission(role permission对应关系表:roleid permissionid) user-permission(user permission对应关系表:userid permissionid) |
重要申明: 1 此处role没有继承关系,只是permission的集合
2 user-permission表只是为了方便,其数据是根据user-role role-permission两表得来,只有在user-role role-permission两表有更新的时候更新此表,并不能单独赋予user某个permission,只能赋予user一个或多个role。
3 permission的分配,这是一个难点,很多比较复杂的权限控制系统也是因为这个才发展出来,此处把它尽量想简单,不考虑业务逻辑,以页面为视角,分两层,首先是需要控制的jsp页面,然后是需要控制的页面field(包括link,text,textbox,button等等),field这一层还有privilege之分(r和w,即可读和可写)
基本思路:进入jsp页面时,检查用户信息,查到用户有此permission就包含此代码,如果没有此permission就不包含此代码,此功能由tag来完成(不会写tag?不要紧,抄!)。看代码吧!
1 建表(如上)
2 建两个class(bean) (userprofile是用户基本信息 userpermission是permission )
| userprofile.java: package com.××.××.××; import java.util.collection; public class userprofile { private string userid; private string usertype; private string companyno; private string companyname; private string companytype; private collection userpermissions; |
| public string getuserid() { return userid; } public void setuserid(string userid) { this.userid = userid; } public string getusertype() { return usertype; } public void setusertype(string usertype) { this.usertype = usertype; } public string getcompanyno() { return companyno; } public void setcompanyno(string companyno) { this.companyno = companyno; } public string getcompanyname() { return companyname; } public void setcompanyname(string companyname) { this.companyname = companyname; } public string getcompanytype() { return companytype; } public void setcompanytype(string companytype) { this.companytype = companytype; } public collection getuserpermissions() { return userpermissions; } public void setuserpermissions(collection userpermissions) { this.userpermissions = userpermissions; } } userpermission.java: package com.××.××.××; public class userpermission { private int permissionid; private string privilege; public int getpermissionid() { return permissionid; } public void setpermissionid(int permissionid) { this.permissionid = permissionid; |
| } public string getprivilege() { return privilege; } public void setprivilege(string privilege) { this.privilege = privilege; } } 3 加两个tag(page与field): securitytagforpage.java: package com.**.**.taglib; import java.util.*; public class securitytagforpage extends tagsupport { private int permissionid; public int doendtag() throws jspexception { httpsession session = pagecontext.getsession(); //登陆时把该user的userprofile放到session里 userprofile userprofile = (userprofile)session.getattribute("userprofile"); collection collection= userprofile.getuserpermissions(); iterator it = collection.iterator() ; while(it.hasnext()) { userpermission userpermission = (userpermission)it.next(); if ((permissionid == userpermission.getpermissionid())) { return eval_page; } } return skip_page; } public int getpermissionid() { return permissionid; } public void setpermissionid(int permissionid) { this.permissionid = permissionid; } } |
| securitytagforfield: public class securitytagforfield extends tagsupport { private int permissionid; private string privilege; public int dostarttag() throws jspexception { httpsession session = pagecontext.getsession(); userprofile userprofile = (userprofile)session.getattribute("userprofile"); collection collection= userprofile.getuserpermissions(); iterator it = collection.iterator() ; while(it.hasnext()) { userpermission userpermission = (userpermission)it.next(); if (privilege ==null) { if ( (permissionid == userpermission.getpermissionid())) { return eval_body_include; } } else { if ((permissionid == userpermission.getpermissionid()) &&(privilege.equals(userpermission.getprivilege()))) { return eval_body_include; } } } return skip_body; } public int getpermissionid() { return permissionid; } public void setpermissionid(int permissionid) { this.permissionid = permissionid; } public string getprivilege() { return privilege; |
| } public void setprivilege(string privilege) { this.privilege = privilege; } } |
4 在web-inf目录下建个securitytag.tld文件,内容如下:(改一下class的目录)
| <?xml version="1.0" encoding="iso-8859-1"?> <!doctype taglib public "-//sun microsystems, inc.//dtd jsp tag library 1.1//en" "http://java.sun.com/j2ee/dtds/web-jsptaglibrary_1_1.dtd"> <!-- a tag library descriptor --> <taglib> <tlibversion>1.0</tlibversion> <jspversion>1.1</jspversion> <shortname>security</shortname> <uri/> <info> access control! </info> <tag> <name>securityforfield</name> <tagclass>com.companyname.prjname.taglib.securitytagforfield</tagclass> <attribute> <name>permissionid</name> <required>true</required> </attribute> <attribute> <name>privilege</name> </attribute> </tag> <tag> |
| <name>securityforpage</name> <tagclass>com.companyname.prjname.taglib.securitytagforpage</tagclass> <attribute> <name>permissionid</name> <required>true</required> </attribute> </tag> </taglib> |
5 修改需要控制的jsp
在jsp页面这样写:
| <%@ taglib uri="/web-inf/securitytag.tld" prefix="security" %> <%@ page import="com.hp.elog2.util.util" %> <security:securityforpage permissionid="36" /> ....... <security:securityforfield permissionid="46" privilege="r"> <td><html:text name="formbean" property="property1" readonly="true" /></td> </security:securityforfield> <security:securityforfield permissionid="46" privilege="w"> <td><html:text name="formbean" property="property1" /></td> </security:securityforfield> ...... |
这样就大功告成了,建议在所有jsp页面完成后再做权限控制这一块(添加tag),主要都是些copy+c和copy+v的工作。
此方法最大的问题就是hardcode太多,但结构简单,思路清晰,适用范围广。
复杂的方法希望同道之士于我联系leon_sandy@tom.com,共同研究!