Пользователь в роли "admin", но [Authorize (Roles = "admin")] не пройдет аутентификацию - PullRequest
10 голосов
/ 15 марта 2011

Я нашел отличный ответ на SO, описывающий , как настроить пользовательские роли пользователя , и я сделал то же самое в своем проекте. Так что в моем сервисе входа в систему у меня есть:

public ActionResult Login() {
  // password authentication stuff omitted here
  var roles = GetRoles(user.Type); // returns a string e.g. "admin,user"
  var authTicket = new FormsAuthenticationTicket(
                    1,
                    userName,
                    DateTime.Now,
                    DateTime.Now.AddMinutes(20), // expiry
                    false,
                    roles,
                    "/");
  var cookie = new HttpCookie(FormsAuthentication.FormsCookieName, 
    FormsAuthentication.Encrypt(authTicket));
  Response.Cookies.Add(cookie);
  return new XmlResult(xmlDoc); // don't worry so much about this - returns XML as ActionResult
}

А в Global.asax.cs у меня есть (дословно скопировано из другого ответа):

protected void Application_AuthenticateRequest(Object sender, EventArgs e) {
  var authCookie = Context.Request.Cookies[FormsAuthentication.FormsCookieName];
  if (authCookie != null) {
    var authTicket = FormsAuthentication.Decrypt(authCookie.Value);
    var roles = authTicket.UserData.Split(new Char[] { ',' });
    var userPrincipal = new GenericPrincipal(new GenericIdentity(authTicket.Name), roles);
    Context.User = userPrincipal;
  }
}

Тогда в моем классе ServicesController у меня есть:

[Authorize(Roles = "admin")]
//[Authorize]
public ActionResult DoAdminStuff() {
  ...
}

Я захожу как пользователь с ролью "admin", и это работает. Затем я вызываю / services / doadminstuff - и мне отказывают в доступе, хотя, когда я ставлю точку останова в Global.asax.cs, я вижу, что мои роли включают «admin». Если я закомментирую первый атрибут Authorize (с ролями) и просто использую простой ваниль Authorize, я получу доступ к сервису.

Я, должно быть, здесь упускаю что-то критическое - но с чего начать?

Ответы [ 2 ]

17 голосов
/ 15 марта 2011

Я бы порекомендовал вам использовать пользовательский атрибут авторизации вместо Application_AuthenticateRequest:

[AttributeUsage(AttributeTargets.Method | AttributeTargets.Class, Inherited = true, AllowMultiple = true)]
public class CustomAuthorizeAttribute : AuthorizeAttribute
{
    public override void OnAuthorization(AuthorizationContext filterContext)
    {
        string cookieName = FormsAuthentication.FormsCookieName;

        if (!filterContext.HttpContext.User.Identity.IsAuthenticated ||
            filterContext.HttpContext.Request.Cookies == null ||
            filterContext.HttpContext.Request.Cookies[cookieName] == null
        )
        {
            HandleUnauthorizedRequest(filterContext);
            return;
        }

        var authCookie = filterContext.HttpContext.Request.Cookies[cookieName];
        var authTicket = FormsAuthentication.Decrypt(authCookie.Value);
        string[] roles = authTicket.UserData.Split(',');

        var userIdentity = new GenericIdentity(authTicket.Name);
        var userPrincipal = new GenericPrincipal(userIdentity, roles);

        filterContext.HttpContext.User = userPrincipal;
        base.OnAuthorization(filterContext);
    }
}

и затем:

[CustomAuthorize(Roles = "admin")]
public ActionResult DoAdminStuff() 
{
    ...
}

Также очень важно убедиться, что при входе в систему создается файл cookie для аутентификации, поскольку вы возвращаете файл XML. Используйте FireBug, чтобы проверить, правильно ли отправляется куки-файл аутентификации при попытке доступа к URL /services/doadminstuff.

.
1 голос
/ 27 марта 2015

Я бы сначала поменял главное назначение:

Thread.CurrentPrincipal = userPrincipal;
if (HttpContext.Current != null)
{
    HttpContext.Current.User = userPrincipal;
}

в качестве документации ASP.NET.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...