当柳上原的风吹向天际的时候...

真正的快乐来源于创造

  BlogJava :: 首页 :: 联系 :: 聚合  :: 管理
  368 Posts :: 1 Stories :: 201 Comments :: 0 Trackbacks
权限系统是稍成规模的系统中一个必不可少的部分,操作的可否执行,流程的具体走向,业务的具体步骤都会涉及权限的处理。
具体来说有两种权限的控制方式:一种是等级权限控制方式,一种是角色权限控制方式。前者可用于范围控制,适用于用户权力大小不同的场合;后者可用于单点控制,适用于用户权力多寡有异的场合。现实世界中,军队中官衔类似于等级权限控制,现代企业中各司其职的权力分配类似于角色控制。范围控制前面已经提到过了,今天来谈谈角色权限控制。

角色权限控制是把单项权限一项项的赋予用户,如同现实世界中把具体职位一个个的赋予某个员工一样。在他执行操作前,先看他是否拥有执行此操作的权限,如果有则执行,否则不执行。

在这里我们还是采用上一讲的业务,实现IDocService的实现类DocService,但要把等级权限控制方式修改成角色权限控制方式,原来的处置是用户权限高于某个值就能执行操作,现在如果一个用户有“添加”角色,他就可以添加文档;如果他缺乏“修改”角色,他就不能修改文档。

实现用户角色权限控制并不复杂,下面请看具体思路:
1.创建两个领域对象类:用户类User和角色类Role,他们之间是一对多的关系,他们对应的表用主外键关联起来。使用Hibernate很容易实现这一关系。
2.使用AOP,实现IDocService接口的实现类DocService的代理,使用UserRoleController作为前置通知,角色权限控制放入其中。
3. UserRoleController中,查看用户是否有执行某项操作的权限,没有则抛出异常NoRoleException,否则执行的DocService中的函数。

领域对象类的基类BaseDomainObj,User,Role,Doc等都是它的子类。
package com.heyang.domain;

/**
 * 领域对象基类
 * 
@author 何杨
 * 
@version 1.00
 * 
@since 2009-1-5 上午10:26:32
 *
 
*/

public abstract class BaseDomainObj{
    
// ID
    protected long id;
    
    
// 名称
    protected String name;
    
    
public String toString(){
        
return name;
    }


    
public long getId() {
        
return id;
    }


    
public void setId(long id) {
        
this.id = id;
    }
        

    
public String getName() {
        
return name;
    }


    
public void setName(String name) {
        
this.name = name;
    }

}

User类
package com.heyang.domain;

import java.util.LinkedHashSet;
import java.util.Set;

/**
 * 领域对象用户类
 * 
@author 何杨
 * 
@version 1.00
 * 
@since 2009-1-5 上午10:23:25
 *
 
*/

public class User extends BaseDomainObj{
    
// 用户所拥有的权限
    private Set<Role> roles=new LinkedHashSet<Role>();
    
    
public User(){
        
    }

    
    
public User(String name){
        
this.name=name;
    }

        
    
/**
     * 判断用户是否拥有角色。若参数角色名在用户角色集合中能找到则认为用户有此角色,即名相同则有,否则无
     * 
@param roleName :角色名
     * 
@return
     
*/

    
public boolean hasRole(String roleName){
        
for(Role role:roles){
            
if(role.getName().equals(roleName)){
                
return true;
            }

        }

        
        
return false;
    }


    
public Set<Role> getRoles() {
        
return roles;
    }


    
public void setRoles(Set<Role> roles) {
        
this.roles = roles;
    }
    
}

User类的Hibernate映射文件,Set部分是关键:
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC 
  "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
  "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd"
>
<hibernate-mapping package="org.hibernate.auction">
  
<class name="com.heyang.domain.User"
    table
="AOPRoleSample_User" lazy="false">
    
<id name="id" column="ID" >
      
<generator class="native"/>
    
</id>
    
<property name="name" column="name" />
    
<set name="roles" cascade="all" lazy="false">
      
<key column="userid"/>
      
<one-to-many class="com.heyang.domain.Role"/>
    
</set>
  
</class>
</hibernate-mapping>

Role类:
package com.heyang.domain;

/**
 * 领域对象角色类
 * 
@author 何杨
 * 
@version 1.00
 * 
@since 2009-1-5 上午10:32:16
 *
 
*/

public class Role extends BaseDomainObj{
  
public Role(){
    
  }

  
  
public Role(String name){
    
this.name=name;
  }

}


Role类的映射文件:
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC 
  "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
  "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd"
>
<hibernate-mapping package="org.hibernate.auction">
  
