1. 程式人生 > >許可權管理設計方法

許可權管理設計方法

首先,設定三種要素:使用者、群組、角色。
使用者為登入用,對應到人。群組對應為使用者的集合,是一種特殊的使用者。角色為一組許可權項的集合,使用者(群組)都有各自的角色。



許可權的實現通過Permission類和Rule類來實現。

Permission供外部呼叫,Rule為一個介面,為許可權判斷規則。

Permission是一個抽象類,有以下方法

public boolean hasPermission(User user,HashMap oldData,Input input);

public String getPermissionName();

public abstract Rule[] getDenyRule();

public abstract Rule[] getAcceptRule();

hasPermission方法供外部呼叫,已實現,實現方法為先根據getDenyRule()得到的規則判斷許可權是否被阻攔,再根據getAcceptRule來判斷是否有許可權。

而Rule介面的接品則由使用者自行定義,隨包附帶了一個已實現的Rule,實現的功能如下:

先尋找User的所有角色,然後判斷角色是否有許可權,如果無許可權則尋找其父級群組,再取父級群組的所有角色進行判斷是否有許可權,如果無許可權則再往上級群組找,直到找最上一級還是無許可權才判斷為無許可權。

現實現判斷許可權有無許可權的方式已可以達成的有以下三種:

1、 是否有操作的許可權。

2、 是否有操作的子操作的許可權。

3、 在資料為某條件時有操作(子操作)的許可權。



在進行程式開發時,第一步,編寫User,Group,Role的實現類,已提供了一套XML的實現類。

第二步,寫配置檔案,進行許可權項的配置。

第三步,在程式中要進行許可權判斷的地方呼叫Permission.hasPermission方法即可。



以後我會把程式碼逐天貼出來。



如果大家有什麼別的種類許可權要進行判斷的,請給我傳送郵件,我繼續改善,歡迎大家多提意見。







==================================================

許可權元件之一(使用者)

----------------------

首先,我定義了一個使用者介面,可以從其中取出其的各種屬性.程式碼如後面所示.使用者除了各種不同的屬性以外還必須設定其角色以及所屬的群組.

然後定義一個AbstractUser把User共性的東西進行處理.所有的取屬性的方法都已實現.使用者只要根據實現情況繼承AbstractUser把自己要定義的屬性進行處理即可.(因為每個系統的使用者都會有不同的屬性,所以留成抽象類供使用者自己擴充套件). 只要初始化變數description, name ,group ,id, prop,role,propMap即可.

最後定義了一個類UserImpl來實現具體的User作隨包的一個User供一般使用者使用.不建議直接使用UserImpl,因為以後的版本可能會重寫該類.如果要使用的話可以把該類改名為自己的類即可.



這部分涉及到了一個ResourceLib類,該類中存是我自己定義的儲存各種資源配置用的類,可以直接使用.



======================User.java===============================

package org.fswan.permission;



import org.fswan.Identity;

import java.util.Properties;

import org.fswan.workflow.exception.CantFoundIDException;

public interface User

{

/**

* 獲取使用者名稱

* @return 使用者名稱

*/

public String getName();

/**

* 獲取使用者描述

* @return 描述

*/

public String getDescription();

/**

* 獲取使用者標識

* @return 使用者標識

*/

public Identity getId();

/**

* 獲取屬性

* @return 屬性值

*/

public Properties getProperties();

/**

* 獲取所屬組

* @return 組列表

*/

public Group[] getGroups() throws CantFoundIDException;

/**

* 獲取所有角色

* @return 角色陣列

*/

public Role[] getRoles() throws CantFoundIDException;

/**

* 獲取使用者用作許可權判斷的屬性

* @param prop 許可權屬性

* @return 屬性值

*/

public Object getPermissionProp(String prop);

}

=======================AbstractUser===================================

package org.fswan.permission;

import java.util.HashMap;

import java.util.Properties;



import org.fswan.Identity;

import org.fswan.workflow.exception.IdentityMappingError;

/**

*

* 實現AbstractUser的類構造必須做的一些事

* 初始化變數description,name,group,id,prop,role,propMap

*/

public class AbstractUser implements User

{

/**

* 描述

*/

protected String description;

/**

* 名稱

*/

protected String name;

/**

* 所屬的組的標識

*/

protected Identity[] group;

/**

* 使用者標識

*/

protected Identity id;

/**

* 屬性

*/

protected Properties prop;

/**

* 角色

*/

protected Identity[] role;

/**

* 許可權屬性儲存的位置

*/

protected HashMap propMap;



/* (non-Javadoc)

* @see org.fswan.permission.User#getDescription()

*/

public String getDescription()

{

return description;

}

/* (non-Javadoc)

* @see org.fswan.permission.User#getGroups()

*/

public Group[] getGroups()

{

Group[] groups = new Group[group.length];

for (int i = 0; i < groups.length; i++)

{

try

{

groups[i] = (Group) group[i].newInstance();

} catch (IdentityMappingError e)

{

e.printStackTrace();

}

}

return groups;

}

/* (non-Javadoc)

* @see org.fswan.permission.User#getId()

*/

public Identity getId()

{

return id;

}

/* (non-Javadoc)

* @see org.fswan.permission.User#getName()

*/

public String getName()

{

return name;

}

/* (non-Javadoc)

* @see org.fswan.permission.User#getProperties()

*/

public Properties getProperties()

{

return prop;

}

/* (non-Javadoc)

* @see org.fswan.permission.User#getRoles()

*/

public Role[] getRoles()

{

Role[] roles = new Role[role.length];

for (int i = 0; i < roles.length; i++)

{

try

{

roles[i] = (Role) role[i].newInstance();

} catch (IdentityMappingError e)

{

e.printStackTrace();

}

}

return roles;

}

public String toString()

{

String retStr = id.getIdName();

retStr += ":" + name;

retStr += " " + description + "/n";

retStr += "Group:";

Group[] groups = this.getGroups();

if (groups != null)

{

for (int i = 0; i < groups.length; i++)

{

if (groups[i] != null)

retStr += groups[i].getId().getIdName() + "/t";

}

}

Properties p = getProperties();

Object[] obj = p.keySet().toArray();

for (int i = 0; i < obj.length; i++)

{

retStr+=obj[i]+":"+p.getProperty(obj[i].toString())+"/n";

}

return retStr;

}



/* (non-Javadoc)

* @see org.fswan.permission.User#getPermissionProp(java.lang.String)

*/

public Object getPermissionProp(String prop)

{

return propMap.get(prop);

}



}

==============================UserImpl.java===========================

package org.fswan.permission;

import java.util.ArrayList;

import java.util.Properties;

import javax.xml.parsers.DocumentBuilderFactory;

import org.fswan.Identity;

import org.fswan.IdentityImpl;

import org.fswan.ImplementIdentity;

import org.fswan.ResourceLib;

import org.fswan.workflow.exception.IdentityMappingError;

import org.w3c.dom.Document;

import org.w3c.dom.Element;

import org.w3c.dom.NodeList;

public class XMLUser extends AbstractUser implements ImplementIdentity

