權限系統是稍成規模的系統中一個必不可少的部分,操作的可否執行,流程的具體走向,業務的具體步驟都會涉及權限的處理。
具體來說有兩種權限的控制方式:一種是等級權限控制方式,一種是角色權限控制方式。前者可用于范圍控制,適用于用戶權力大小不同的場合;后者可用于單點控制,適用于用戶權力多寡有異的場合?,F實世界中,軍隊中官銜類似于等級權限控制,現代企業中各司其職的權力分配類似于角色控制。范圍控制前面已經提到過了,今天來談談角色權限控制。
角色權限控制是把單項權限一項項的賦予用戶,如同現實世界中把具體職位一個個的賦予某個員工一樣。在他執行操作前,先看他是否擁有執行此操作的權限,如果有則執行,否則不執行。
在這里我們還是采用上一講的業務,實現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();
}
小結:
代碼下載:
http://www.aygfsteel.com/Files/heyang/AOPRoleSample20090106060255.rar
需要的庫請自行補充(基本ProjectTodolist的lib全有)。
具體來說有兩種權限的控制方式:一種是等級權限控制方式,一種是角色權限控制方式。前者可用于范圍控制,適用于用戶權力大小不同的場合;后者可用于單點控制,適用于用戶權力多寡有異的場合?,F實世界中,軍隊中官銜類似于等級權限控制,現代企業中各司其職的權力分配類似于角色控制。范圍控制前面已經提到過了,今天來談談角色權限控制。
角色權限控制是把單項權限一項項的賦予用戶,如同現實世界中把具體職位一個個的賦予某個員工一樣。在他執行操作前,先看他是否擁有執行此操作的權限,如果有則執行,否則不執行。
在這里我們還是采用上一講的業務,實現IDocService的實現類DocService,但要把等級權限控制方式修改成角色權限控制方式,原來的處置是用戶權限高于某個值就能執行操作,現在如果一個用戶有“添加”角色,他就可以添加文檔;如果他缺乏“修改”角色,他就不能修改文檔。
實現用戶角色權限控制并不復雜,下面請看具體思路:
1.創建兩個領域對象類:用戶類User和角色類Role,他們之間是一對多的關系,他們對應的表用主外鍵關聯起來。使用Hibernate很容易實現這一關系。
2.使用AOP,實現IDocService接口的實現類DocService的代理,使用UserRoleController作為前置通知,角色權限控制放入其中。
3. UserRoleController中,查看用戶是否有執行某項操作的權限,沒有則拋出異常NoRoleException,否則執行的DocService中的函數。
領域對象類的基類BaseDomainObj,User,Role,Doc等都是它的子類。




































User類:















































User類的Hibernate映射文件,Set部分是關鍵:


















Role類:



















Role類的映射文件:














DocService類,有了AOP的幫忙,其中不需要任何權限控制的代碼,它甚至不知道權限控制子系統的存在:


























UserRoleController類,它作為DocService的前置處理器,在真正的數據庫操作開始前進行權限處理:
















































































全體配置文件:





























































































模擬處理:




































小結:
權限子系統是企業應用中不可或缺的環節,它具體的權限控制方式有兩種:一種是等級權限控制方式,一種是角色權限控制方式,其他復雜的權限系統都可以由它們組合而來。
由于業務控制的關系,權限子系統和其他業務子系統的最容易耦合在一起,久而久之會對程序的可讀性,可維護性帶來消極影響,而AOP恰好能幫助我們有效降低權限子系統和其他業務子系統的耦合,實現他們之間的離散化。因此,AOP值得我們認真掌握,尤其是其背后面向方面編程的精神。
代碼下載:
http://www.aygfsteel.com/Files/heyang/AOPRoleSample20090106060255.rar
需要的庫請自行補充(基本ProjectTodolist的lib全有)。