它比我前幾天看的ASP.NET StartKit Commerce複雜了許多。
例如:在ASP.NET StartKit TimeTracker開始有明顯的三層結構的設計。PL層,BLL層和DAL層。
同時開始在項目中引進了角色權限管理功能等等。
今天我們先討論角色權限的實現問題。
讓我們先看一角色權限設置的參考資料:
http://www.cnblogs.com/kwklover/archive/2004/06/29/19455.aspx
現在假如我們系統中有3 種角色:Service,Work,Manage
要是我們想在WebForm1.aspx禁止Service,Manage這2類角色的登陸用戶訪問,我們可以在Web.config文件中做下面設置:
<location path="WebForm1.aspx">
<system.web>
<authorization>
<deny roles="Service,Manage" />
<deny users="?" />
</authorization>
</system.web>
</location>
還有一種方式就是:建立三個文件夾,某一角色的人只能訪問某一文件夾裏的ASPX.NET文件
假如我有用戶a,他有Service,Work這2種角色,假如有頁面abc.aspx,它允許Work,Manage這2種角色的用戶訪問。
個人感覺這樣設置的靈活性不好,有沒有通過代碼控制的方法呢?
我編寫了如下代碼:實現單用戶可以多角色,單頁面多角色訪問。
讓我們先看Global.asax.cs中代碼,請注意看事件Application_AuthenticateRequest中的代碼實現。
using System.Web;
using System.Web.Security;
using System.Web.SessionState;
using System.Threading;
using System.Globalization;
using System.Configuration;
namespace BluepieCustomerService
{
/**//// <summary>
/// Global 的摘要說明。
/// </summary>
public class Global : System.Web.HttpApplication
{
/**//// <summary>
/// 必需的設計器變量。
/// </summary>
private System.ComponentModel.IContainer components = null;
/**//// <summary>
/// 本系統自定義的角色之一“服務人員”
/// </summary>
public const string ConstUserRoleNameService="Service";
/**//// <summary>
/// 本系統自定義的角色之一“普通工作人員”
/// </summary>
public const string ConstUserRoleNameWork="Work";
/**//// <summary>
/// 本系統自定義的角色之一“管理人員”
/// </summary>
public const string ConstUserRoleNameManage="Manage";
/**//// <summary>
/// 逗號字符串
/// </summary>
public const string ConstStringComma=",";
/**//// <summary>
/// 百分號字符串
/// </summary>
public const string ConstStringPercent="%";
/**//// <summary>
/// char 類型逗號
/// </summary>
public const char ConstCharComma=',';
/**//// <summary>
/// char 類型百分號
/// </summary>
public const char ConstCharPercent='%';
/**//// <summary>
/// 發生權限訪問錯誤時,轉向的錯誤提示頁面
/// </summary>
public const string ConstRoleErrorPageName="RoleError.aspx?Index=-1";
/**//// <summary>
/// DB的連接字符串
/// </summary>
public const string ConstWebConfigFileKeyName_ConnectionString="ConnectionString";
public Global()
{
InitializeComponent();
}
protected void Application_Start(Object sender, EventArgs e)
{
}
protected void Session_Start(Object sender, EventArgs e)
{
}
protected void Application_BeginRequest(Object sender, EventArgs e)
{
}
protected void Application_EndRequest(Object sender, EventArgs e)
{
}
protected void Application_AuthenticateRequest(Object sender, EventArgs e)
{
if (HttpContext.Current.User!=null)
{
//用戶已經通過驗證
if (Request.IsAuthenticated )
{
//得到用戶的角色Cookie的名稱
string userRolesCookieName=FormsAuthentication.FormsCookieName;
//得到用戶的角色Cookie
string currentCookieValue=Context.Request.Cookies[userRolesCookieName].Value;
//解密
FormsAuthenticationTicket currentFormsAuthenticationTicket = FormsAuthentication.Decrypt(currentCookieValue);
//得到cookie中的用戶數據
string[] userData = BCSTool.StringToArray(currentFormsAuthenticationTicket.UserData,ConstCharPercent);
//取得用戶的個人詳細信息數組
int userId=Convert.ToInt32( userData[0]);
string userDisPlayName=userData[1];
string userName=userData[2];
string userEmail=userData[3];
//按當初加入的規則分解爲數組
string [] roleArray= BCSTool.StringToArray(userData[4],ConstCharComma );
//設置當前 HTTP 安全信息
Context.User = new BCSLoginPrincipal(userId,
userDisPlayName,
userName,
userEmail,
roleArray,
HttpContext.Current.User.Identity);
}
}
}
protected void Application_Error(Object sender, EventArgs e)
{
}
protected void Session_End(Object sender, EventArgs e)
{
}
protected void Application_End(Object sender, EventArgs e)
{
}
Web 窗體設計器生成的代碼#region Web 窗體設計器生成的代碼
/**//// <summary>
/// 設計器支持所需的方法 - 不要使用代碼編輯器修改
/// 此方法的內容。
/// </summary>
private void InitializeComponent()
{
this.components = new System.ComponentModel.Container();
}
#endregion
}
}
讓我們再看類BCSLoginPrincipal
實現了接口:IPrincipal,該接口定義用戶對象的基本功能。
該接口有一個屬性IIdentity Identity {get;},獲取當前用戶的標識。
一個方法bool IsInRole(string role),確定當前用戶是否屬於指定的角色。
using System.Security.Principal;
namespace BluepieCustomerService
{
/**//// <summary>
/// BCSLoginPrincipal 的摘要說明。
/// </summary>
public class BCSLoginPrincipal :System.Security.Principal.IPrincipal
{
private string[] _userRole;
protected IIdentity _iIdentity;
int _userId;
string _userDisPlayName;
string _userName;
string _userEmail;
/**//// <summary>
/// 類BCSLoginPrincipal的有參構造器
/// </summary>
/// <param name="iIdentity"></param>
/// <param name="userRole"></param>
public BCSLoginPrincipal(int userId,string userDisPlayName,string userName,string userEmail , string[] userRole,IIdentity iIdentity)
{
this._userId=userId;
this._userDisPlayName=userDisPlayName;
this._userName=userName;
this._userEmail=userEmail;
this._userRole=userRole;
this._iIdentity=iIdentity;
}
/**//// <summary>
/// 取得和設置登陸用戶的UserID
/// </summary>
public int UserId
{
get
{
return _userId;
}
set
{
_userId=value;
}
}
/**//// <summary>
/// 取得和設置登陸用戶的登陸帳號
/// </summary>
public string UserDisPlayName
{
get
{
return _userDisPlayName;
}
set
{
_userDisPlayName=value;
}
}
/**//// <summary>
/// 取得和設置登陸用戶的真實姓名
/// </summary>
public string UserName
{
get
{
return _userName;
}
set
{
_userName=value;
}
}
/**//// <summary>
/// 取得和設置登陸用戶的Email
/// </summary>
public string UserEmail
{
get
{
return _userEmail;
}
set
{
_userEmail=value;
}
}
/**//// <summary>
/// 取得和設置登陸用戶的角色數組
/// </summary>
public string[] UserRole
{
get
{
return _userRole;
}
set
{
_userRole = value;
}
}
public IIdentity Identity
{
get
{
return _iIdentity;
}
set
{
_iIdentity = value;
}
}
/**//// <summary>
/// 實現接口方法,判斷用戶的角色是否合法
/// </summary>
/// <param name="role"></param>
/// <returns></returns>
public bool IsInRole(string role)
{
//用戶傳過來的角色字符串有可能包含多個角色,所以我們得先分解爲數組
string [] roleArray = BCSTool.StringToArray(role,Global.ConstCharComma);
//取得數組長度
int roleArrayLength=roleArray.Length;
//取出數組中每一個角色與用戶的現有角色做比較
for(int i=0;i<roleArrayLength;i++)
{
if( isRole( roleArray[i] ) )
{
return true;
}
}
return false;
}
/**//// <summary>
/// 與用戶的現有角色做比較
/// </summary>
/// <param name="str"></param>
/// <returns></returns>
bool isRole(string str)
{
int arrayLength=_userRole.Length;
for(int i=0;i<arrayLength;i++)
{
if ( _userRole[i]==str )
{
return true;
}
}
return false;
}
}
}