1+1=2,0+0=0

日月累积
posts - 7, comments - 50, trackbacks - 0, articles - 0
  BlogJava :: 首页 :: 新随笔 :: 联系 :: 聚合  :: 管理
在上文中我们提到了一个资源对应一个数据库表,在T_ResourceInfo表中我们也提到了有一个字段专门来记录表名,然后我书写一个资源配置文件,用来配置我的业务类与资源的对应关系,代码如下:
1<?xml version="1.0" encoding="GB2312"?>
2<data>
3    <mapping SysName="s">
4        <module BusinessClass="com.ideal.framework.business.businessface.IBLogin" TableName="user_info"/>
5    </mapping>
6</data>
其中BusinessClass代表业务接口,TableName代表该业务接口所要操作的数据实体(数据表),此处的TableName必须与T_ResourceInfo中的Module_Code一致。
用户登录后,需要操作T_UserInfo这个表时,我们的逻辑将会把请求带入IBLogin这个业务逻辑中,在我们的AOP模块中,可以用MethodInterceptor来截获当前用户想要操作的业务逻辑,当AOP模块截获了用户的请求,并判断用户想要操作IBLogin这个业务逻辑,它将在上述的mapping文件中去找该业务逻辑对应的资源user_info,然后去资源表中判断该用户是否有操作user_info的权限。
(注:上述xml文件在系统初始化时候加载入内存中,我们也可以将权限信息也加载在内存中,不会很大,一切资源在内存中操作,非常快)
下面我贴点代码,在系统初始化时:
 1package com.ideal.framework;
 2
 3import java.util.*;
 4import java.sql.*;
 5import com.ideal.framework.dao.daoface.*;
 6import com.ideal.framework.po.*;
 7
 8public class ResourceContainer
 9{
10    public static boolean change_resource; //更新资源  系统持久
11    public static Vector resource_container = new Vector(); //资源容器  用户持久
12    private IUserRoleDAO m_user_role_dao;
13    private IRoleResourceDAO m_role_resource_dao;
14    private IUserDAO m_user_dao;
15
16    public ResourceContainer()
17{
18    }

19
20    public void setUserResource()
21    {
22        System.out.println("initialize resource:");
23        List user_list = m_user_dao.getAllUser();
24        for (int i = 0; i < user_list.size(); i++)
25        {
26            UserInfo user = (UserInfo) user_list.get(i);
27            List role_list = m_user_role_dao.getRoleInfo(user);
28            for (int j = 0; j < role_list.size(); j++)
29            {
30                RoleInfo role = (RoleInfo) role_list.get(j);
31                List resource_list = m_role_resource_dao.
32                    getResourceInfo(role);
33                for (int k = 0; k < resource_list.size(); k++)
34                {
35                    Hashtable hash = new Hashtable();
36                    hash.put(user.getLoginId(), resource_list.get(k));
37                    hash.put("Unit_"+user.getLoginId(), user.getUnit());
38                    hash.put("Role_"+user.getLoginId(), role.getRoleName());
39                    ResourceContainer.resource_container.add(hash);
40                }

41            }

42        }

43    }

44
45    public Vector getResource_container()
46    {
47        return resource_container;
48    }

49
50    public void setResource_container(Vector resource_container)
51    {
52        this.resource_container = resource_container;
53    }

54
55    public IRoleResourceDAO getM_role_resource_dao()
56    {
57        return m_role_resource_dao;
58    }

59
60    public IUserDAO getM_user_dao()
61    {
62        return m_user_dao;
63    }

64
65    public IUserRoleDAO getM_user_role_dao()
66    {
67        return m_user_role_dao;
68    }

69
70    public void setM_role_resource_dao(IRoleResourceDAO m_role_resource_dao)
71    {
72        this.m_role_resource_dao = m_role_resource_dao;
73    }

74
75    public void setM_user_dao(IUserDAO m_user_dao)
76    {
77        this.m_user_dao = m_user_dao;
78    }

79
80    public void setM_user_role_dao(IUserRoleDAO m_user_role_dao)
81    {
82        this.m_user_role_dao = m_user_role_dao;
83    }

84
85    public void setChange_resource(boolean change_resource)
86    {
87        this.change_resource = change_resource;
88    }

89
90    public boolean isChange_resource()
91    {
92        return change_resource;
93    }

94}

