0

나는 사용자 지정 역할 제공자와 MVC 5 응용 프로그램을 개발하고 위해 AuthorizeAttribute와 문제를 가지고 있지만, AuthorizeAttribute 결코 내 고객 역할 공급자를 호출하지 것 같다, 내 코드는 다음과 같습니다 :사용자 지정 역할 공급자 MVC

내 고객 제공 :

namespace MyDomain 
{ 
    public class CustomRoleProvider : RoleProvider 
    { 
     public override string[] GetRolesForUser(string username) 
     { 
      using (MyContext objContext = new MyContext()) 
      { 
       var objUser = objContext.Users.FirstOrDefault(x => x.Username == username); 
       if (objUser == null) 
       { 
        return null; 
       } 
       else 
       { 
        string[] ret = { objUser.Access_Levels.Name }; 
        return ret; 
       } 
      } 
     } 

     public override bool IsUserInRole(string username, string roleName) 
     { 
      var userRoles = GetRolesForUser(username); 
      return userRoles.Contains(roleName); 
     } 
} 

내 컨트롤러 :

[Authorize(Roles = "Administrator")] 
public class AdminController : Controller 

그리고있는 Web.Config :

<system.web> 
    <roleManager defaultProvider="CustomRoleProvider" enabled="true" > 
     <providers> 
     <clear /> 
     <add name="CustomRoleProvider" type="Online_Storage_Portal.CustomRoleProvider" cacheTimeoutInMinutes="30"/> 
     </providers> 
    </roleManager> 
    </system.web> 

이 또한 내 사용자 지정 역할 공급자, 나는 내 컨트롤러 내에서

문자열 []의 역할을 다음 코드로 내 사용자 지정 역할 공급자 메서드를 호출 할 수 있어요 내 다른 컨트롤러와 같은 프로젝트에 = Roles.GetRolesForUser (사용자 이름)

하지만 [Authorize (Roles = "Administrator")]가있는 컨트롤러는 사용자 로그인과 역할이 모두 평가 된 경우에도 페이지를 로그인 화면으로 항상 리디렉션합니다.

도와주세요 !!

답변

2

나는 당신의 문제의 근원을 발견했다고 생각합니다. Windows 인증을 사용 중이며 자동으로로드되는 Windows 그룹 대신 사용자 지정 역할 공급자를 사용하려고한다고 가정합니다. MVC AuthorizeAttribute 소스를 살펴보면 실제로 Principal.IsInRole을 호출하고 있음을 알 수 있습니다. MSDN에서

InRole은 먼저 IsRoleListCached 속성을 검사하여 현재 사용자의 캐시 된 역할 이름 목록을 사용할 수 있는지 여부를 확인합니다. IsRoleListCached 속성이 true이면 캐시 된 목록의 지정된 역할이 검사됩니다. IsInRole 메서드가 캐시 된 목록에서 지정된 역할을 찾으면 true를 반환합니다. IsInRole에서 지정된 역할을 찾지 못하면 기본 Provider 인스턴스의 GetRolesForUser 메서드를 호출하여 사용자 이름이 구성된 ApplicationName 값의 데이터 원본에있는 역할과 연결되어 있는지 여부를 확인합니다.

그래서 저는 Principal이 Windows Principal이기 때문에 역할이 채워지고 캐싱된다는 사실을 알고 있습니다. 에서 IsInRole가 호출 될 때, 이봐, 난 이미 그들을 다시 얻을 내가 공급자에게 돌아갈 이유, 역할을 가지고있다 '라고 "

이 같은 뭔가를해야만 될 것 대신에 무엇을 할 수 있는지?

protected void Application_PostAuthenticateRequest(object sender, EventArgs e) 
    { 
     WindowsIdentity identity = HttpContext.Current.Request.LogonUserIdentity; 
     HttpContext.Current.User = new System.Security.Principal.GenericPrincipal(new GenericIdentity(identity.Name), Roles.GetRolesForUser()); 
    } 

이것은 HttpContext에서 Windows ID를 가져오고, 이름을 사용하여 사용자 정의 공급자에서 명시 적으로 역할을 가져오고 대신 요청에서 새 GenericPrincipal을 때 리도록합니다. 추가로 가서 역할을 저장하여 암호화 된 쿠키이므로 각 요청에 대해 역할 제공 업체로 갈 필요가 없습니다.

void Application_PostAuthenticateRequest() 
    { 
     HttpCookie authCookie = Context.Request.Cookies[FormsAuthentication.FormsCookieName]; 
     FormsAuthenticationTicket authTicket; 
     if (authCookie == null || authCookie.Value == "") 
     { 
      string[] getRoles = Roles.GetRolesForUser(); 
      authTicket = new FormsAuthenticationTicket(1, 
       User.Identity.Name, 
       DateTime.Now, 
       DateTime.Now.AddMinutes(20), 
       true, 
       String.Join(";", getRoles)); 

      string encryptedTicket = FormsAuthentication.Encrypt(authTicket); 
      authCookie = new HttpCookie(FormsAuthentication.FormsCookieName, encryptedTicket); 
      HttpContext.Current.Response.Cookies.Add(authCookie); 
     } 
     try 
     { 
      authTicket = FormsAuthentication.Decrypt(authCookie.Value); 
     } 
     catch 
     { 
      return; 
     } 
     string[] roles = authTicket.UserData.Split(';'); 
     if (Context.User != null) 
      Context.User = new System.Security.Principal.GenericPrincipal(Context.User.Identity, roles); 
    } 
+0

Dan에 대한 귀하의 의견을 보내 주셔서 감사합니다. 추가 기능을 제공하기 위해 WindowsPrincipal IsInRole 메서드를 재정의 한 CustomerPrincipal을 사용하는 것을 제외하고는 동일한 작업을 수행 할 수있었습니다. https://dotnetfiddle.net/sTU8EQ –

+0

여기와 같습니다. 댄, 너는 남자 야. 게시물 인증, WindowsPrincipal 래핑 개념 또는 기본 impl이 캐시 된 역할만을 사용한다는 개념을 알지 못했습니다. – Visser

관련 문제