简体   繁体   English

授权属性中的角色无法按预期在MVC 4中正常工作

[英]Roles in Authorize Attribute does not work as expected in MVC 4

(I am new to ASP.NET MVC 4 and prior to this project, I was used to working with WebForms with <authentication mode="none"> ). (我是ASP.NET MVC 4的新手,在此项目之前,我曾经使用过<authentication mode="none"> )来处理WebForms。

I have a database in which I have specific roles against a user entity like ADMIN and SUBADMIN . 我有一个数据库,在该数据库中,我对诸如ADMINSUBADMIN类的用户实体具有特定角色。 I have separate controllers in my project to deal with different views for the different roles for example, AdminController and SubAdminController I can successfully redirect users to the respective views according to their roles. 我在项目中有单独的控制器来处理不同角色的不同视图,例如AdminControllerSubAdminController我可以根据用户的角色将用户成功重定向到相应的视图。

My issue is that when the users have logged in they can even access pages which they are not privileged to access.This implies that may be I have not set up authorization properly. 我的问题是,当用户登录后,他们甚至可以访问他们无权访问的页面。这意味着我可能没有正确设置授权。

What I have tried? 我尝试了什么?

I have tried the authorized attribute with ADMIN role filter so that only admins are authorized to view the respective views like: 我已经尝试使用ADMIN角色过滤器来授权属性,以便仅管理员有权查看相应的视图,例如:

[Authorize(Roles="ADMIN")]
    public class AdminController : BaseController
    {
    ....
    }

This redirects the user even if he is successfully authenticated to the login page which is configured in web.config like this: 即使用户成功通过身份验证,也重定向到在web.config中配置的登录页面,如下所示:

 <authentication mode="Forms">
      <forms loginUrl="~/Home/Index" timeout="2880" />
    </authentication>

Note that if I just use [Authorize] instead then it works but even SubAdmin can gain access to the Admin views. 请注意,如果我只使用[Authorize] ,则可以使用,但是即使SubAdmin也可以访问Admin视图。

I have tried configuring the authorization in Web.config too like this: 我也尝试在Web.config中配置授权,如下所示:

<location path="Admin">
    <system.web>

      <authorization>
        <allow roles="ADMIN"/> 

        <deny users="*"/> 
      </authorization>

    </system.web>
  </location>

This has lead to same results as using [Authorize(Roles="ADMIN")] . 与使用[Authorize(Roles="ADMIN")]

Note that if I console out the following 请注意,如果我执行以下操作

User.Identity.ToGenericUserIdentity().RoleName; in my AdminController then I get ADMIN and i can use it in my action methods to re-check whether the user is actually an admin or sub admin but that is not the correct way to write it down as checks in all my action methods. 在我的AdminController我得到ADMIN ,然后可以在我的操作方法中使用它来重新检查用户实际上是管理员还是子管理员,但这不是将其写下来作为所有我的操作方法中检查的正确方法。

Related classes: 相关类别:

[Serializable]
    public class GenericUser
    {

        public bool IsInRole(string role) { return false; }



        public string RoleName { get; set; }
        public int UserID { get; set; }
        public string UserName { get; set; }
    }

    [Serializable]
    public class GenericUserIdentity : IIdentity
    {
        private GenericUser genericUser;
        private FormsAuthenticationTicket ticket;

        public GenericUserIdentity(FormsAuthenticationTicket ticket)
        {
            var serializer = new JsonSerializer();
            var reader = new JsonTextReader(new StringReader(ticket.UserData));
            genericUser = serializer.Deserialize<GenericUser>(reader);
            this.ticket = ticket;
        }

        public string AuthenticationType
        {
            get { return "Custom"; }
        }

        public bool IsAuthenticated
        {
            get { return ticket != null; }
        }

        public string Name
        {
            get { return genericUser.UserName; }
        }

        public string RoleName
        {
            get { return genericUser.RoleName; }
        }

        public int UserID
        {
            get { return genericUser.UserID; }
        }



    }