<class name="com.heyang.domain.Role"
    table
="AOPRoleSample_Role" lazy="false">
    
<id name="id" column="ID" >
      
<generator class="native"/>
    
</id>
    
<property name="name" column="name" />
  
</class>
</hibernate-mapping>

DocService类,有了AOP的帮忙,其中不需要任何权限控制的代码,它甚至不知道权限控制子系统的存在
public class DocService extends BaseService implements IDocService {
  
/**
   * 按ID取得文档
   * 
@param id
   * 
@return
   
*/

  
public Doc getDoc(long id){
    
return (Doc)dao.get(Doc.class,id);
  }

  
  
public void add(Doc doc, User user) {
    System.out.println(
"" + doc + "交由dao处理(存入数据库)");
    dao.create(doc);
  }


  
public void delete(Doc doc, User user) {
    System.out.println(
"" + doc + "交由dao处理(从数据库删除)");
    dao.delete(doc);
  }


  
public void update(Doc doc, User user) {
    System.out.println(
"" + doc + "交由dao处理(修改数据库中对应的记录)");
    dao.update(doc);
  }

}


UserRoleController类,它作为DocService的前置处理器,在真正的数据库操作开始前进行权限处理
package com.heyang.service;

import java.lang.reflect.Method;

import org.springframework.aop.MethodBeforeAdvice;

import com.heyang.domain.User;
import com.heyang.exception.NoRoleException;

/**
 * 实现角色子系统---用户角色控制
 * 
@author: 何杨(heyang78@gmail.com)
 * @date: 2009-1-2-下午04:19:13
 
*/

public class UserRoleController implements MethodBeforeAdvice{
    
private String addDocRoleName;
    
private String deleteDocRoleName;
    
private String updateDocRoleName;
        
    
/**
     * 在IDocService的实际方法开始前进行前置处理--用户角色检查
     
*/

    
public void before(Method arg0, Object[] arg1, Object arg2) throws Throwable {
        
// 取得方法名
        String mothodName=arg0.getName();
        
        
// 取得用户
        User user=null;        
        
if(arg1.length>1){
            user
=(User)arg1[1];        
        }

        
        
// 根据方法名判断用户是否拥有所需要的角色,否则抛出异常
        if("add".equals(mothodName)){
            
if(user.hasRole(addDocRoleName)==false){
                
throw new NoRoleException("用户"+user+"必须拥有‘添加’角色才能执行添加文档操作");
            }

        }

        
else if("delete".equals(mothodName)){
            
if(user.hasRole(deleteDocRoleName)==false){
                
throw new NoRoleException("用户"+user+"必须拥有‘删除’角色才能执行删除文档操作");
            }

        }

        
else if("update".equals(mothodName)){
            
if(user.hasRole(updateDocRoleName)==false){
                
throw new NoRoleException("用户"+user+"必须拥有‘修改’角色才能执行修改文档操作");
            }

        }

    }



    
public String getAddDocRoleName() {
        
return addDocRoleName;
    }



    
public void setAddDocRoleName(String addDocRoleName) {
        
this.addDocRoleName = addDocRoleName;
    }



    
public String getDeleteDocRoleName() {
        
return deleteDocRoleName;
    }



    
public void setDeleteDocRoleName(String deleteDocRoleName) {
        
this.deleteDocRoleName = deleteDocRoleName;
    }



    
public String getUpdateDocRoleName() {
        
return updateDocRoleName;
    }



    
public void setUpdateDocRoleName(String updateDocRoleName) {
        
this.updateDocRoleName = updateDocRoleName;
    }

}

全体配置文件
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd">
<beans>
    
<!-- 数据源 -->
    
<bean id="dataSource"
        class
="org.springframework.jdbc.datasource.DriverManagerDataSource">
        
<property name="driverClassName"
            value
="org.gjt.mm.mysql.Driver">
        
</property>
        
<property name="url" value="jdbc:mysql://127.0.0.1/test">
        
</property>
        
<property name="username" value="root"></property>
        
<property name="password" value="hy"></property>
    
</bean>
    
    
<!-- Hibernate Session Factory,使用了上面配置的数据源 -->
    
<bean id="sessionFactory"
        class
="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
        
<property name="dataSource">
            
<ref bean="dataSource"/>
        
</property>
        
<property name="mappingResources">
          
<list>
            
<value>com/heyang/domain/User.hbm.xml</value>
            
<value>com/heyang/domain/Role.hbm.xml</value>
            
<value>com/heyang/domain/Doc.hbm.xml</value>
          
</list>
        
</property>
        
