[Security]Custom Role Provider without Member Provider
-
導覽
1. 登入
1.1. 建立 LoginPage.aspx 處理登入
1.2. 設定 web.config authentication section
2. 授權
2.1 人員與角色的對應讀取於INI中
2.2 建立 Role Persist for 存取人員對應角色於記憶體中.
2.3 建立 Role Provider 實作 System.Web.Security.RoleProvider
2.4 設定 web.config 的 roleManager section
2.5 設定 web.config 的 authorization section (含: location)
2.6 建立 AccessDenied.aspx 處理無權限, 並修改LoginPage.aspx 導頁至 AccessDenied.aspx
3. 內容
3.1 建立Web.sitemap
3.2 設定 web.config 的 siteMap section
3.3 建立內容頁面
-
實作
1. 登入
1.1. 建立 LoginPage.aspx 處理登入
<asp:Login ID="Login1" runat="server" onauthenticate="Login1_Authenticate"></asp:Login>protected void Login1_Authenticate(object sender, AuthenticateEventArgs e){e.Authenticated = true; // always login}
1.2. 設定 web.config authentication section
<authentication mode="Forms"><forms name=".CA_BKSTG_AUTH" loginUrl="LoginPage.aspx" defaultUrl="Index.aspx"></forms></authentication>
2. 授權
2.1 人員與角色的對應讀取於INI中
# ~/App_Data/Role.iniROLE.A=John,Kevin,PeterROLE.B=Amy,Stacy
2.2 建立 Role Persist for 存取人員對應角色於記憶體中.
class MacroRolePersist{Dictionary<string, List<string>> persist = new Dictionary<string, List<string>>();public void Clear(){foreach (string role in persist.Keys){persist[role].Clear();}persist.Clear();}public void Load(string ini){if (!File.Exists(ini)){throw new ArgumentException(ini + " not found");}using (StreamReader reader = new StreamReader(ini)){Properties prpts = new Properties();prpts.Load(reader);foreach (string name in prpts.PropertyNames()){string[] names = Regex.Split(name, @"^ROLE\.", RegexOptions.IgnoreCase);if (names != null && name.Length > 0){string[] emps = Regex.Split(prpts[name], "[,;]");AddEmployeesToRole(names[1], emps);}}}}/// <summary>////// </summary>/// <param name="role"></param>/// <param name="emps"></param>public void AddEmployeesToRole(string role, params string[] emps){// validationif (string.IsNullOrEmpty(role))return;if (emps == null || emps.Length == 0)return;// normalize usersIEnumerable<string> noNullEmps = extractNoNull(emps);if (noNullEmps == null || noNullEmps.Count() == 0)return;if (!persist.ContainsKey(role)){// initial first rolepersist.Add(role, new List<string>(noNullEmps));return;}// add users in roleaddNoDuplicateEmp(role, noNullEmps);}/// <summary>/// Return no null and after trim strings./// </summary>/// <param name="emps"></param>/// <returns></returns>private static IEnumerable<string> extractNoNull(string[] emps){IEnumerable<string> noNullUsers = emps.Where(x => !string.IsNullOrEmpty(x)).Select(x => x.Trim());return noNullUsers;}/// <summary>/// Add users in role/// </summary>/// <param name="role"></param>/// <param name="noNullEmps"></param>private void addNoDuplicateEmp(string role, IEnumerable<string> noNullEmps){List<string> employees = persist[role];IEnumerable<string> fulfillEmps = noNullEmps.Where(x => !employees.Contains(x));if (fulfillEmps == null || !fulfillEmps.Any())return;employees.AddRange(fulfillEmps);}/// <summary>/// Remove employees in role/// </summary>/// <param name="role"></param>/// <param name="emps"></param>public void RemoveEmployeesInRole(string role, params string[] emps){if (string.IsNullOrEmpty(role))return;if (emps == null || emps.Length == 0)return;if (!persist.ContainsKey(role))return;// Remove employees in role (clear and bulk-insert)List<string> employees = persist[role];IEnumerable<string> noNullEmps = extractNoNull(emps);IEnumerable<string> susurvivor = employees.Where(x => !noNullEmps.Contains(x));employees.Clear();if (susurvivor == null || !susurvivor.Any())return;employees.AddRange(susurvivor);}/// <summary>/// Remove role/// </summary>/// <param name="role"></param>public void RemoveRole(string role){if (string.IsNullOrEmpty(role))return;if (!persist.ContainsKey(role))return;// Clear values (employees)persist[role].Clear();// Remove key (role)persist.Remove(role);}public string[] GetAllRoles(){return persist.Keys.ToArray();}public string[] GetEmpsInRole(string role){if (string.IsNullOrEmpty(role))return new string[0];if(!persist.ContainsKey(role))return new string[0];return persist[role].ToArray();}class IgnoreCaseEquality : IEqualityComparer<string>{public bool Equals(string x, string y){if (x == null)return y == null;return x.Equals(y, StringComparison.OrdinalIgnoreCase);}public int GetHashCode(string obj){return obj.GetHashCode();}}public string[] GetRolesForUser(string emp){if (string.IsNullOrEmpty(emp))return new string[0];string tEmp = emp.Trim();List<string> roles = new List<string>();foreach (string role in persist.Keys){if (persist[role].Contains(tEmp,new IgnoreCaseEquality())){roles.Add(role);}}return roles.ToArray();}}
2.3 建立 Role Provider 實作 System.Web.Security.RoleProvider
public class MacroRoleProvider : System.Web.Security.RoleProvider{static MacroRolePersist persist = new MacroRolePersist();public override void AddUsersToRoles(string[] usernames, string[] roleNames){foreach (string role in roleNames){persist.AddEmployeesToRole(role, usernames);}}//// System.Web.Security.RoleProvider properties.//private string pApplicationName;public override string ApplicationName{get{return pApplicationName;}set{pApplicationName = value;}}//// System.Web.Security.RoleProvider properties.//private string pIniName;public string IniName{get{return pIniName;}set{pIniName = value;}}public override void Initialize(string name, System.Collections.Specialized.NameValueCollection config){base.Initialize(name, config);if (config["applicationName"] == null || config["applicationName"].Trim() == ""){pApplicationName = System.Web.Hosting.HostingEnvironment.ApplicationVirtualPath;}else{pApplicationName = config["applicationName"];}if (config["iniPath"] == null || config["iniPath"].Trim() == ""){pIniName = System.Web.Hosting.HostingEnvironment.ApplicationPhysicalPath + "/App_Data/MacroRole.ini";}else{pIniName = config["iniPath"];}persist.Load(pIniName);}public override void CreateRole(string roleName){persist.AddEmployeesToRole(roleName, null);}public override bool DeleteRole(string roleName, bool throwOnPopulatedRole){persist.RemoveRole(roleName);return true;}public override string[] FindUsersInRole(string roleName, string usernameToMatch){return GetUsersInRole(roleName).Where(x => x.IndexOf(usernameToMatch, StringComparison.OrdinalIgnoreCase) > -1).ToArray();}public override string[] GetAllRoles(){return persist.GetAllRoles();}public override string[] GetRolesForUser(string username){return persist.GetRolesForUser(username);}public override string[] GetUsersInRole(string roleName){return persist.GetEmpsInRole(roleName);}public override bool IsUserInRole(string username, string roleName){return GetUsersInRole(roleName).Contains(username);}public override void RemoveUsersFromRoles(string[] usernames, string[] roleNames){foreach (string role in roleNames){persist.RemoveEmployeesInRole(role, usernames);}}public override bool RoleExists(string roleName){return GetAllRoles().Any();}}
2.4 設定 web.config 的 roleManager section
<roleManagerdefaultProvider="MacroRoleProvider"enabled="true"cacheRolesInCookie="true"cookieName=".ROLES"cookieTimeout="30"cookiePath="/"cookieRequireSSL="false"cookieSlidingExpiration="true"cookieProtection="All" ><providers><clear /><add name="MacroRoleProvider" type="MacroRoleProvider"/></providers></roleManager>
2.5 設定 web.config 的 authorization section (含: location)
<location path="Index.aspx"><system.web><authorization><allow roles="BZ,ADM" /><deny users="*" /></authorization></system.web></location><system.web><authorization><deny users="?" /></authorization></system.web>
2.6 建立 AccessDenied.aspx 處理無權限, 並修改LoginPage.aspx 導頁至 AccessDenied.aspx
ASPX:您沒有權限執行此功能,請洽系統管理人員或<asp:LinkButton ID="login"runat="server" onclick="login_Click">重新登入</asp:LinkButton>。CS:protected void login_Click(object sender, EventArgs e){System.Web.Security.FormsAuthentication.SignOut();Response.Redirect("~/LoginPage.aspx");}---public partial class LoginPage : System.Web.UI.Page{protected void Page_Load(object sender, EventArgs e){if (User != null && User.Identity.IsAuthenticated){Response.Redirect("~/AccessDenied.aspx");}}
3. 內容
3.1 建立Web.sitemap
<?xml version="1.0" encoding="utf-8" ?><siteMap xmlns="http://schemas.microsoft.com/AspNet/SiteMap-File-1.0" ><siteMapNode url="/" title="管理後台" description="管理後台"><siteMapNode url="/ContentManagement.aspx" title="內容管理" description="內容管理" /><siteMapNode url="/SystemManagement.aspx" title="系統管理" description="系統管理" /></siteMapNode></siteMap>
3.2 設定 web.config 的 siteMap section
<siteMap defaultProvider="XmlSiteMapProvider" enabled="true"><providers><add name="XmlSiteMapProvider" type="System.Web.XmlSiteMapProvider" siteMapFile="Web.sitemap" securityTrimmingEnabled="true"/></providers></siteMap>
3.3 建立內容頁面
…