{

/**

* XML中定義使用者的標籤

*/

public static final String USER = "User";

public Object newInstance(Identity id)

{

ArrayList sources = ResourceLib.getXmlResource();

for (int i = 0; i < sources.size(); i++)

{

try

{

Document doc = DocumentBuilderFactory.newInstance().newDocumentBuilder().parse(sources.get(i).toString());

NodeList nl = doc.getElementsByTagName(USER);

for (int j = 0; j < nl.getLength(); j++)

{

Element tempEl = (Element) nl.item(j);

String idStr = tempEl.getAttribute("id");

if (idStr != null && !idStr.equals(""))

{

if (idStr.equals(id.getIdName()))

{

this.id = new IdentityImpl(Identity.SWITCH, Identity.XMLUSER, idStr);

NodeList tempNl = tempEl.getElementsByTagName("Name");

name = tempNl.item(0).getChildNodes().item(0).getNodeValue();

tempNl = tempEl.getElementsByTagName("Description");

description = tempNl.item(0).getChildNodes().item(0).getNodeValue();

tempNl = tempEl.getElementsByTagName("ParentGroup");

Identity[] groups = new Identity[tempNl.getLength()];

for (int iGroup = 0; iGroup < groups.length; iGroup++)

{

Element tempEl2 = (Element) tempNl.item(iGroup);

String subType = tempEl.getAttribute("subType");

if(subType==null || subType.equals(""))subType = Identity.XMLGROUP;

groups[iGroup] = new IdentityImpl(Identity.GROUP, subType, tempEl2.getAttribute("id"));

}

this.group = groups;

tempNl = tempEl.getElementsByTagName("Role");

Identity[] roles = new Identity[tempNl.getLength()];

for (int iRole = 0; iRole < tempNl.getLength(); iRole++)

{

Element tempEl2 = (Element) tempNl.item(iRole);

String subType = tempEl.getAttribute("subType");

if(subType==null || subType.equals(""))subType = Identity.XMLROLE;

roles[iRole] = new IdentityImpl(Identity.ROLE, subType, tempEl2.getAttribute("id"));

}

this.role = roles;

this.prop = new Properties();

tempNl = tempEl.getElementsByTagName("Property");

if (tempNl != null)

for (int k = 0; k < tempNl.getLength(); k++)

{

Element tempElement = (Element) tempNl.item(k);

System.out.println(tempElement.getAttribute("name"));

this.prop.setProperty(tempElement.getAttribute("name"), tempElement.getAttribute("value"));

}

return this;

}

}

}

} catch (Exception e)

{

e.printStackTrace();

}

}

return null;

}

public static void main(String[] args)

{

try

{

ResourceLib.addResource("D://eclipse//workspace//workflow//workflow.xml");

User u = (User) new IdentityImpl(Identity.USER, Identity.XMLUSER, "U01").newInstance();

System.out.println(u);

} catch (IdentityMappingError e)

{

e.printStackTrace();

}

}

}



========================XML格式=====================

<User id="U01">

<Name>Swan</Name>

<Description>方誌文</Description>

<ParentGroup id="G01"/>

<Property name="SEX" value="male"/>

<Property name="AGE" value="20"/>

</User>

========================XML描述檔案==================

<xs:complexType name="User">

<xs:annotation>

<xs:documentation>使用者名稱</xs:documentation>

</xs:annotation>

<xs:sequence>

<xs:element name="Name"/>

<xs:element name="Description"/>

<xs:element name="ParentGroup" type="Identity" minOccurs="0" maxOccurs="unbounded"/>

<xs:element name="Role" type="Identity" minOccurs="0" maxOccurs="unbounded"/>

<xs:element name="Property" minOccurs="0" maxOccurs="unbounded">

<xs:complexType>

<xs:attribute name="name" use="required"/>

<xs:attribute name="value" use="required"/>

</xs:complexType>

</xs:element>

</xs:sequence>

<xs:attribute name="id" use="required"/>

</xs:complexType>







=========================================================

==========================================================

==========================================================

許可權元件之二(群組)

-------------------------

首先,我定義了一個群組介面,除了繼承使用者的方法以外還有兩個方法,getUsers,getSubGroup.程式碼如後面所示.使用者除了各種不同的屬性以外還必須設定其角色以及所屬的群組.

然後定義一個AbstractGroup,他繼承了Group以及AbstractUser,並實現了Group介面定義的兩個方法.使用者只要根據實現情況繼承AbstractGroup把自己要定義的屬性進行處理即可.(因為每個系統的使用者都會有不同的屬性,所以留成抽象類供使用者自己擴充套件). 只要初始化變數description, name ,group ,id, prop,role,propMap,subGroup,user即可.

最後定義了一個類XMLGroup來實現具體的Group作隨包的一個Group供一般使用者使用.不建議直接使用XMLGroup,因為以後的版本可能會重寫該類.如果要使用的話可以把該類改名為自己的類即可.



這部分涉及到了一個ResourceLib類,該類中存是我自己定義的儲存各種資源配置用的類,可以直接使用.



======================Group.java===============================

package org.fswan.permission;

public interface Group extends User

{

/**

* 獲取組下所有的使用者

* @return 使用者陣列

*/

public User[] getUsers();

/**

* 獲取組下屬的組

* @return 組的陣列

*/

public Group[] getSubGroup();

}

=======================AbstractGroup===================================

package org.fswan.permission;



import org.fswan.Identity;

import org.fswan.workflow.exception.IdentityMappingError;

public class AbstractGroup extends AbstractUser implements Group

{

protected Identity[] subGroup;

protected Identity[] user;

/* (non-Javadoc)

* @see org.fswan.permission.Group#getSubGroup()

*/

public Group[] getSubGroup()

{

Group[] groups = new Group[subGroup.length];

for (int i = 0; i < groups.length; i++)

{

try

{

groups[i] = (Group)subGroup[i].newInstance();

} catch (IdentityMappingError e)

{

e.printStackTrace();

}

}

return groups;

}



/* (non-Javadoc)

* @see org.fswan.permission.Group#getUsers()

*/

public User[] getUsers()

{

User[] users = new User[user.length];

for (int i = 0; i < users.length; i++)

{

try

{

users[i] = (User)user[i].newInstance();

} catch (IdentityMappingError e)

{

e.printStackTrace();

}

}

return users;

}

public String toString()

{

String retStr = id.getIdName();

retStr +=":"+name;

retStr += " "+description;

return retStr;

}

}

==============================XMLGroup.java===========================

package org.fswan.permission;



import java.util.ArrayList;

import java.util.Properties;



import javax.xml.parsers.DocumentBuilderFactory;



import org.fswan.Identity;

import org.fswan.IdentityImpl;

import org.fswan.ImplementIdentity;

import org.fswan.ResourceLib;

import org.w3c.dom.Document;

import org.w3c.dom.Element;

import org.w3c.dom.NodeList;



public class XMLGroup extends AbstractGroup implements ImplementIdentity