<property name="hibernateProperties">
            
<value>
                hibernate.hbm2ddl.auto=Acreate
                hibernate.dialect=org.hibernate.dialect.MySQLDialect
                hibernate.show_sql=true    
                hibernate.format_sql=true                            
            
</value>
        
</property>        
    
</bean>
    
    
<!-- Hibernate Template,使用了上面配置的sessionFactory -->
    
<bean id="hibernateTemplate"
        class
="org.springframework.orm.hibernate3.HibernateTemplate">
        
<property name="sessionFactory">
            
<ref bean="sessionFactory"/>
        
</property>
    
</bean>
    
    
<!-- 使用了上面配置的hibernateTemplate的BaseDao -->
    
<bean id="dao" class="com.heyang.dao.BaseDao">
        
<property name="hibernateTemplate">
            
<ref bean="hibernateTemplate"/>
        
</property>
    
</bean>
    
    
<!-- 使用了上面配置的dao的UserService -->
    
<bean id="userService" class="com.heyang.service.UserService">
        
<property name="domainClass">
            
<value>User</value>
        
</property>
        
<property name="dao">
            
<ref bean="dao"/>
        
</property>
    
</bean>
    
    
<!-- 用于文件处理的IDocService实现类DocService -->
    
<bean id="docService" class="com.heyang.service.DocService">
        
<property name="dao">
            
<ref bean="dao"/>
        
</property>
    
</bean>
    
    
<!-- 在执行docService的实际方法前进行用户角色检查 -->
    
<bean id="userRoleController" class="com.heyang.service.UserRoleController">
        
<property name="addDocRoleName" value="添加" />
        
<property name="deleteDocRoleName" value="删除" />
        
<property name="updateDocRoleName" value="修改" />        
    
</bean>
    
    
<!-- docService的代理对象 -->
    
<bean id="docServiceProxy" class="org.springframework.aop.framework.ProxyFactoryBean">
        
<property name="proxyInterfaces">
            
<value>com.heyang.service.IDocService</value>
        
</property>
        
<property name="interceptorNames">
            
<list>
                
<value>userRoleController</value>
            
</list>
        
</property>
        
<property name="target">
            
<ref bean="docService"/>
        
</property>
    
</bean>
</beans>

模拟处理:
        ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
        
        UserService userService
=(UserService)ctx.getBean("userService");
        IDocService docService
=(IDocService)ctx.getBean("docServiceProxy");
        
        User user
=userService.getUser(1);
        Doc doc1;
        
        
// 模拟添加操作
        doc1=new Doc("论次贷危机对美国的影响");
        
try{
            docService.add(doc1, user);
        }

        
catch(NoRoleException ex){
            ex.printStackTrace();
        }

        
        
// 模拟修改操作
        doc1=docService.getDoc(1);
        doc1.setName(
"论次贷危机对中国的影响");
        
try{
            docService.update(doc1, user);
        }

        
catch(NoRoleException ex){
            ex.printStackTrace();
        }

        
        
// 模拟删除操作
        doc1=docService.getDoc(1);
        doc1.setName(
"论次贷危机对世界的影响");
        
try{
            docService.delete(doc1, user);
        }

        
catch(NoRoleException ex){
            ex.printStackTrace();
        }

小结:

权限子系统是企业应用中不可或缺的环节,它具体的权限控制方式有两种:一种是等级权限控制方式,一种是角色权限控制方式,其他复杂的权限系统都可以由它们组合而来。

由于业务控制的关系,权限子系统和其他业务子系统的最容易耦合在一起,久而久之会对程序的可读性,可维护性带来消极影响,而AOP恰好能帮助我们有效降低权限子系统和其他业务子系统的耦合,实现他们之间的离散化。因此,AOP值得我们认真掌握,尤其是其背后面向方面编程的精神。


代码下载:
http://www.blogjava.net/Files/heyang/AOPRoleSample20090106060255.rar

需要的库请自行补充(基本ProjectTodolist的lib全有)。
posted on 2009-01-05 21:38 何杨 阅读(2028) 评论(2)  编辑  收藏

Feedback

# re: 用户角色权限控制的实现 2009-04-22 20:24 小何
有没有角色,用户控制权限(细粒度)的例子,我最近也在做一个项目的权限控制,但找不到好的例子,有就发给我一下,邮箱是:hgyang_1984@126.com,谢谢~  回复  更多评论
  

# re: 用户角色权限控制的实现 2009-04-22 22:44 hy
http://www.blogjava.net/heyang/archive/2009/04/02/263471.html

  回复  更多评论
  


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


网站导航: