2013-08-23 5 views
2

Я создал роль поставщика роли для моего приложения MVC4, где я успешно смог переопределить методы CreateRole, GetAlRoles и RoleExists и связать их к моей существующей базе данных следующим образом:Переопределить User.IsInRole и [Authorize (Roles = "Admin")] для приложения MVC4

namespace Project.Providers 
{ 
    public class MyProvider : System.Web.Security.SqlRoleProvider 
    { 
    private MyContext dbcontext = new MyContext(System.Configuration.ConfigurationManager.ConnectionStrings["MyContext"].ConnectionString); 
    private Repository<MyUser> userRepository; 
    private Repository<Role> roleRepository; 

    public MyProvider() 
    { 
     this.userRepository = new Repository<MyUser>(dbcontext); 
     this.roleRepository = new Repository<Role>(dbcontext); 
    } 

    public override string[] GetAllRoles() 
    { 
     IEnumerable<Role> dbRoles = roleRepository.GetAll(); 
     int dbRolesCount = roleRepository.GetAll().Count(); 
     string[] roles = new string[dbRolesCount]; 
     int i = 0; 
     foreach(var role in dbRoles) 
     { 
      roles[i] = role.Name; 
      i++; 
     } 
     return roles; 
    } 

    public override bool RoleExists(string roleName) 
    { 
     string[] roles = { "Admin", "User", "Business" }; 
     if(roles.Contains(roleName)) 
      return true; 
     else 
      return false; 
    } 

    public override void CreateRole(string roleName) 
    { 
     Role newRole = new Role(); 
     newRole.Name = roleName; 
     roleRepository.Add(newRole); 
     roleRepository.SaveChanges(); 
    } 

    public override bool IsUserInRole(string userName, string roleName) 
    { 
     MyUser user = userRepository.Get(u => u.Username == userName).FirstOrDefault(); 
     Role role = roleRepository.Get(r => r.Name == roleName).FirstOrDefault(); 
     if (user.RoleID == role.RoleID) 
      return true; 
     else 
      return false; 
    } 
    } 
} 

Я не смог найти способ, чтобы переопределить

User.IsInRole(string roleName) 

что еще я должен сделать так, чтобы когда я использую:

[Authorize(Roles = "Admin")] 

Он будет основан на роли поставщика, которого я настроил, а не по умолчанию asp.

Мой класс пользователей теперь выглядит следующим образом:

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Text; 
using System.Threading.Tasks; 
using System.ComponentModel.DataAnnotations; 
using System.Collections; 
using System.Security.Principal; 

namespace Project.Data 
{ 
    public class MyUser : IPrincipal 
    { 
    [Key] 
    public int UserID { get; set; } 

    [StringLength(128)] 
    public string Username { get; set; }    

    .....other properties 

    public IIdentity Identity { get; set; } 

    public bool IsInRole(string role) 
    { 
     if (this.Role.Name == role) 
     { 
      return true; 
     } 
     return false; 
    } 

    public IIdentity Identity 
    { 
     get { throw new NotImplementedException(); } 
    } 
    } 
} 

Мой трассировки стека, кажется, следует более по адресу:

System.Web.Security.RolePrincipal.IsInRole(String role) 

Так что я пытался реализовать пользовательские RolePrincipal в той же манере I установить пользовательский поставщик какие-либо идеи, как я могу это сделать? Не уверен, какие параметры конструктора он принимает. Вот моя попытка:

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Web; 
using System.Configuration.Provider; 
using Project.Data; 
using System.Web.Security; 
using System.Security.Principal.IIdentity; 

namespace Project.Principal 
{ 
    public class MyPrincipal : System.Web.Security.RolePrincipal 
    { 
    private MyContext dbcontext = new MyContext(System.Configuration.ConfigurationManager.ConnectionStrings["MyContext"].ConnectionString); 
    private Repository<MyUser> userRepository; 
    private Repository<Role> roleRepository;   

    public MyPrincipal() 
    { 
     this.userRepository = new Repository<MyUser>(dbcontext); 
     this.roleRepository = new Repository<Role>(dbcontext); 
    } 

    public override bool IsInRole(string role) 
    { 
     //code to be added 
     return true; 
    } 
} 

}

+0

Ваш последний пример кода, расширяющий RolePrincipal, отходит от всего, что я сделал. – Matthew

ответ

2

перенастройка IsInRole в классе IPrincipal, шахта в EF выглядит следующим образом:

public class MyUser : IPrincipal { 
    //Properties 
    ... 
    public bool IsInRole(string role) { 
     if (Roles.Any(m=>m.NameKey.ToLower().Equals(role.ToLower()))) { 
      return true; 
     } 
     return false; 
    } 
} 

Затем, когда вы добавляете соответствующие разделы в вашем WebConfig для как RoleProvider, так и MembershipProvider, вы должны быть полезны для атрибута Authorize.

UPDATE в ответ на ваши комментарии

веб Config должна выглядеть следующим образом:

... 
<authentication mode="Forms"> 
    <forms loginUrl="~/Login" timeout="2880"></forms> 
</authentication> 
<authorization> 
</authorization> 

.. 

<membership defaultProvider="MyMembershipProvider"> 
    <providers> 
    <add name="MyMembershipProvider" type="MyApp.Infrastructure.MyMembershipProvider" connectionStringName="connectionstring" enablePasswordRetrieval="false" enablePasswordReset="true" requiresQuestionAndAnswer="false" requiresUniqueEmail="true" /> 
    </providers> 
</membership> 
<roleManager defaultProvider="MyRoleProvider" enabled="true" cacheRolesInCookie="true"> 
    <providers> 
    <clear /> 
    <add name="MyRoleProvider" type="MyApp.Infrastructure.MyRoleProvider" /> 
    </providers> 
</roleManager> 
... 

В поставщике, является пользователем вашего IPrincipal?

public MyUser User { get; private set; } 

Пользователь должен иметь и IIdentity

в MyUser.cs:

... 
    public virtual ICollection<Role> Roles { get; set; } 
    public IIdentity Identity { get; set; } 

Я не много дополнительных советов, чтобы помочь устранить из ваших комментариев.

UPDATE

Некоторые примеры я через и нашел полезным при установке шахты до: http://www.brianlegg.com/post/2011/05/09/Implementing-your-own-RoleProvider-and-MembershipProvider-in-MVC-3.aspx

http://www.mattwrock.com/post/2009/10/14/Implementing-custom-MembershipProvider-and-Role-Provider-for-Authinticating-ASPNET-MVC-Applications.aspx

http://blogs.msdn.com/b/rickandy/archive/2012/03/23/securing-your-asp-net-mvc-4-app-and-the-new-allowanonymous-attribute.aspx?Redirected=true

Я читал много других статей и SO сообщения на мой первый пробег, но это были вещи, которые я позаботился о закладке. Я применил подход к разрешению ролей/прав для авторизации, поэтому один из них настроен таким образом.

+0

Я пробовал вышеуказанное предложение, и я получаю следующую ошибку: «Project.Data.User» не реализует член интерфейса «System.Security.Principal.IPrincipal.Identity» – Jay

+0

Я реализовал интерфейс, нажав на конец IPrincipal и нажав ALT + SHIFT + F10. Теперь я получаю нестационарный метод, требующий целевой ошибки. – Jay

+0

. Моя трассировка стека, кажется, следует за: System.Web.Security.RolePrincipal.IsInRole (роль строки) Я попытался реализовать пользовательский RolePrincipal так же, как я установил пользовательский поставщик любые идеи, как я могу это сделать? Не уверен, какие параметры конструктора он принимает – Jay

7

Вам просто нужно переопределить метод GetRolesForUser в вашем пользовательском ролевом провайдере вместо более логичного IsUserInRole, потому что именно это вызвано реализацией по умолчанию, которая делает некоторое нежелательное кэширование.