{

/**

* XML中定義群組的標籤

*/

public static final String GROUP = "Group";

public Object newInstance(Identity id)

{

ArrayList sources = ResourceLib.getXmlResource();

for (int i = 0; i < sources.size(); i++)

{

try

{

Document doc = DocumentBuilderFactory.newInstance().newDocumentBuilder().parse(sources.get(i).toString());

NodeList nl = doc.getElementsByTagName(GROUP);

for (int j = 0; j < nl.getLength(); j++)

{

Element tempEl = (Element)nl.item(j);



String idStr = tempEl.getAttribute("id");

if(idStr!=null && !idStr.equals(""))

{

if(idStr.equals(id.getIdName()))

{

this.id = new IdentityImpl(Identity.SWITCH,Identity.XMLGROUP,idStr);

//載入名稱

NodeList tempNl = tempEl.getElementsByTagName("Name");

name = tempNl.item(0).getChildNodes().item(0).getNodeValue();

//載入描述

tempNl = tempEl.getElementsByTagName("Description");

description = tempNl.item(0).getChildNodes().item(0).getNodeValue();

//載入父群組

tempNl = tempEl.getElementsByTagName("ParentGroup");

Identity[] groups = new Identity[tempNl.getLength()];

for (int iGroup=0; iGroup < tempNl.getLength(); iGroup++)

{

tempEl = (Element)tempNl.item(iGroup);

groups[iGroup] = new IdentityImpl(Identity.GROUP,Identity.XMLGROUP,tempEl.getAttribute("id"));

}

this.subGroup = groups;

//載入角色

tempNl = tempEl.getElementsByTagName("Role");

Identity[] roles = new Identity[tempNl.getLength()];

for (int iRole=0; iRole < tempNl.getLength(); iRole++)

{

tempEl = (Element)tempNl.item(iRole);

roles[iRole] = new IdentityImpl(Identity.ROLE,Identity.XMLROLE,tempEl.getAttribute("id"));

}

this.role = roles;

//載入屬性

this.prop = new Properties();

tempNl = tempEl.getElementsByTagName("Property");

if(tempNl!=null)

for (int k = 0; k < tempNl.getLength(); k++)

{

Element tempElement = (Element)tempNl.item(k);

this.prop.setProperty(tempElement.getAttribute("name"),tempElement.getAttribute("value"));

}

//載入子群組

tempNl = tempEl.getElementsByTagName("SubGroup");

if (tempNl != null)

{

subGroup = new Identity[tempNl.getLength()];

for (int k = 0; k < subGroup.length; k++)

{

Element tempElement = (Element) tempNl.item(k);

subGroup[k] = new IdentityImpl(Identity.GROUP,Identity.XMLGROUP,tempElement.getAttribute("id"));

}

}

//載入使用者

tempNl = tempEl.getElementsByTagName("User");

if (tempNl != null)

{

user = new Identity[tempNl.getLength()];

for (int k = 0; k < subGroup.length; k++)

{

Element tempElement = (Element) tempNl.item(k);

user[k] = new IdentityImpl(Identity.USER,Identity.XMLUSER,tempElement.getAttribute("id"));

}

}

return this;

}

}

}

} catch (Exception e)

{

e.printStackTrace();

}

}

return null;

}

}



========================XML格式=====================

<Group id="G01">

<Name>系統部</Name>

<Description>系統部</Description>

</Group>

========================XML描述檔案==================

<xs:complexType name="Group">

<xs:annotation>

<xs:documentation>群組</xs:documentation>

</xs:annotation>

<xs:complexContent>

<xs:extension base="User">

<xs:sequence>

<xs:element name="SubGroup" type="Identity" minOccurs="0" maxOccurs="unbounded"/>

<xs:element name="User" type="Identity" minOccurs="0" maxOccurs="unbounded"/>

</xs:sequence>

</xs:extension>

</xs:complexContent>

</xs:complexType>









================================================

====================================================

======================================================

許可權元件之三(角色)

---------------------------------

首先,我定義了一個角色介面,可以從其中取出其的各種屬性.程式碼如後面所示.

然後定義一個AbstractRole把Role共性的東西進行處理.所有的取屬性的方法都已實現.使用者只要根據實現情況繼承AbstractRole把自己要定義的屬性進行處理即可.(因為每個系統的使用者都會有不同的屬性,所以留成抽象類供使用者自己擴充套件). 只要初始化變數description, name ,id, prop,users(可能是群組), permissionMap即可.



最後定義了一個類XMLRole來實現具體的Role作隨包的一個Role供一般使用者使用.不建議直接使用XMLRole,因為以後的版本可能會重寫該類.如果要使用的話可以把該類改名為自己的類即可.



這部分涉及到了一個ResourceLib類,該類中存是我自己定義的儲存各種資源配置用的類,可以直接使用.



======================Role.java===============================

package org.fswan.permission;

import org.fswan.Identity;

import java.util.Properties;

import org.fswan.workflow.exception.CantFoundIDException;

public interface Role

{

/**

* 獲取角色ID

* @return

*/

public Identity getId();

/**

* 獲取角色的名稱

* @return 名稱

*/

public String getName();

/**

* 獲取角色的描述

* @return 描述

*/

public String getDescription();

/**

* 獲取角色的所有的使用者(組)

* @return 使用者

*/

public User[] getUsers() throws CantFoundIDException;

/**

* 角色的屬性

* @return 屬性值

*/

public Properties getProperties();



/**

* 獲取使用者用作許可權判斷的屬性

* @param prop 許可權屬性

* @return 屬性值

*/

public Object getPermissionProp(String prop);

}

=======================AbstractRole===================================

package org.fswan.permission;



import java.util.HashMap;

import java.util.Properties;



import org.fswan.Identity;

import org.fswan.workflow.exception.IdentityMappingError;



public class AbstractRole implements Role

{

/**

* 描述

*/

protected String description ;

/**

* 名稱

*/

protected String name;

/**

* 標識

*/

protected Identity id;

/**

* 屬性

*/

protected Properties prop;

/**

* 該角色所有使用者的標識

*/

protected Identity[] users;

/**

* 許可權屬性表

*/

protected HashMap permissionMap;

/* (non-Javadoc)

* @see org.fswan.permission.Role#getDescription()

*/

public String getDescription()

{

return description;

}



/* (non-Javadoc)

* @see org.fswan.permission.Role#getId()

*/

public Identity getId()

{

return id;

}



/* (non-Javadoc)

* @see org.fswan.permission.Role#getName()

*/

public String getName()

{

return name;

}



/* (non-Javadoc)

* @see org.fswan.permission.Role#getProperties()

*/

public Properties getProperties()

{

return prop;

}



/* (non-Javadoc)

* @see org.fswan.permission.Role#getUsers()

*/

public User[] getUsers()

{

User[] retUser = new User[users.length];

for (int i = 0; i < retUser.length; i++)

{

try

{

retUser[i] = (User)users[i].newInstance();

} catch (IdentityMappingError e)

{

e.printStackTrace();

}

}

return retUser;

}



public String toString()

{

String retStr = id.getIdName();

retStr +=":"+name;

retStr += " "+description;

return retStr;

}



/* (non-Javadoc)

* @see org.fswan.permission.Role#getPermissionProp(java.lang.String)

*/

public Object getPermissionProp(String prop)

{

return permissionMap.get(prop);

}



}

==============================XMLRole.java===========================

/*

* Created on 2004-4-21

*

* To change the template for this generated file go to

* Window&gt;Preferences&gt;Java&gt;Code Generation&gt;Code and Comments

*/

package org.fswan.permission;

import java.util.ArrayList;

import java.util.Properties;



import javax.xml.parsers.DocumentBuilderFactory;



import org.fswan.Identity;

import org.fswan.IdentityImpl;

import org.fswan.ImplementIdentity;

import org.fswan.ResourceLib;

import org.w3c.dom.Document;

import org.w3c.dom.Element;

import org.w3c.dom.NodeList;

public class XMLRole extends AbstractRole implements ImplementIdentity

{

/**

* XML標籤用的字串

*/

public static final String ROLE = "Role";

public Object newInstance(Identity id)

{

ArrayList sources = ResourceLib.getXmlResource();

for (int i = 0; i < sources.size(); i++)

{

try

{

Document doc = DocumentBuilderFactory.newInstance().newDocumentBuilder().parse(sources.get(i).toString());

NodeList nl = doc.getElementsByTagName(ROLE);

for (int j = 0; j < nl.getLength(); j++)

{

Element tempEl = (Element)nl.item(j);



String idStr = tempEl.getAttribute("id");

if(idStr!=null && !idStr.equals(""))

{

if(idStr.equals(id.getIdName()))

{

this.id = new IdentityImpl(Identity.SWITCH,Identity.XMLROLE,idStr);



NodeList tempNl = tempEl.getElementsByTagName("Name");

name = tempNl.item(0).getChildNodes().item(0).getNodeValue();

tempNl = tempEl.getElementsByTagName("Description");

description = tempNl.item(0).getChildNodes().item(0).getNodeValue();



this.prop = new Properties();

tempNl = tempEl.getElementsByTagName("Property");

if(tempNl!=null)

for (int k = 0; k < tempNl.getLength(); k++)

{

Element tempElement = (Element)tempNl.item(k);

this.prop.setProperty(tempElement.getAttribute("name"),tempElement.getAttribute("value"));

}



return this;

}

}

}

} catch (Exception e)

{

e.printStackTrace();

}

}

return null;

}



}

========================XML格式=====================

<Role id="R01">

<Name>系統管理員</Name>

<Description>系統管理員</Description>

</Role>

========================XML描述檔案==================

<xs:complexType name="Role">

<xs:annotation>

<xs:documentation>角色名</xs:documentation>

</xs:annotation>

<xs:sequence>

<xs:element name="Name"/>

<xs:element name="Description"/>

<xs:element name="Property" minOccurs="0" maxOccurs="unbounded"/>

</xs:sequence>

<xs:attribute name="id" use="required"/>

</xs:complexType>









======================================================================

=======================================================================

=======================================================================



許可權元件之四(規則)

---------------------------

定義好User,Group,Role了以後,下面我定義了許可權判斷的規則.

首先定義Rule介面,見Rule.java.Rule只做一件事判斷User是否有許可權.

然後我實現了一個Rule,見RuleImpl.java.





這部分涉及到了一個Input類,這個類是一個輸入的類,介面如Input.java.這個通過繼承該介面可以使用各種方式資料(HTTP,XML,SOAP……)作為輸入資料.

Permission為許可權類,下面一篇會介紹.



======================Rule.java===============================

package org.fswan.permission;



import java.util.HashMap;



import org.fswan.Input;



/**

* 用來進行判斷的規則.

* 供Permission呼叫

*/

public interface Rule

{

public boolean pass(Permission permission,User user,HashMap oldData,Input input);

}



=======================RuleImpl===================================

package org.fswan.permission;

import java.util.ArrayList;

import java.util.HashMap;

import java.util.Properties;

import org.fswan.Input;

/**

*

*/

public class RuleImpl implements Rule

{

/* (non-Javadoc)

* @see org.fswan.permission.Rule#pass(org.fswan.permission.Permission, org.fswan.permission.User, org.fswan.permission.Role, org.fswan.permission.Group, java.util.HashMap, org.fswan.Input)

*/

public boolean pass(Permission permission, User user, HashMap oldData, Input input)

{

try

{

Role[] roles = user.getRoles();

if (roles != null)

{

for (int i = 0; i < roles.length; i++)

{

if (hasPermission(permission, user, roles[i], oldData, input)) //有許可權

return true;

}

}

Group[] groups = user.getGroups();

if (groups != null)

for (int i = 0; i < groups.length; i++)

{

if (pass(permission, groups[i], oldData, input))

return true;

}

return false;

} catch (Exception ex)

{

ex.printStackTrace();

}

return false;

}

/**

* 判斷使用者的某個角色是否有許可權進行某操作

* @param permission 許可權

* @param user 使用者

* @param role 角色

* @param oldData 資料

* @param input 輸入

* @return 是否有許可權

*/

private boolean hasPermission(Permission permission, User user, Role role, HashMap oldData, Input input)

{

//如角色沒有該許可權ID則無許可權

if (role.getPermissionProp(permission.getPermissionName()) == null)

return false;

//如果許可權還要判斷層別

if (permission.getPermissionItem() != null)

{

ArrayList item = permission.getPermissionItem();

boolean accept = true;

ArrayList roleItem = (ArrayList) role.getPermissionProp(permission.getPermissionName());

ttt : for (int i = 0; i < roleItem.size(); i++)

{

Properties p = (Properties) roleItem.get(i);

accept = true;

for (int j = 0; j < item.size(); j++)

{

if (p.getProperty(item.get(j).toString()) != null

&& p.getProperty(item.get(j).toString()).indexOf(oldData.get(item.get(j).toString()).toString())

!= -1) //如果無許可權

continue ttt;

}

return true;

}

return false;

}

return true;

}

}

=============================Input.java=======================

package org.fswan;



/**

* @author 方誌文

*

* 輸入資料的介面,作為主類的資料輸入式,

* 現可以從xml,HttpServletRequest和JSPUpload獲取資料

*

*/

public interface Input {

/**

* 獲取引數的值,如果無該引數則返回null,如果該引數對應多個值則返回其第一個值

* @param parameter 引數

* @return 值

*/

public String getParameter(String parameter);

/**

* 獲取引數的值列表

* @param parameter 引數

* @return 值

*/

public String[] getParameterValues(String parameter);

/**

* 獲取引數名的列表

* @return 所有的引數的名

*/

public String[] getParameterNames();

/**

* 獲取資料來源

* @return 資料來源

*/

public Object getSource();

/**

* 設定引數,如果已存在該引數,則原來的作廢

* @param parameter 引數

* @param value 值

*/

public void setParameter(String parameter,String value);

/**

* 設定引數,如果已存在該引數,則把原來的作廢

* @param parameter 引數

* @param values 值

*/

public void setParameter(String parameter,String[] values);

/**

* 新增引數,如果已存在該引數,則把該值新增到原值後成陣列

* @param parameter 引數

* @param value 值

*/

public void addParameter(String parameter,String value);

/**

* 新增引數(多個值),如果已存在該引數,則把該值新增到原值後成陣列

* @param parameter 引數

* @param values 值

*/

public void addParameter(String parameter,String[] values);

}





============================================================

===============================================================

===============================================================

許可權元件五(許可權)(完)

----------------------------

最後,我定義了一個Permission類把所有的元素連線起來形成一個完整許可權判斷元件。程式碼如下。使用者繼承該類時要完兩個方法getDenyRule,getAcceptRule即可。



當我們進行許可權判斷時只要呼叫hasPermission(User user,HashMap oldData,Input input)即可。其後三個引數分別為使用者,資料,輸入。使用者為在判斷的人,資料為原有資料,比較進行更新操作時,oldData為老資料,input在前一部分有介紹,為一個通用的輸入方式。比WEB輸入Post或Get方式等,可以轉換成一個Input類,也可以手動新建一個Input.為操作以及其資料的集合。

在Permission類中進行了DenyRule和AcceptRule的判斷,只要有一個DenyRule規則符合要求,則認為該使用者無許可權進行操作,如果使用者的沒被DenyRule排除則進行AcceptRule的判斷,只要有一個規則符合要求則認為該使用者有許可權。



因為本人比較懶所以Permission的實現還沒有寫出一個通用的。



綜上所述,使用此許可權元件要進行以下幾項工作:

1、 編寫User的實現。

2、 編寫Group的實現。

3、 編寫Role的實現。

4、 編寫Permission的實現。(過段時間我會擺個通用的上來)

5、 編寫N個Rule(同你的系統要進行許可權判斷相對應)。

6、 在程式中呼叫Permission.hasPermission判斷。









======================Permission.java===============================

package org.fswan.permission;



import java.util.ArrayList;

import java.util.HashMap;

import org.fswan.Input;



/**

* 許可權判斷類

*/

public abstract class Permission

{

public String permission;

public String subPermission;

protected ArrayList prop;

public boolean hasPermission(User user,HashMap oldData,Input input)

{

Rule[] rules = getDenyRule();

boolean accept = true;

for (int i = 0; i < rules.length; i++)

{

if(!rules[i].pass(this,user,oldData,input))

{

accept = false;

break;

}

}

if(accept)return false;

rules = getAcceptRule();

for (int i = 0; i < rules.length; i++)

{

if(!rules[i].pass(this,user,oldData,input))

return false;

}

return true;

}

public String getPermissionName()

{

if(subPermission==null)return permission;

return permission+":"+subPermission;

}

public ArrayList getPermissionItem()

{

return prop;

}

public abstract Rule[] getDenyRule();

public abstract Rule[] getAcceptRule();

}







==================================================

==================================================

==================================================

許可權元件所缺的檔案

原意是給大家看一下結構,沒想大家都那麼關心,我現在把所有的程式碼貼上來,謝謝大家關心.

唉,BLOG好煩啊,無法直接上傳檔案要一個一個貼


================ResourceLib.java ============
package org.fswan;

import java.util.ArrayList;
import java.util.Properties;

/**
* 用來儲存通用的XML配置檔案位置和資料庫連線屬性.
* 作為org.fswan裡所有的包中類的基礎配置檔案.
*/
public class ResourceLib
{
/**
* 驅動的字串
*/
public static final String DRIVER = "Driver";
/**
* 資料庫連線字串
*/
public static final String URL = "URL";
/**
* 使用者
*/
public static final String USER = "User";
/**
* 密碼
*/
public static final String PASSWORD = "Password";
/**
* 所有的XML配置檔案的儲存位置,儲存的物件為URL
*/
private static ArrayList resource = new ArrayList();
/**
* 儲存所有的資料庫配置.
* 所有的資料庫儲存位置格式為:
* 物件為Properties物件
* 而properties物件裡包含:
* {@link #DRIVER DRIVER},{@link #URL URL},{@link #USER USER},{@link #PASSWORD PASSWORD},{@link #VIEW VIEW},{@link #TYPE TYPE}六個屬性分別對應
* 資料庫的驅動,邊接字串,使用者名稱,密碼,檢視,型別
* 或者
* {@link #JNDI JNDI},{@link #VIEW VIEW},{@link #TYPE TYPE}
* JNDI名,檢視,型別
* 型別是以下的一個
* {@link #WORKFLOW WORKFLOW}
* {@link #BRAND BRAND}
* {@link #STATUS STATUS}
* {@link #SWITCH SWITCHER}
* {@link #WORKUNIT WORKUNIT}
* {@link #USER USER}
*/
private static ArrayList prop = new ArrayList();
/**
* 獲取所有的XML資源
* @return XML資源泉
*/
public static ArrayList getXmlResource()
{
return resource;
}
/**
* 獲取所有的資料庫連線屬性
* @return 資料庫連結屬性
*/
public static ArrayList getConnection()
{
return prop;
}
/**
* 增加XML資源
* @param source XML資源
*/
public static void addResource(String source)
{
synchronized(resource)
{
resource.add(source);
}
}
/**
* 增加資料庫連結屬性
* @param pro 資料庫連結屬性
*/
public static void addDataProperty(Properties pro)
{
synchronized(prop)
{
prop.add(pro);
}
}
}

==============Input.java============
/*
* Created on 2003-11-20
*
* Create By 方誌文
* email:
[email protected]

*/
package org.fswan;

/**
* @author 方誌文
*
* 輸入資料的介面,作為主類的資料輸入式,
* 現可以從xml,HttpServletRequest和JSPUpload獲取資料
*
*/
public interface Input {
/**
* 獲取引數的值,如果無該引數則返回null,如果該引數對應多個值則返回其第一個值
* @param parameter 引數
* @return 值
*/
public String getParameter(String parameter);
/**
* 獲取引數的值列表
* @param parameter 引數
* @return 值
*/
public String[] getParameterValues(String parameter);
/**
* 獲取引數名的列表
* @return 所有的引數的名
*/
public String[] getParameterNames();
/**
* 獲取資料來源
* @return 資料來源
*/
public Object getSource();
/**
* 設定引數,如果已存在該引數,則原來的作廢
* @param parameter 引數
* @param value 值
*/
public void setParameter(String parameter,String value);
/**
* 設定引數,如果已存在該引數,則把原來的作廢
* @param parameter 引數
* @param values 值
*/
public void setParameter(String parameter,String[] values);
/**
* 新增引數,如果已存在該引數,則把該值新增到原值後成陣列
* @param parameter 引數
* @param value 值
*/
public void addParameter(String parameter,String value);
/**
* 新增引數(多個值),如果已存在該引數,則把該值新增到原值後成陣列
* @param parameter 引數
* @param values 值
*/
public void addParameter(String parameter,String[] values);
}
================ManualInput.java ==============
package org.fswan;

public class ManualInput extends AbstractInput
{
/* (non-Javadoc)
* @see org.fswan.Input#getSource()
*/
public Object getSource()
{
return null;
}

}
===================Identity.java==========
package org.fswan;

import org.fswan.workflow.exception.IdentityMappingError;

/**
* @author Administrator
* 這個接是一個標識,用來唯一標識所有的工作流,狀態,切換開關,分枝操作
*/
public interface Identity
{
/**
* 工作流的標識
*/
public static final int WORKFLOW = 0;
/**
* 分枝操作的標識
*/
public static final int BRAND = 1;
/**
* 狀態的標識
*/
public static final int STATUS =2;
/**
* 切換開關的標識
*/
public static final int SWITCH = 3;
/**
* 使用者的標識
*/
public static final int USER = 4;
/**
* 工作單元
*/
public static final int WORKUNIT = 5;
/**
* 角色
*/
public static final int ROLE = 6;
/**
* 群組
*/
public static final int GROUP = 7;

public static final int VIEWCLASS = 255;

public static final String XMLWORKFLOW = "XMLWorkFlow";
public static final String XMLBRAND = "XMLBrand";
public static final String XMLSWITCHER = "XMLSwitcher";
public static final String XMLSTATUS = "XMLStatus";
public static final String XMLWORKUNIT = "XMLWorkUnit";
public static final String DBWORKFLOW = "DBWorkFlow";
public static final String DBBRAND = "DBBrand";
public static final String DBSWITCHER = "DBSwitcher";
public static final String DBSTATUS = "DBStatus";
public static final String DBWORKUNIT = "DBWorkUnit";
public static final String XMLUSER = "XMLUser";
public static final String XMLGROUP = "XMLGroup";
public static final String XMLROLE = "XMLRole";

/**
* 獲取標識的型別
* 是以下常量中的一個
* {@link #WORKFLOW WORKFLOW}
* {@link #BRAND BRAND}
* {@link #STATUS STATUS}
* {@link #SWITCH SWITCH}
* {@link #USER USER}
* @return 標識的型別
*/
public int getIdType();
/**
* 獲取標識的名稱
* @return 標識的名稱
*/
public String getIdName();
/**
* 返回該Identity的子型別,該子型別是給newInstance使用的
* @return 子型別
*/
public String getSubType();
/**
* 通過ID生成例項
* @return 例項
* @throws IdentityMappingError 找不到生器異常
*/
public Object newInstance() throws IdentityMappingError;
}
=============IdentityImpl.java===============
package org.fswan;

import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Hashtable;

import org.fswan.workflow.exception.IdentityMapHadExist;
import org.fswan.workflow.exception.IdentityMappingError;

/**
* 唯一識別符號類.
* 由唯一識別符號可以呼叫相應的類來生成相對應的介面生成相對應的例項
* 不同種類識別符號生成相對應的例項的類在{@link map}中進行對映定義.
* 可呼叫靜態方法register進行註冊.
*/
public class IdentityImpl implements Identity
{
private String name;
private int type;
private String subType;
/**
* 從ID到類的對映表
*/
private static Hashtable map = new Hashtable();
public IdentityImpl(int type,String subType,String name)
{
this.type = type;
this.subType=subType;
this.name = name;
}
public IdentityImpl genIdentity(int type)
{
SimpleDateFormat f = new SimpleDateFormat("yyyyMMddHHmmssSSS");
String name = f.format(new Date());
return new IdentityImpl(type,"",name);
}
/* (non-Javadoc)
* @see org.fswan.Identity#getIdName()
*/
public String getIdName()
{
return name;
}

/* (non-Javadoc)
* @see org.fswan.Identity#getIdType()
*/
public int getIdType()
{
return type;
}
public String getSubType()
{
return subType;
}

public String toString()
{
return "["+type+":"+name+"]";
}
public boolean equals(Object obj)
{
if(obj instanceof Identity)
{
return this.getIdType()==((Identity)obj).getIdType()
&& getIdName().equals(((Identity)obj).getIdName());
}
return false;
}
/**
* 查詢相應對的物件
* @return 例項化後的物件
* @throws IdentityMappingError 對映實現不了,
* 可能是因為註冊的類不存在或者無法例項化該類,或該類不是ImplementIdentity
*/
public Object newInstance() throws IdentityMappingError
{
try
{
if(map.get(subType)==null)return null;
ImplementIdentity ids = (ImplementIdentity)Class.forName(map.get(subType).toString()).newInstance();
return ids.newInstance(this);
} catch (InstantiationException e)
{
e.printStackTrace();
} catch (IllegalAccessException e)
{
e.printStackTrace();
} catch (ClassNotFoundException e)
{
e.printStackTrace();
}
throw new IdentityMappingError();
}
/**
* 註冊標識種類到生成例項類的對映
* @param type 型別
* @param obj 相對應的類名
* @throws IdentityMapHadExist 異常,(該型別已註冊)
*/
public static void register(String subType,String obj) throws IdentityMapHadExist
{
if(map.containsKey(subType)) throw new IdentityMapHadExist(subType);
map.put(subType,obj);
}
static
{
try
{
IdentityImpl.register(Identity.DBBRAND,"org.fswan.workflow.DBWrokFlow");
} catch (IdentityMapHadExist e)
{
e.printStackTrace();
}
try
{
IdentityImpl.register(Identity.DBSTATUS,"org.fswan.workflow.DBStatus");
} catch (IdentityMapHadExist e)
{
e.printStackTrace();
}
try
{
IdentityImpl.register(Identity.DBSWITCHER,"org.fswan.workflow.DBSwitcher");
} catch (IdentityMapHadExist e)
{
e.printStackTrace();
}
try
{
IdentityImpl.register(Identity.DBWORKFLOW,"org.fswan.workflow.DBWrokFlow");
} catch (IdentityMapHadExist e)
{
e.printStackTrace();
}
try
{
IdentityImpl.register(Identity.DBWORKUNIT,"org.fswan.workflow.DBWorkUnit");
} catch (IdentityMapHadExist e)
{
e.printStackTrace();
}
try
{
IdentityImpl.register(Identity.XMLBRAND,"org.fswan.workflow.XMLBrand");
} catch (IdentityMapHadExist e)
{
e.printStackTrace();
}
try
{
IdentityImpl.register(Identity.XMLGROUP,"org.fswan.permission.XMLGroup");
} catch (IdentityMapHadExist e)
{
e.printStackTrace();
}
try
{
IdentityImpl.register(Identity.XMLROLE,"org.fswan.permission.XMLRole");
} catch (IdentityMapHadExist e)
{
e.printStackTrace();
}
try
{
IdentityImpl.register(Identity.XMLSTATUS,"org.fswan.workflow.XMLStatus");
} catch (IdentityMapHadExist e)
{
e.printStackTrace();
}
try
{
IdentityImpl.register(Identity.XMLSWITCHER,"org.fswan.workflow.XMLSwitcher");
} catch (IdentityMapHadExist e)
{
e.printStackTrace();
}
try
{
IdentityImpl.register(Identity.XMLUSER,"org.fswan.permission.XMLUser");
} catch (IdentityMapHadExist e)
{
e.printStackTrace();
}
try
{
IdentityImpl.register(Identity.XMLWORKFLOW,"org.fswan.workflow.XMLWorkFlow");
} catch (IdentityMapHadExist e)
{
e.printStackTrace();
}
try
{
IdentityImpl.register(Identity.XMLWORKUNIT,"org.fswan.workflow.XMLWorkUnit");
} catch (IdentityMapHadExist e)
{
e.printStackTrace();
}

}
}
==================ImplementIdentity.java=============
package org.fswan;

/**
* @author swan
* 通過ID例項化相應的物件.
* 當用戶自己實現User,Role,Group,Brand等物件時,通過ID來查詢相對應的物件,
* 在類IdentityImpl物件中根據註冊各種Identity型別對應的InstanceIdentity物件
* 來例項化物件.
* 注意:該介面的子類的構造方法一定是PUBLIC且不帶任何引數.
*/
public interface ImplementIdentity
{
/**
* 例項化ID相對對應的物件.
* @param identity 要例項化的物件的ID
* @return 物件
*/
public Object newInstance(Identity identity);
}
===========CantFoundIDException.java-==============
package org.fswan.workflow.exception;

import org.fswan.Identity;

/**
* @author Administrator
*
* To change the template for this generated type comment go to
* Window&gt;Preferences&gt;Java&gt;Code Generation&gt;Code and Comments
*/
public class CantFoundIDException extends Exception
{
public CantFoundIDException(Identity id)
{
super("Can't Found ID:["+id.getIdType()+":"+id.getIdName()+"]");
}
}
==================IdentityMapHadExist.java============
package org.fswan.workflow.exception;

/**
* @author swan
*
* To change the template for this generated type comment go to
* Window&gt;Preferences&gt;Java&gt;Code Generation&gt;Code and Comments
*/
public class IdentityMapHadExist extends Exception
{
public IdentityMapHadExist(String subType)
{
super("Mapping Had Exist:"+subType);
}
}
==================IdentityMappingError.java============
package org.fswan.workflow.exception;

/**
* @author swan
*
* To change the template for this generated type comment go to
* Window&gt;Preferences&gt;Java&gt;Code Generation&gt;Code and Comments
*/
public class IdentityMappingError extends Exception
{
public IdentityMappingError()
{
super("The Mapping Class is not InstanceIdentity.");
}
}
=================TypeCastException.java ============
package org.fswan.workflow.exception;

import org.fswan.db.Field;

/**
* 型別轉換異常,當從字串轉成特定型別出錯時丟擲
*/
public class TypeCastException extends Exception
{
/**
* 建構函式
* @param field 欄位
* @param str 字串值
*/
public TypeCastException(Field field,String str)
{
super(str+" cast to "+field + " Error");
}
}





思路很好!!!!!!!!!

author: EdwarddotNet

前言:
許可權往往是一個極其複雜的問題,但也可簡單表述為這樣的邏輯表示式:判斷“Who對What(Which)進行How的操作”的邏輯表示式是否為真。針對不同的應用,需要根據專案的實際情況和具體架構,在維護性、靈活性、完整性等N多個方案之間比較權衡,選擇符合的方案。
目標:
直觀,因為系統最終會由終端使用者來維護,許可權分配的直觀和容易理解,顯得比較重要,系統不辭勞苦的實現了組的繼承,除了功能的必須,更主要的就是因為它足夠直觀。
簡單,包括概念數量上的簡單和意義上的簡單還有功能上的簡單。想用一個許可權系統解決所有的許可權問題是不現實的。設計中將常常變化的“定製”特點比較強的部分判斷為業務邏輯,而將常常相同的“通用”特點比較強的部分判斷為許可權邏輯就是基於這樣的思路。
擴充套件,採用可繼承在擴充套件上的困難。的Group概念在支援許可權以組方式定義的同時有效避免了重定義時
現狀:
對於在企業環境中的訪問控制方法,一般有三種:
1.自主型訪問控制方法。目前在我國的大多數的資訊系統中的訪問控制模組中基本是藉助於自主型訪問控制方法中的訪問控制列表(ACLs)。
2.強制型訪問控制方法。用於多層次安全級別的軍事應用。
3.基於角色的訪問控制方法(RBAC)。是目前公認的解決大型企業的統一資源訪問控制的有效方法。其顯著的兩大特徵是:1.減小授權管理的複雜性,降低管理開銷。2.靈活地支援企業的安全策略,並對企業的變化有很大的伸縮性。
名詞:
粗粒度:表示類別級,即僅考慮物件的類別(the type of object),不考慮物件的某個特
定例項。比如,使用者管理中,建立、刪除,對所有的使用者都一視同仁,並不區分操作的具體物件例項。
細粒度:表示例項級,即需要考慮具體物件的例項(the instance of object),當然,細
粒度是在考慮粗粒度的物件類別之後才再考慮特定例項。比如,合同管理中,列表、刪除,需要區分該合同例項是否為當前使用者所建立。
原則:
許可權邏輯配合業務邏輯。即許可權系統以為業務邏輯提供服務為目標。相當多細粒度的許可權問題因其極其獨特而不具通用意義,它們也能被理解為是“業務邏輯”的一部分。比如,要求:“合同資源只能被它的建立者刪除,與建立者同組的使用者可以修改,所有的使用者能夠瀏覽”。這既可以認為是一個細粒度的許可權問題,也可以認為是一個業務邏輯問題。在這裡它是業務邏輯問題,在整個許可權系統的架構設計之中不予過多考慮。當然,許可權系統的架構也必須要能支援這樣的控制判斷。或者說,系統提供足夠多但不是完全的控制能力。即,設計原則歸結為:“系統只提供粗粒度的許可權,細粒度的許可權被認為是業務邏輯的職責”。
需要再次強調的是,這裡表述的許可權系統僅是一個“不完全”的許可權系統,即,它不提供所有關於許可權的問題的解決方法。它提供一個基礎,並解決那些具有“共性”的(或者說粗粒度的)部分。在這個基礎之上,根據“業務邏輯”的獨特許可權需求,編碼實現剩餘部分(或者說細粒度的)部分,才算完整。回到許可權的問題公式,通用的設計僅解決了Who+What+How 的問題,其他的許可權問題留給業務邏輯解決。
概念:
Who:許可權的擁用者或主體(Principal、User、Group、Role、Actor等等)
What:許可權針對的物件或資源(Resource、Class)。
How:具體的許可權(Privilege, 正向授權與負向授權)。
Role:是角色,擁有一定數量的許可權。
Operator:操作。表明對What的How 操作。
說明:
User:與 Role 相關,使用者僅僅是純粹的使用者,許可權是被分離出去了的。User是不能與 Privilege 直接相關的,User 要擁有對某種資源的許可權,必須通過Role去關聯。解決 Who 的問題。
Resource:就是系統的資源,比如部門新聞,文件等各種可以被提供給使用者訪問的物件。資源可以反向包含自身,即樹狀結構,每一個資源節點可以與若干指定許可權類別相關可定義是否將其許可權應用於子節點。
Privilege:是Resource Related的許可權。就是指,這個許可權是繫結在特定的資源例項上的。比如說部門新聞的釋出許可權,叫做"部門新聞釋出許可權"。這就表明,該Privilege是一個釋出許可權,而且是針對部門新聞這種資源的一種釋出許可權。Privilege是由Creator在做開發時就確定的。許可權,包括系統定義許可權和使用者自定義許可權使用者自定義許可權之間可以指定排斥和包含關係(如:讀取,修改,管理三個許可權,管理 許可權 包含 前兩種許可權)。Privilege 如"刪除" 是一個抽象的名詞,當它不與任何具體的 Object 或 Resource 繫結在一起時是沒有任何意義的。拿新聞釋出來說,釋出是一種許可權,但是隻說釋出它是毫無意義的。因為不知道釋出可以操作的物件是什麼。只有當釋出與新聞結合在一起時,才會產生真正的 Privilege。這就是 Privilege Instance。許可權系統根據需求的不同可以延伸生很多不同的版本。
Role:是粗粒度和細粒度(業務邏輯)的介面,一個基於粗粒度控制的許可權框架軟體,對外的介面應該是Role,具體業務實現可以直接繼承或拓展豐富Role的內容,Role不是如同User或Group的具體實體,它是介面概念,抽象的通稱。
Group:使用者組,許可權分配的單位與載體。許可權不考慮分配給特定的使用者。組可以包括組(以實現許可權的繼承)。組可以包含使用者,組內使用者繼承組的許可權。Group要實現繼承。即在建立時必須要指定該Group的Parent是什麼Group。在粗粒度控制上,可以認為,只要某使用者直接或者間接的屬於某個Group那麼它就具備這個Group的所有操作許可。細粒度控制上,在業務邏輯的判斷中,User僅應關注其直接屬於的Group,用來判斷是否“同組” 。Group是可繼承的,對於一個分級的許可權實現,某個Group通過“繼承”就已經直接獲得了其父Group所擁有的所有“許可權集合”,對這個Group而言,需要與許可權建立直接關聯的,僅是它比起其父Group需要“擴充套件”的那部分許可權。子組繼承父組的所有許可權,規則來得更簡單,同時意味著管理更容易。為了更進一步實現許可權的繼承,最直接的就是在Group上引入“父子關係”。
User與Group是多對多的關係。即一個User可以屬於多個Group之中,一個Group可以包括多個User。子Group與父Group是多對一的關係。Operator某種意義上類似於Resource + Privilege概念,但這裡的Resource僅包括Resource Type不表示Resource Instance。Group 可以直接對映組織結構,Role 可以直接對映組織結構中的業務角色,比較直觀,而且也足夠靈活。Role對系統的貢獻實質上就是提供了一個比較粗顆粒的分配單位。
Group與Operator是多對多的關係。各概念的關係圖示如下:
解釋:
Operator的定義包括了Resource Type和Method概念。即,What和How的概念。之所以將What和How繫結在一起作為一個Operator概念而不是分開建模再建立關聯,這是因為很多的How對於某What才有意義。比如,釋出操作對新聞物件才有意義,對使用者物件則沒有意義。
How本身的意義也有所不同,具體來說,對於每一個What可以定義N種操作。比如,對於合同這類物件,可以定義建立操作、提交操作、檢查衝突操作等。可以認為,How概念對應於每一個商業方法。其中,與具體使用者身份相關的操作既可以定義在操作的業務邏輯之中,也可以定義在操作級別。比如,建立者的瀏覽檢視與普通使用者的瀏覽檢視要求內容不同。既可以在外部定義兩個操作方法,也可以在一個操作方法的內部根據具體邏輯進行處理。具體應用哪一種方式應依據實際情況進行處理。
這樣的架構,應能在易於理解和管理的情況下,滿足絕大部分粗粒度許可權控制的功能需要。但是除了粗粒度許可權,系統中必然還會包括無數對具體Instance的細粒度許可權。這些問題,被留給業務邏輯來解決,這樣的考慮基於以下兩點:
一方面,細粒度的許可權判斷必須要在資源上建模許可權分配的支援資訊才可能得以實現。比如,如果要求建立者和普通使用者看到不同的資訊內容,那麼,資源本身應該有其建立者的資訊。另一方面,細粒度的許可權常常具有相當大的業務邏輯相關性。對不同的業務邏輯,常常意味著完全不同的許可權判定原則和策略。相比之下,粗粒度的許可權更具通用性,將其實現為一個架構,更有重用價值;而將細粒度的許可權判斷實現為一個架構級別的東西就顯得繁瑣,而且不是那麼的有必要,用定製的程式碼來實現就更簡潔,更靈活。
所以細粒度控制應該在底層解決,Resource在例項化的時候,必需指定Owner和GroupPrivilege在對Resource進行操作時也必然會確定約束型別:究竟是OwnerOK還是GroupOK還是AllOK。Group應和Role嚴格分離User和Group是多對多的關係,Group只用於對使用者分類,不包含任何Role的意義;Role只授予User,而不是Group。如果使用者需要還沒有的多種Privilege的組合,必須新增Role。Privilege必須能夠訪問Resource,同時帶User引數,這樣許可權控制就完備了。
思想:
許可權系統的核心由以下三部分構成:1.創造許可權,2.分配許可權,3.使用許可權,然後,系統各部分的主要參與者對照如下:1.創造許可權 - Creator創造,2.分配許可權 - Administrator 分配,3.使用許可權 - User:
1. Creator 創造 Privilege, Creator 在設計和實現系統時會劃分,一個子系統或稱為模組,應該有哪些許可權。這裡完成的是 Privilege 與 Resource 的物件宣告,並沒有真正將 Privilege 與具體Resource 例項聯絡在一起,形成Operator。
2. Administrator 指定 Privilege 與 Resource Instance 的關聯。在這一步, 許可權真正與資源例項聯絡到了一起, 產生了Operator(Privilege Instance)。Administrator利用Operator這個基本元素,來創造他理想中的許可權模型。如,建立角色,建立使用者組,給使用者組分配使用者,將使用者組與角色關聯等等...這些操作都是由 Administrator 來完成的。
3. User 使用 Administrator 分配給的許可權去使用各個子系統。Administrator 是使用者,在他的心目中有一個比較適合他管理和維護的許可權模型。於是,程式設計師只要回答一個問題,就是什麼許可權可以訪問什麼資源,也就是前面說的 Operator。程式設計師提供 Operator 就意味著給系統穿上了盔甲。Administrator 就可以按照他的意願來建立他所希望的許可權框架可以自行增加,刪除,管理Resource和Privilege之間關係。可以自行設定使用者User和角色Role的對應關係。(如果將 Creator看作是 Basic 的發明者, Administrator 就是 Basic 的使用者,他可以做一些指令碼式的程式設計) Operator是這個系統中最關鍵的部分,它是一個紐帶,一個系在Programmer,Administrator,User之間的紐帶。
用一個功能模組來舉例子。
一.建立角色功能並做分配:
1.如果現在要做一個員工管理的模組(即Resources),這個模組有三個功能,分別是:增加,修改,刪除。給這三個功能各自分配一個ID,這個ID叫做功能代號:
Emp_addEmp,Emp_deleteEmp,Emp_updateEmp。
2.建立一個角色(Role),把上面的功能程式碼加到這個角色擁有的許可權中,並儲存到資料庫中。角色包括系統管理員,測試人員等。
3.建立一個員工的賬號,並把一種或幾種角色賦給這個員工。比如說這個員工既可以是公司管理人員,也可以是測試人員等。這樣他登入到系統中將會只看到他擁有許可權的那些模組。
二.把身份資訊加