Атрибут авторизации не работает с приложением проверки подлинности Windows

У меня есть приложение MVC4, в котором я назначил роли своему пользователю с помощью настраиваемого поставщика ролей, чтобы, когда я проверяю User.IsInRole на свою таблицу User, он определяет, какие ссылки и т. Д. Отображать на экране на моей странице _Layout.cshtml. Это работает на странице макета, поскольку отображаются правильные ссылки.

Однако, когда я защищаю свой контроллер администратора с помощью

[Authorize(Roles = "Admin")]

Я получаю следующую трассировку стека от объекта, для которого не установлен экземпляр ошибки объекта:

[NullReferenceException: Object reference not set to an instance of an object.]
System.Web.Mvc.AuthorizeAttribute.AuthorizeCore(HttpContextBase httpContext) +39
System.Web.Mvc.AuthorizeAttribute.OnAuthorization(AuthorizationContext filterContext) +159
System.Web.Mvc.ControllerActionInvoker.InvokeAuthorizationFilters(ControllerContext controllerContext, IList`1 filters, ActionDescriptor actionDescriptor) +96
System.Web.Mvc.Async.<>c__DisplayClass25.<BeginInvokeAction>b__1e(AsyncCallback asyncCallback, Object asyncState) +446
System.Web.Mvc.Async.WrappedAsyncResult`1.Begin(AsyncCallback callback, Object state, Int32 timeout) +130
System.Web.Mvc.Async.AsyncControllerActionInvoker.BeginInvokeAction(ControllerContext controllerContext, String actionName, AsyncCallback callback, Object state) +302
System.Web.Mvc.<>c__DisplayClass1d.<BeginExecuteCore>b__17(AsyncCallback asyncCallback, Object asyncState) +30
System.Web.Mvc.Async.WrappedAsyncResult`1.Begin(AsyncCallback callback, Object state, Int32 timeout) +130
System.Web.Mvc.Controller.BeginExecuteCore(AsyncCallback callback, Object state) +382
System.Web.Mvc.Async.WrappedAsyncResult`1.Begin(AsyncCallback callback, Object state, Int32 timeout) +130
System.Web.Mvc.Controller.BeginExecute(RequestContext requestContext, AsyncCallback callback, Object state) +317
System.Web.Mvc.Controller.System.Web.Mvc.Async.IAsyncController.BeginExecute(RequestContext requestContext, AsyncCallback callback, Object state) +15
System.Web.Mvc.<>c__DisplayClass8.<BeginProcessRequest>b__2(AsyncCallback asyncCallback, Object asyncState) +71
System.Web.Mvc.Async.WrappedAsyncResult`1.Begin(AsyncCallback callback, Object state, Int32 timeout) +130
System.Web.Mvc.MvcHandler.BeginProcessRequest(HttpContextBase httpContext, AsyncCallback callback, Object state) +249
System.Web.Mvc.MvcHandler.BeginProcessRequest(HttpContext httpContext, AsyncCallback callback, Object state) +50
System.Web.Mvc.MvcHandler.System.Web.IHttpAsyncHandler.BeginProcessRequest(HttpContext context, AsyncCallback cb, Object extraData) +16
System.Web.CallHandlerExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute() +301
System.Web.HttpApplication.ExecuteStep(IExecutionStep step, Boolean& completedSynchronously) +155

Что именно находится в этом контексте фильтра? Это работает без какой-либо дополнительной настройки, когда я использую проверку подлинности на основе ADFS или форм, но при использовании проверки подлинности на основе Windows мне пришлось сделать следующее, чтобы метод IsInRole заработал:

this.UserName = System.Security.Principal.WindowsIdentity.GetCurrent().Name;

if (this.UserName.Contains("\\"))
{
  string[] stringArray = this.UserName.Split(new Char[] { '\\' });
  this.UserName = stringArray[1];

  MyUser identity = userRepository.Get(u => u.Username == this.UserName).FirstOrDefault();
  HttpContext.Current.User = identity;
}

Нужно ли мне правильно настраивать какой-либо другой HttpContext, чтобы атрибут Authorize работал так же, как метод IsInRole?


person Jay    schedule 29.11.2013    source источник
comment
Кто-нибудь может мне с этим помочь? Баунти в 50 баллов теперь доступна, спасибо   -  person Jay    schedule 04.12.2013
comment
Можете ли вы установить точку останова непосредственно перед тем, как получите this.UserName? Я предполагаю, что GetCurrent () возвращает ноль. FilterContext предоставит вам все необходимое для написания фильтра, который будет включать httpcontext и словарь маршрутов. Взгляните на msdn.microsoft.com/en -us / library / dd381609 (v = vs.100) .aspx для разных контекстов фильтра.   -  person Jun Wei Lee    schedule 04.12.2013
comment
GetCurrent возвращает имя пользователя, и я могу правильно получить имя пользователя, однако из этого контекст авторизации и текущий контекст пользователя не устанавливаются, как это делается в ADFS и формах, все, что требовалось, - это получить имя пользователя, которое я могу делать здесь, я думаю, я пропустил шаг   -  person Jay    schedule 04.12.2013


Ответы (1)


В случае с формами это может быть что угодно, но очень распространено реализовать форму имени пользователя и пароля с поиском по имени пользователя в таблице пользователей, на основе представленного кода похоже, что репозиторий ожидает только имя пользователя, просто оказывается, что windows.identity.name возвращает домен \ пользователя. Вот тут-то и нужно приложить дополнительные усилия для разделения на домен, пользователь. пример ниже:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;

namespace MvcApplication6
{
    public class DemoAuthAttribute : AuthorizeAttribute
    {
        // create a file like auth.cs in the mvc project 
        // called 
        //    [DemoAuth("BAR")]
        // as an attibute on a controller method

    private string _role;

    public DemoAuthAttribute(string role)
    {
        _role = role; // should be exapanded to handle more than one
    }

    protected override bool AuthorizeCore(HttpContextBase httpContext)
    {
        return httpContext.Request.IsAuthenticated &&  _role == "FOO";
        // lookup the current user in database does the user have role as specificed by the attribute?
        // if yes sucess if not fail.
    }
    public override void OnAuthorization(AuthorizationContext filterContext)
    {
        if (filterContext == null)
        {
            throw new ArgumentNullException("filterContext");
        }

        if (AuthorizeCore(filterContext.HttpContext))
        {
            // your custom logic here
            string text = string.Format("<u><h5>Auth successfull.....</h5></u></br>");
            filterContext.HttpContext.Response.Write(text);
        }
        else
        {
            // RedirectResult, etc.
            string text = string.Format("<u><h5>Auth unsuccessfull.....</h5></u></br>");
            filterContext.HttpContext.Response.Write(text);
        }
    }

}

}

person Mike Beeler    schedule 04.12.2013
comment
Я получил только имя пользователя и разделил часть домена, чтобы получить только имя пользователя, и это работает для метода .IsInRole, но не для метода авторизации. Я думаю, что это связано с тем, что контекст авторизации не настроен, и мне интересно, как я могу это сделать, чтобы текущий пользователь был связан с поставщиком настраиваемой роли таким же образом, как при аутентификации через ADFS и формы. - person Jay; 04.12.2013
comment
хорошо я понял. это пользовательский провайдер, который вы написали, или сторонний поставщик / с открытым исходным кодом? - person Mike Beeler; 04.12.2013
comment
Это тот, который я написал, работает для пользователей, прошедших аутентификацию ADFS и Forms. Я просто не уверен, как получить контекст авторизации для пользователя в зависимости от того, как я устанавливаю HttpContext.Current.User, который хорошо работает для User.IsInRole - person Jay; 04.12.2013
comment
С помощью форм и аутентификации ADFS данные пользователя вводятся на страницу входа, а затем эти данные аутентифицируются для существующего пользователя в базе данных в таблице MyUser. У этого пользователя есть идентификатор роли, связанный с ролью, содержащейся в таблице под названием Роль, которая используется для моего поставщика ролей. Мне нужно проверить, найден ли пользователь в базе данных, а затем выполнить какую-то аутентификацию, чтобы им был назначен контекст безопасности, в котором их роль можно проверить с помощью [Authorize (Roles = blah, blah, blah) - person Jay; 04.12.2013
comment
Вам необходимо переопределить авторизованное ядро, чтобы вы могли реализовать свою собственную логику для обработки авторизации (Roles = x) с вашей собственной логикой. см. blog.dkmulligan.com/2013/ 23 января / - person Mike Beeler; 04.12.2013
comment
в любом случае создать iprincipal из имени Windows и использовать его для поиска соответствующего пользователя в моей базе данных и связанной роли? - person Jay; 04.12.2013
comment
HttpContext.Current.User = новый System.Security.Principal.GenericPrincipa (идентификатор, роли); где роли - это список строк для ролей - person Mike Beeler; 04.12.2013
comment
Используя ваше предложение, я, по крайней мере, могу связать пользователя с ролью, есть ли способ установить isauthenticated равным true для удостоверения пользователя, которое я создаю. Я делаю следующее: WindowsIdentity identity = new WindowsIdentity (this.UserName); строка [] роли = новая строка [1]; роли [0] = myUser.Role.Name; - person Jay; 04.12.2013
comment
Я пытаюсь получить доступ к странице / Admin, и это отображается как 401 ограниченный доступ при использовании аутентификации ADFS или Forms, но у меня есть вход в систему на контроллере, который проверяет, аутентифицирован ли пользователь, в этом случае он по-прежнему имеет значение false и читается только так, кажется, не могу установить его программно - person Jay; 04.12.2013
comment
с помощью MVC это можно реализовать как фильтр, который у вас есть у пользователя, это просто вопрос добавления роли и переопределения stackoverflow.com/questions/4837103/ - person Mike Beeler; 04.12.2013