public static class IdentityExtension
{
    public static GenericUserIdentity ToGenericUserIdentity(this IIdentity identity)
    {
        var cookie = HttpContext.Current.Request.Cookies[FormsAuthentication.FormsCookieName];
        var ticketInfo = FormsAuthentication.Decrypt(cookie.Value);
        return new GenericUserIdentity(ticketInfo);
    }
}

And how do I authenticate? 我该如何认证?

In my HomeController which shows the login page on Index() action, I have set up a HttpPost Index action like this: 在显示了Index()操作登录页面的HomeController中,我设置了一个HttpPost Index操作,如下所示:

  public ActionResult Index()
        {
            return View();
        }
 [HttpPost]
        public ActionResult Index(string username,string password)
        {

            UserInformation userInfo = _userProvider.FindUserByName(username);

            OrderProvider orderProvider = new OrderProvider(new OrderRepository());

            if (userInfo != null && string.Equals(userInfo.Password, password,StringComparison.Ordinal))
            {
                if (userInfo.isEnabled)
                {
                    GenericUser genericUser = new GenericUser() { UserName = userInfo.Email, UserID = userInfo.UserID, RoleName = userInfo.RoleName };

                    Response.SetAuthCookie<GenericUser>(genericUser.UserName, genericUser);

                    if (userInfo.RoleName == "ADMIN")
                    {
                        return RedirectToAction("Index", "Admin");
                    }
                    else if (userInfo.RoleName == "USER")
                    {
                        return RedirectToAction("Index", "Customer");
                    }
                    else if (userInfo.RoleName == "DRIVER")
                    {
                        return RedirectToAction("Index", "Driver");
                    }
                    else if (userInfo.RoleName == "SUBADMIN")
                    {
                        return RedirectToAction("Index", "SubAdmin");
                    }
                }



            }

            ViewBag.Error = true;

            return View("Index");

        }

Edit 编辑

Finally overriding the AuthorizeCore method of my custom attribute worked for me. 最终,覆盖我的自定义属性的AuthorizeCore方法对我有用。

public enum Role
    {
        ADMIN, SUBADMIN, USER, DRIVER
    }

    [AttributeUsage(AttributeTargets.Method | AttributeTargets.Class, Inherited = true, AllowMultiple = true)]
    public class AuthorizeUser : AuthorizeAttribute
    {
        public AuthorizeUser(params object[] roles)
        {
            if (roles.Any(r => r.GetType().BaseType != typeof(Enum)))
                throw new ArgumentException("roles");

            this.Roles = string.Join(",", roles.Select(r => Enum.GetName(r.GetType(), r)));
        }



protected override bool AuthorizeCore(HttpContextBase httpContext)
        {
            var cookie = HttpContext.Current.Request.Cookies[FormsAuthentication.FormsCookieName];
            var ticketInfo = FormsAuthentication.Decrypt(cookie.Value);

            GenericUserIdentity iden = new GenericUserIdentity(ticketInfo);
            if (Roles.Contains(iden.RoleName))
                return true;
            else
                return false;
        }
        }

The attribute [Authorize(Roles="ADMIN")] only works for the built-in Roles. 属性[Authorize(Roles="ADMIN")]仅适用于内置角色。
You have your own GenericUser.RoleName , that won't be used here. 您有自己的GenericUser.RoleName ,此处将不再使用。

You could write your own MyAuthorize attribute but first ask yourself very seriously why you are re-inventing the wheel here. 您可以编写自己的MyAuthorize属性,但首先要非常MyAuthorize自己,为什么要在这里重新发明轮子。 The Identity and Membership frameworks are available and tested. 身份和成员资格框架可用并经过测试。 When I see a string.Equals(userInfo.Password, password) I very much doubt the security of your implementation. 当我看到一个string.Equals(userInfo.Password, password)我非常怀疑您的实现的安全性。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM