Override the User.IsInRole and [Authorize(Roles = “Admin”)] for MVC4 application

此生再无相见时 提交于 2019-11-30 10:27:56

You just need to override method GetRolesForUser in your custom role provider, instead of the more logical IsUserInRole, because that is what is called by the default implementation that does some unwanted caching.

You override IsInRole in your IPrincipal class, mine in EF looks like this:

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

Then once you add the appropriate sections to your webconfig for both RoleProvider and MembershipProvider you should be good for Authorize attribute.

UPDATE in response to your comments

web Config should look like:

...
<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>
...

In the provider, is the User your IPrincipal?

public MyUser User { get; private set; }

User should have and IIdentity

in MyUser.cs:

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

I don't have much additional advice to help troubleshoot from your comments.

UPDATE

Some examples I have been through and found helpful when setting mine up: 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

I read many other articles and SO posts on my first run through, but these were things I bothered to bookmark. I took a roles/rights approach to authorization, which is why one of them is geared that way.

To fix this, you need to do 4 updates to your application.

    1. Create a class that extends RoleProvider.

    namespace MyApp
    {


     public class MyRoleProvider : RoleProvider
        {
            public override string ApplicationName
            {
                get
                {
                    throw new NotImplementedException();
                }

                set
                {
                    throw new NotImplementedException();
                }
            }

            public override void AddUsersToRoles(string[] usernames, string[] roleNames)
            {
                throw new NotImplementedException();
            }

            public override void CreateRole(string roleName)
            {
                throw new NotImplementedException();
            }

            public override bool DeleteRole(string roleName, bool throwOnPopulatedRole)
            {
                throw new NotImplementedException();
            }

            public override string[] FindUsersInRole(string roleName, string usernameToMatch)
            {
                throw new NotImplementedException();
            }

            public override string[] GetAllRoles()
            {
                throw new NotImplementedException();
            }

            public override string[] GetRolesForUser(string username)
            {
                using (ApplicationDbContext db = new ApplicationDbContext())
                {
                        // get user roles here using user name.

                }
            }



            public override string[] GetUsersInRole(string roleName)
            {
                throw new NotImplementedException();
            }

            public override bool IsUserInRole(string username, string roleName)
            {

                return GetRolesForUser(username).Contains(roleName);

            }

            public override void RemoveUsersFromRoles(string[] usernames, string[] roleNames)
            {
                throw new NotImplementedException();
            }

            public override bool RoleExists(string roleName)
            {
                throw new NotImplementedException();
            }
        }

}

    2. Create a custom filter that extends AuthorizeAttribute and overwrite its methods.

      public class MyAuthFilter : AuthorizeAttribute
    {


        public override void OnAuthorization(AuthorizationContext filterContext)
        {
            base.OnAuthorization(filterContext);
       }


        protected override void HandleUnauthorizedRequest(AuthorizationContext filterContext)
        {
            var routeValues = new RouteValueDictionary(new
            {
                controller = "Account",
                action = "Login",


            });

             filterContext.Result = new RedirectToRouteResult(routeValues);

            base.HandleUnauthorizedRequest(filterContext);
        }

        protected override bool AuthorizeCore(HttpContextBase httpContext)
        {
            string[] roles = Roles.Split(',');

            string userName = HttpContext.Current.User.Identity.Name;

            MyRoleProvider myProvider = new MyRoleProvider();


            foreach (string role in roles)
            {
                bool success = myProvider.IsUserInRole(userName, role);

                if (success == true)
                {
                    return true;
                }

            }

            return false;
        }

    3. Configure your custom role provider in your web.config.
      <system.web>
        <roleManager defaultProvider="MyRoleProvider" enabled="true" cacheRolesInCookie="true">
          <providers>
            <clear />
            <add name="MyRoleProvider" type="MyApp.MyRoleProvider" />
          </providers>
        </roleManager>
      </system.web>

      Note: The type here uses the fully qualified namespace and your class name = MyApp.MyRoleProvider. Yours can be different

    4. Use your custom filter instead of the default Authorize attribute for your controllers and actions. E.g 

    [MyAuthFilter]
    public class HomeController : Controller
    {
        public ActionResult Index()
        {
            ViewBag.Title = "Home Page";

            return View();
        }
    }
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!