95
将用户对应的角色,资源信息加载如内存,另外在初始化时候的xml文件的树形结构也加载入内存,这边就不贴代码了
下面是AOP模块的advice代码:
package com.ideal.framework.sys.advice;

/**
 * <p>Title: BusinessAccessAdvisor</p>
 * <p>Description: 业务模块AOP权限监听器</p>
 * <p>Copyright: Copyright (c) 2006</p>
 * <p>Company: ideal</p>
 * 
@author alex
 * 
@version 1.0
 
*/


import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
import com.ideal.framework.InitResource;
import com.ideal.framework.util.XMLUtil;
import java.util.ArrayList;
import java.util.Hashtable;
import com.ideal.framework.sys.accesscontrol.GenericAccessBase;
import java.lang.reflect.Field;
import com.ideal.framework.po.*;
import java.lang.reflect.Method;
import java.util.*;
import java.io.*;
import javax.servlet.http.HttpServletRequest;

public class BusinessAccessAdvisor
    
implements MethodInterceptor
{

    
public BusinessAccessAdvisor()
    
{
    }


    
public Object invoke(MethodInvocation invocation) throws
        Throwable
    
{
        String user_name 
= "";
        Object obj 
= invocation.getArguments()[1];
        
if (obj instanceof HttpServletRequest)
    
{
            HttpServletRequest request 
= (HttpServletRequest)obj;
            user_name 
= (String)request.getSession().getAttribute("UserName");//取出用户名
        }

        String bean_name 
= invocation.getMethod().getDeclaringClass().getName();//取出用户想要操作的业务逻辑
        XMLUtil xml 
= (XMLUtil) InitResource.context.getBean("XMLUtil");
        ArrayList list 
= xml.getFieldList("mapping""s", xml.doc);
        
for (int i = 0; i < list.size(); i++)
    
{
            Hashtable hash 
= (Hashtable) list.get(i);
            
if (hash.get("BusinessClass").equals(invocation.getMethod().//判断用户是否有权操作该业务逻辑所对应表
                                                 getDeclaringClass().getName()))
        
{
                String table_name 
= (String) hash.get("TableName");
                GenericAccessBase access_controller 
= (GenericAccessBase)
                    InitResource.context.getBean(
"GenericAccessBase");
                
if (access_controller.CheckAccessPrivilege(user_name, table_name))//若用户有权操作该表,则让程序进入业务逻辑
            
{
                    
return invocation.proceed();
                }

            }

        }

        System.out.println(
"no permission .reject by " + bean_name);
        
return null;
    }

}

下面是判断用户是否具有操作该表权限的类:
 1package com.ideal.framework.sys.accesscontrol;
 2
 3import com.ideal.framework.InitResource;
 4import com.ideal.framework.util.XMLUtil;
 5import com.ideal.framework.po.UserInfo;
 6import com.ideal.framework.ResourceContainer;
 7import java.util.*;
 8//import com.ideal.framework.po.ResourceInfo;
 9
10public class GenericAccessBase
11{
12    UserInfo user;
13
14    public GenericAccessBase()
15    {
16    }

17
18    public void setUser(UserInfo user)
19    {
20        this.user = user;
21    }

22
23    public boolean CheckAccessPrivilege(String user_name, String table_name)
24    {
25        for (int i = 0; i < ResourceContainer.resource_container.size(); i++)
26        {
27            Hashtable temp_hash = (Hashtable)ResourceContainer.resource_container.get(i);//从内存中取出用户资源信息
28            if (temp_hash.containsKey(user_name))
29            {
30                ResourceInfo resource = (ResourceInfo)temp_hash.get(user_name);
31                if (table_name.trim().toLowerCase().equals(resource.getModuleCode().trim().toLowerCase()))//比对用户拥有的资源和当前的table_name
32                {
33                    return true;
34                }

35            }

36        }

37        return false;
38    }

39}

40
ok,到此为止,我们的底层拦截就完成了,接下来就是界面权限处理,界面权限比较复杂,因为用户可能具有添加权限,没有上传权限,有下载权限却没有更新权限等,情况很复杂,所以我们这边必须有一个判断当前用户是否具有这些复杂权限的类:
  1package com.ideal.framework.sys.privilege;
  2
  3/**
  4 * <p>Title: GenericPrivilegeBase</p>
  5 * <p>Description: 通用权限法则</p>
  6 * <p>Copyright: Copyright (c) 2006</p>
  7 * <p>Company: ideal</p>
  8 * @author alex
  9 * @version 1.0
 10 */

 11
 12public class GenericPrivilegeBase
 13{
 14    public final static int NO_PRIVILEGE = 0;
 15    public final static int QUERY_OR_USE_PRIVILEGE = 1;//察看权限
 16    public final static int CREATE_PRIVILEGE = 2;//添加权限
 17    public final static int DELETE_PRIVILEGE = 4;//删除权限
 18    public final static int UPDATE_PRIVILEGE = 8;//更新权限
 19    public final static int ALL_PRIVILEGE = QUERY_OR_USE_PRIVILEGE |
 20        CREATE_PRIVILEGE | DELETE_PRIVILEGE | UPDATE_PRIVILEGE;//增删改查权限
 21
 22    public GenericPrivilegeBase()
 23    {
 24    }

 25
 26    public static boolean isValidPrivilege(int privilege)//判断是否具有权限
 27    {
 28        if ( (privilege & QUERY_OR_USE_PRIVILEGE) != 0)
 29        {
 30            return true;
 31        }

 32
 33        if ( (privilege & CREATE_PRIVILEGE) != 0)
 34        {
 35            return true;
 36        }

 37
 38        if ( (privilege & DELETE_PRIVILEGE) != 0)
 39        {
 40            return true;
 41        }

 42
 43        if ( (privilege & UPDATE_PRIVILEGE) != 0)
 44        {
 45            return true;
 46        }

 47
 48        return false;
 49    }

 50
 51    public static boolean checkQueryPrivilege(int privilege)//判断是否具有察看权限
 52    {
 53        if ( (privilege & QUERY_OR_USE_PRIVILEGE) != 0)
 54        {
 55            return true;
 56        }

 57        else
 58        {
 59            return false;
 60        }

 61    }

 62
 63    public static boolean checkUsePrivilege(int privilege)
 64    {
 65        if ( (privilege & QUERY_OR_USE_PRIVILEGE) != 0)
 66        {
 67            return true;
 68        }

 69        else
 70        {
 71            return false;
 72        }

 73    }

 74
 75    public static boolean checkCreatePrivilege(int privilege)//判断是否有添加权限
 76    {
 77        if ( (privilege & CREATE_PRIVILEGE) != 0)
 78        {
 79            return true;
 80        }

 81        else
 82        {
 83            return false;
 84        }

 85    }

 86
 87    public static boolean checkDeletePrivilege(int privilege)//判断是否有删除权限
 88    {
 89        if ( (privilege & DELETE_PRIVILEGE) != 0)
 90        {
 91            return true;
 92        }

 93        else
 94        {
 95            return false;
 96        }

 97    }

 98
 99    public static boolean checkUpdatePrivilege(int privilege)
100    {
101        if ( (privilege & UPDATE_PRIVILEGE) != 0)
102        {
103            return true;
104        }

105        else
106        {
107            return false;
108        }

109    }

110}

111
然后我们自定义两个标签,Privilege与noPrivilege用来判断用户是否具有权限,这两个标签必须具有三个基本的attribute,beanName:当前所要操作的哪个资源;scope:用户信息存放在哪个域;operation:用户想要进行什么操作
贴一个privilege标签的代码:
  1package com.ideal.framework.tag;
  2
  3import javax.servlet.jsp.tagext.BodyTagSupport;
  4import javax.servlet.jsp.tagext.*;
  5import javax.servlet.http.*;
  6import javax.servlet.jsp.*;
  7import java.sql.*;
  8import java.io.*;
  9import com.ideal.framework.*;
 10import com.ideal.framework.po.ResourceInfo;
 11import java.util.Hashtable;
 12import com.ideal.framework.sys.privilege.GenericPrivilegeBase;
 13
 14public class PrivilegeTag
 15    extends BodyTagSupport
 16{
 17    String operation;
 18    private String beanName;
 19    private String scope;
 20
 21    public PrivilegeTag()
 22    {
 23        super();
 24    }

 25
 26    public void setOperation(String operation)
 27    {
 28        this.operation = operation;
 29    }

 30
 31    public void setBeanName(String beanName)
 32    {
 33        this.beanName = beanName;
 34    }

 35
 36    public void setScope(String scope)
 37    {
 38        this.scope = scope;
 39    }

 40
 41    public int doStartTag() throws JspTagException
 42    {
 43        if (scope == null || scope.equals(""))
 44            return SKIP_BODY;
 45        else
 46        {
 47            String user_name = "";
 48            if (scope.equalsIgnoreCase("session"))
 49            {
 50                HttpSession session = pageContext.getSession();
 51                user_name = (String) session.getAttribute("UserName");
 52            }

 53            else
 54            {
 55                HttpServletRequest request = (HttpServletRequest) pageContext.
 56                    getRequest();
 57                user_name = (String) request.getAttribute("UserName");
 58            }

 59
 60            for (int i = 0; i < ResourceContainer.resource_container.size(); i++)
 61            {
 62                Hashtable temp_hash = (Hashtable) ResourceContainer.
 63                    resource_container.get(i);
 64                if (temp_hash.containsKey(user_name))
 65                {
 66                    ResourceInfo resource = (ResourceInfo) temp_hash.get(
 67                        user_name);
 68                    if (beanName.trim().toLowerCase().equals(resource.
 69                        getModuleCode().trim().toLowerCase()))
 70                    {
 71                        if(this.checkPrivilege(resource.getPrivilegeCode()) == EVAL_BODY_TAG)
 72                            return EVAL_BODY_TAG;
 73                    }

 74                }

 75            }

 76
 77        }

 78        return SKIP_BODY;
 79return EVAL_BODY_TAG;
 80    }

 81
 82    public int checkPrivilege(String privilege)
 83    {
 84        int int_privilege = 0;
 85        try
 86        {
 87            int_privilege = Integer.parseInt(privilege);
 88        }

 89        catch (NumberFormatException ex)
 90        {
 91            System.out.println(ex.getMessage());
 92        }

 93        GenericPrivilegeBase gpb = new GenericPrivilegeBase();
 94        if (operation.equals("NONE"))
 95            return EVAL_BODY_TAG;
 96        if (operation.equals("QUERY"))
 97            if (gpb.checkQueryPrivilege(int_privilege))
 98                return EVAL_BODY_TAG;
 99        if (operation.equals("CREATE"))
100            if (gpb.checkCreatePrivilege(int_privilege))
101                return EVAL_BODY_TAG;
102        if (operation.equals("DELETE"))
103            if (gpb.checkDeletePrivilege(int_privilege))
104                return EVAL_BODY_TAG;
105        if (operation.equals("UPDATE"))
106            if (gpb.checkUpdatePrivilege(int_privilege))
107                return EVAL_BODY_TAG;
108        if (operation.equals("USE"))
109            if (gpb.checkUsePrivilege(int_privilege))
110                return EVAL_BODY_TAG;
111        return SKIP_BODY;
112    }

113
114    public int doAfterBody() throws JspTagException
115    {
116        return SKIP_BODY;
117    }

118
119    public int doEndTag() throws JspTagException
120    {
121        try
122        {
123            if (bodyContent != null)
124            {
125                bodyContent.writeOut(bodyContent.getEnclosingWriter());
126            }

127        }

128        catch (IOException ex)
129        {
130            throw new JspTagException("IO Error:" + ex.getMessage());
131        }

132        return EVAL_PAGE;
133    }

134
135    public void doInitBody() throws JspTagException
136    {
137    }

138
139    public void setBodyContent(BodyContent bodyContent)
140    {
141        this.bodyContent = bodyContent;
142    }

143}

144
在页面上,我们如此使用该标签:
1<privilege beanName="user_info" scope="session" operation="create">
2    <input type="button" value="添加">
3</privilege>

如此,系统会自动根据当前session中的用户来判断是否需要显示当前的添加按钮。
到此所有权限的代码完成,在此套权限设计中,我始终抱着AOP的想法:让他属于一个系统切面,以后再开发其他系统时,作为一个模块就可以加载上去,与系统无关

评论

# re: web开发中的权限设计拙见一二(3) ----资源配置与权限判断  回复  更多评论   

2007-01-03 15:54 by errorfun
代码没仔细看,不过你的判断是否有权限方法,感觉可以只是地判断是否值大于1就行了,不过搞四个那么多,就像你原来所说的,如果扩展了权限,那你不是每次要加一个判断?

# re: web开发中的权限设计拙见一二(3) ----资源配置与权限判断  回复  更多评论   

2007-01-03 17:04 by 江上一叶舟
@errorfun
判断是否具有权限,那么的确只要判断是否但与1就可以了,目前那个权限类存在的目的不仅是判断是否具有权限,还要判断是否具有添加的权限、删除的权限等等

另外我个人感觉如果每扩展一种权限就需要在里面加一个权值和一个函数,权值我们可以用其他方式来处理,譬如propeties文件,xml文件,数据库,常量类等,但函数我觉得挺有必要增加的的:如增加上传权限,我们需要加个函数checkUplodaPrivilege(),我觉得是有必要的,但如果您有更好的办法,我们可以拿出来探讨一下:)

# re: web开发中的权限设计拙见一二(3) ----资源配置与权限判断  回复  更多评论   

2007-01-03 19:12 by errorfun
@江上一叶舟
我是对你这个方法而说的:
public static boolean isValidPrivilege(int privilege)//判断是否具有权限
27 {
28 if ( (privilege & QUERY_OR_USE_PRIVILEGE) != 0)
29 {
30 return true;
31 }
32
33 if ( (privilege & CREATE_PRIVILEGE) != 0)
34 {
35 return true;
36 }
37
38 if ( (privilege & DELETE_PRIVILEGE) != 0)
39 {
40 return true;
41 }
42
43 if ( (privilege & UPDATE_PRIVILEGE) != 0)
44 {
45 return true;
46 }
47
48 return false;
49 }
isValidPrivilege方法要是有任何一个权限都会返回TRUE,但结果与return privilege >0是一样的。难道不是?

# re: web开发中的权限设计拙见一二(3) ----资源配置与权限判断  回复  更多评论   

2007-01-03 22:39 by 江上一叶舟
@errorfun
不是这样的,可以看到,我的权限中有一个是QUERY_OR_USE_PRIVILEGE权限,也就是最基本的使用权限,如果没有这个权限,那其他的就不用检查了,若有这个权限,我们就说他对该资源是有使用权,即有权限的。

另外我们其实也无需这样来判断用户是否具有该资源的操作权限,我们可以在资源表(T_ResourceInfo)中查看,若该角色没有对应到该资源,自然就没有权限了,这个类仅仅是用来在页面上判断是否显示某些元素,譬如添加按钮的时候用的,如页面上有这种标签的时候,我们就需要用到这个类中的CheckDeletePrivilege函数

# re: web开发中的权限设计拙见一二(3) ----资源配置与权限判断  回复  更多评论   

