回答

115

我已經創建了一個包含自定義的成員提供一個新的項目,並從MembershipProvider抽象類重寫了ValidateUser方法:

public class MyMembershipProvider : MembershipProvider 
{ 
    public override bool ValidateUser(string username, string password) 
    {  
     // this is where you should validate your user credentials against your database. 
     // I've made an extra class so i can send more parameters 
     // (in this case it's the CurrentTerritoryID parameter which I used as 
     // one of the MyMembershipProvider class properties). 

     var oUserProvider = new MyUserProvider(); 
     return oUserProvider.ValidateUser(username,password,CurrentTerritoryID); 
    } 
} 

然後我連接的是提供給我的ASP.NET MVC 2項目通過添加引用並指出它從我的web.config:

<membership defaultProvider="MyMembershipProvider"> 
    <providers> 
     <clear /> 
     <add name="MyMembershipProvider" 
      applicationName="MyApp" 
      Description="My Membership Provider" 
      passwordFormat="Clear" 
      connectionStringName="MyMembershipConnection" 
      type="MyApp.MyMembershipProvider" /> 
    </providers> 
</membership> 

我需要創建一個繼承RoleProvider抽象類和覆蓋會見了GetRolesForUser自定義類HOD。 ASP.NET MVC授權使用該方法找出哪些角色分配給當前登錄用戶,並確保允許用戶訪問控制器操作。

下面是步驟,我們需要採取:

1)創建一個繼承RoleProvider抽象類和覆蓋GetRolesForUser方法的自定義類:

public override string[] GetRolesForUser(string username) 
{ 
    SpHelper db = new SpHelper(); 
    DataTable roleNames = null; 
    try 
    { 
     // get roles for this user from DB... 

     roleNames = db.ExecuteDataset(ConnectionManager.ConStr, 
        "sp_GetUserRoles", 
        new MySqlParameter("_userName", username)).Tables[0]; 
    } 
    catch (Exception ex) 
    { 
     throw ex; 
    } 
    string[] roles = new string[roleNames.Rows.Count]; 
    int counter = 0; 
    foreach (DataRow row in roleNames.Rows) 
    { 
     roles[counter] = row["Role_Name"].ToString(); 
     counter++; 
    } 
    return roles; 
} 

2)將隨角色提供ASP.NET MVC通過我們的web.config 2應用:有用控制器/操作上述

<system.web> 
... 

<roleManager enabled="true" defaultProvider="MyRoleProvider"> 
    <providers> 
     <clear /> 
     <add name="MyRoleProvider" 
      applicationName="MyApp" 
      type="MyApp.MyRoleProvider" 
      connectionStringName="MyMembershipConnection" /> 
    </providers> 
</roleManager> 

... 
</system.web> 

3)設置授權(角色= 「XXX,YYY」):

[Authorization(Roles = "Customer Manager,Content Editor")] 
public class MyController : Controller 
{ 
    ...... 
} 

就是這樣!現在它工作了!

4)可選:設置自定義Authorize屬性,這樣就可以重定向不需要的角色的存取遭拒頁:

[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, Inherited = true, AllowMultiple = false)] 
public class MyAuthorizationAttribute : AuthorizeAttribute 
{ 
    /// <summary> 
    /// The name of the master page or view to use when rendering the view on authorization failure. Default 
    /// is null, indicating to use the master page of the specified view. 
    /// </summary> 
    public virtual string MasterName { get; set; } 

    /// <summary> 
    /// The name of the view to render on authorization failure. Default is "Error". 
    /// </summary> 
    public virtual string ViewName { get; set; } 

    public MyAuthorizationAttribute() 
     : base() 
    { 
     this.ViewName = "Error"; 
    } 

    protected void CacheValidateHandler(HttpContext context, object data, ref HttpValidationStatus validationStatus) 
    { 
     validationStatus = OnCacheAuthorization(new HttpContextWrapper(context)); 
    } 

    public override void OnAuthorization(AuthorizationContext filterContext) 
    { 
     if (filterContext == null) 
     { 
      throw new ArgumentNullException("filterContext"); 
     } 

     if (AuthorizeCore(filterContext.HttpContext)) 
     { 
      SetCachePolicy(filterContext); 
     } 
     else if (!filterContext.HttpContext.User.Identity.IsAuthenticated) 
     { 
      // auth failed, redirect to login page 
      filterContext.Result = new HttpUnauthorizedResult(); 
     } 
     else if (filterContext.HttpContext.User.IsInRole("SuperUser")) 
     { 
      // is authenticated and is in the SuperUser role 
      SetCachePolicy(filterContext); 
     } 
     else 
     { 
      ViewDataDictionary viewData = new ViewDataDictionary(); 
      viewData.Add("Message", "You do not have sufficient privileges for this operation."); 
      filterContext.Result = new ViewResult { MasterName = this.MasterName, ViewName = this.ViewName, ViewData = viewData }; 
     } 
    } 

    protected void SetCachePolicy(AuthorizationContext filterContext) 
    { 
     // ** IMPORTANT ** 
     // Since we're performing authorization at the action level, the authorization code runs 
     // after the output caching module. In the worst case this could allow an authorized user 
     // to cause the page to be cached, then an unauthorized user would later be served the 
     // cached page. We work around this by telling proxies not to cache the sensitive page, 
     // then we hook our custom authorization code into the caching mechanism so that we have 
     // the final say on whether a page should be served from the cache. 
     HttpCachePolicyBase cachePolicy = filterContext.HttpContext.Response.Cache; 
     cachePolicy.SetProxyMaxAge(new TimeSpan(0)); 
     cachePolicy.AddValidationCallback(CacheValidateHandler, null /* data */); 
    } 
} 

現在我們可以用我們自己的製造屬性爲我們的用戶重定向到訪問拒絕觀點:

[MyAuthorization(Roles = "Portal Manager,Content Editor", ViewName = "AccessDenied")] 
public class DropboxController : Controller 
{ 
    ....... 
} 

就是這樣! 超級騙子!

下面是一些我使用來獲取所有這些信息的鏈接:

自定義角色提供: http://davidhayden.com/blog/dave/archive/2007/10/17/CreateCustomRoleProviderASPNETRolePermissionsSecurity.aspx

我希望這個信息幫助!

+0

你已經解釋這是令人震驚的方式!我敢打賭,你甚至都沒有努力嘗試......你應該考慮寫博客文章:)。 – 2010-05-06 13:44:55

+0

你已經解釋過這是轟動的方式!我敢打賭,你甚至都沒有努力嘗試......你應該考慮寫博客文章:)。感謝夥計 – 2010-05-06 13:46:22

+2

,很高興它有幫助。我發現自己經常這樣做,通過做我自己更好地理解它:-) – danfromisrael 2010-05-06 19:42:07

1

我用NauckIt.PostgreSQL提供商的源代碼爲基礎,並修改它適合我的需要。

8

它也可以使用這個少得多的代碼量,我不完全確定,如果這種方法是安全的,但對任何你使用的數據庫工作得很好。

在全球範圍內。ASAX

protected void Application_AuthenticateRequest(object sender, EventArgs e) 
    { 
     if (HttpContext.Current.User != null) 
     { 
      if (HttpContext.Current.User.Identity.IsAuthenticated) 
      { 
       if (HttpContext.Current.User.Identity is FormsIdentity) 
       { 
        FormsIdentity id = 
         (FormsIdentity)HttpContext.Current.User.Identity; 
        FormsAuthenticationTicket ticket = id.Ticket; 

        // Get the stored user-data, in this case, our roles 
        string userData = ticket.UserData; 
        string[] roles = userData.Split(','); 
        HttpContext.Current.User = new GenericPrincipal(id, roles); 
       } 
      } 
     } 
    } 

這是什麼一樣的是,它讀取來自authCookie這是從的FormsAuthenticationTicket

製成,登錄邏輯是這樣的

public class dbService 
{ 
    private databaseDataContext db = new databaseDataContext(); 

    public IQueryable<vwPostsInfo> AllPostsAndDetails() 
    { 
     return db.vwPostsInfos; 
    } 

    public IQueryable<role> GetUserRoles(int userID) 
    { 
     return (from r in db.roles 
        join ur in db.UsersRoles on r.rolesID equals ur.rolesID 
        where ur.userID == userID 
        select r); 
    } 

    public IEnumerable<user> GetUserId(string userName) 
    { 
     return db.users.Where(u => u.username.ToLower() == userName.ToLower()); 
    } 

    public bool logOn(string username, string password) 
    { 
     try 
     { 
      var userID = GetUserId(username); 
      var rolesIQueryable = GetUserRoles(Convert.ToInt32(userID.Select(x => x.userID).Single())); 
      string roles = ""; 
      foreach (var role in rolesIQueryable) 
      { 
       roles += role.rolesName + ","; 
      } 

      roles.Substring(0, roles.Length - 2); 
      FormsAuthenticationTicket ticket = new FormsAuthenticationTicket(
         1, // Ticket version 
         username, // Username associated with ticket 
         DateTime.Now, // Date/time issued 
         DateTime.Now.AddMinutes(30), // Date/time to expire 
         true, // "true" for a persistent user cookie 
         roles, // User-data, in this case the roles 
         FormsAuthentication.FormsCookiePath);// Path cookie valid for 

      // Encrypt the cookie using the machine key for secure transport 
      string hash = FormsAuthentication.Encrypt(ticket); 
      HttpCookie cookie = new HttpCookie(
       FormsAuthentication.FormsCookieName, // Name of auth cookie 
       hash); // Hashed ticket 

      // Set the cookie's expiration time to the tickets expiration time 
      if (ticket.IsPersistent) cookie.Expires = ticket.Expiration; 

      // Add the cookie to the list for outgoing response 
      HttpContext.Current.Response.Cookies.Add(cookie); 

      return true; 
     } 
     catch 
     { 
      return (false); 
     } 
    } 
} 

我的角色存儲在我的數據庫中的角色有兩個表:表:具有列:roleID和roleName以及表的角色:UsersRoles具有列:userID和roleID,這使得多個用戶可以有多個角色,並且可以很容易地創建自己的邏輯來添加/從用戶中刪除角色等等。這使您可以使用[授權(角色=「超級管理員」)]例如。希望這可以幫助。

編輯:忘了做密碼檢查,但你只是如果在檢查登錄方法添加的,如果用戶名和密碼提供了檢查,如果沒有返回false

+0

等待,因此您將角色名稱存儲在auth cookie中?這是不是意味着用戶可以將他們想要的任何角色放入auth cookie中?我想這不重要,因爲他們必須解密cookie。 – Pandincus 2011-02-26 21:02:17

+0

@Pandincus:是的,如果用戶設法解密cookie,那麼這就是使用這種方法的缺點之一,那麼可以做的是進一步加密角色並提供一個公共密鑰和cookie一起用於以後在全球解密的.asax。這並不完美,但它完成了工作,並沒有那麼複雜。 – Joakim 2011-02-28 09:57:17

相關問題