2007-01-04 09:57 by Tendy
@江上一叶舟
你的代码没有体现出你所说的检查方法
errorfun说的没错~~

by the way:
if ( (privilege & QUERY_OR_USE_PRIVILEGE) != 0)
{
return true;
}
else
{
return false;
}

写成:
return (privilege & QUERY_OR_USE_PRIVILEGE) != 0;
简洁一点。。。

# re: web开发中的权限设计拙见一二(3) ----资源配置与权限判断  回复  更多评论   

2007-01-04 10:06 by ronghao[匿名]
权限操作本来就是对业务而言的,控制到数据库再映射回来,呵呵,麻烦.
直接使用acegi对业务方法拦截,页面使用标签,效果和你一样,还可以动态扩展用户直接实现增加删除权限

# re: web开发中的权限设计拙见一二(3) ----资源配置与权限判断  回复  更多评论   

2007-01-04 10:13 by 江上一叶舟
@ronghao[匿名]
acegi我考虑过,对业务类权限控制不够灵活.

@Tendy
isValidPrivilege方法本身只要判断QUERY_OR_USE_PRIVILEGE就够了,至于代码是否简洁,我觉得不在我想讨论的范围

# re: web开发中的权限设计拙见一二(3) ----资源配置与权限判断  回复  更多评论   

2007-01-04 16:01 by 1

# re: web开发中的权限设计拙见一二(3) ----资源配置与权限判断  回复  更多评论   

2007-01-10 13:43 by K.G
请教: 若一个业务逻辑需要和底层的多个表操作,会不会引入配置和程序的复杂性?还是需要重新考虑数据库设计合理性?

# re: web开发中的权限设计拙见一二(3) ----资源配置与权限判断  回复  更多评论   

2007-01-10 13:49 by 江上一叶舟
@K.G
恩,我考虑过这个问题,我们现在的做法主要是把一个表作为一个资源来控制,自然控制的业务逻辑也是针对一个表的,若我们一个业务逻辑涉及到多个资源,也就是多个表,那我们就需要考虑这个业务逻辑主要是针对那张表的,譬如说我们添加人员信息,添加人员信息势必要涉及到给人员配置角色,那么就要涉及到人员表、人员角色对应表两个数据库表。一种方法是我们可以把两个业务逻辑分开,第二种是我们就把这个添加人员的业务逻辑看成是针对人员信息资源的业务逻辑,只考虑这个业务逻辑的主要针对资源,不考虑分支。这样的话也可以解决这个问题

# re: web开发中的权限设计拙见一二(3) ----资源配置与权限判断  回复  更多评论   

2007-01-11 10:57 by 康康[匿名]
检查权限功能时,如果功能代号大于32,计算不到..

"&"移位运算符只支持Integer类型的运算..

# re: web开发中的权限设计拙见一二(3) ----资源配置与权限判断  回复  更多评论   

2007-10-19 09:51 by ehoole
资源指代业务逻辑而不是数据表,这样不是操作起来不是更清晰?

# re: web开发中的权限设计拙见一二(3) ----资源配置与权限判断  回复  更多评论   

2008-04-30 15:06 by piter
表里存表名,垃圾,
不过作者挺认真能把它这写完,态度还是值的肯定的

# re: web开发中的权限设计拙见一二(3) ----资源配置与权限判断  回复  更多评论   

2009-04-14 08:53 by jsfMe
“(注:上述xml文件在系统初始化时候加载入内存中,我们也可以将权限信息也加载在内存中,不会很大,一切资源在内存中操作,非常快)”,请问具体如何操作才能将其加载如内存,请指教,谢谢

# re: web开发中的权限设计拙见一二(3) ----资源配置与权限判断  回复  更多评论   

2009-08-10 16:35 by pantu0914
拜读了你的文章,有一点小小的疑问请教:
List user_list = m_user_dao.getAllUser();
初始化的时候把所有的用户的都取出来放入内存中,这样可取吗?如果

只有注册用户登录后才能发表评论。


网站导航: