2016-07-05 5 views
1

У меня есть приложение в ASP.NET MVC Ядро (dnx46) RC1 с AuthorizationHandler:AuthorizationHandler исключение не происходит через ExceptionFilter

public class AppSumAuthAuthorizationHandler : AuthorizationHandler<AppSumAuthRequirement> 
{ 
    private readonly IUserRepository _userRepository; 
    private readonly IUserRoleRepository _userRoleRepository; 

    public AppSumAuthAuthorizationHandler(IUserRepository userRepository, IUserRoleRepository userRoleRepository) 
    { 
     _userRepository = userRepository; 
     _userRoleRepository = userRoleRepository; 
    } 
    protected override async void Handle(AuthorizationContext context, AppSumAuthRequirement requirement) 
    { 
     await HandleAsync(context,requirement); 
    } 

    protected override async Task HandleAsync(AuthorizationContext context, AppSumAuthRequirement requirement) 
    { 
     var currentUserName = context.User.Identity.Name; 
     var currentUser = await _userRepository.GetAsync(u => u.UserName == context.User.Identity.Name); 

     // Create user that does not yet exist 
     if(currentUser == null) 
     { 
      var user = new User(currentUserName); 
      /* Temporary add SysAdmin role */ 
      using(new CreatedBySystemProvider(_userRepository)) 
      { 
       _userRepository.Add(user); 
       await _userRepository.SaveChangesAsync(); 
       if (string.Equals(currentUserName, @"BIJTJES\NilsG", StringComparison.CurrentCultureIgnoreCase)) 
       { 
        user.AddRole(1); 
       } 
       currentUser = await _userRepository.GetAsync(u => u.Id == user.Id); 
      } 
     } 
     var resource = (Microsoft.AspNet.Mvc.Filters.AuthorizationContext) context.Resource; 
     var controllerActionDescriptor = resource.ActionDescriptor as ControllerActionDescriptor; 
     var controllerName = controllerActionDescriptor.ControllerName; 
     var actionName = controllerActionDescriptor.Name; 
     string moduleName; 
     try 
     { 
      // Get the name of the module 
      moduleName = ((ModuleAttribute)controllerActionDescriptor.ControllerTypeInfo.GetCustomAttributes(false).First(a => a.GetType().Name == "ModuleAttribute")).ModuleName; 
     } 
     catch(InvalidOperationException ex) 
     { 
      context.Fail(); 
      throw new InvalidOperationException($"The Module Attribute is required on basecontroller {controllerName}.", ex); 
     } 

     var access = new Access(moduleName, controllerName, actionName); 

     if (await currentUser.HasPermissionTo(UrlAccessLevel.Access).OnAsync(access)) 
     { 
      context.Succeed(requirement); 
     } 
     else 
     { 
      context.Fail(); 
     } 
    } 
} 

Класс требование пуст:

public interface IAppSumAuthRequirement : IAuthorizationRequirement 
{ 

} 
public class AppSumAuthRequirement : IAppSumAuthRequirement 
{ 

} 

Атрибут Module также нет ничего особенного:

public class ModuleAttribute : Attribute 
{ 
    public string ModuleName { get; private set; } 
    public ModuleAttribute(string moduleName) 
    { 
     ModuleName = moduleName; 
    } 

    public override string ToString() 
    { 
     return ModuleName; 
    } 
} 

Фильтр исключений:

public class JsonExceptionFilterAttribute : ExceptionFilterAttribute 
{ 
    public override void OnException(ExceptionContext context) 
    { 
     var exception = context.Exception; 
     context.HttpContext.Response.StatusCode = 500; 
     context.Result = new JsonResult(new Error 
     { 
      Message = exception.Message, 
      InnerException = exception.InnerException?.InnerException?.Message, 
      Data = exception.Data, 
      ErrorCode = exception.HResult, 
      Source = exception.Source, 
      Stacktrace = exception.StackTrace, 
      ErrorType = exception.GetType().ToString() 
    }); 
    } 
} 

и политики настроены в моих Startup.cs:

public IServiceProvider ConfigureServices(IServiceCollection services) 
    { 
     services.AddMvc(options => 
     { 
      options.Filters.Add(new JsonExceptionFilterAttribute()); 
      options.ModelBinders.Insert(0, new NullableIntModelBinder()); 
     }).AddJsonOptions(options => { 
      options.SerializerSettings.ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore; 
      options.SerializerSettings.ContractResolver = new Newtonsoft.Json.Serialization.CamelCasePropertyNamesContractResolver(); 
     }); 

     // Security 
     services.AddAuthorization(options => 
     { 
      options.AddPolicy("AppSumAuth", 
       policy => policy.Requirements.Add(new AppSumAuthRequirement())); 
     }); 
} 

и политика устанавливается на всех контроллерах, наследуя BaseController:

[Authorize(Policy = "AppSumAuth")] 
public class BaseController : Controller 
{ 
    public BaseController() 
    { 

    } 
} 

Таким образом, в моем обработчике, я получить управляющее имя, имя_файла и имя_модуля (из атрибута, установленного на контроллерах):

[Module("Main")] 

Когда этот атрибут не установлен на контроллере, я хотел бы поймать исключение и сообщить об этом разработчику, вызывающему контроллер, и запретить доступ. Чтобы сделать это, я добавил:

 catch(InvalidOperationException ex) 
     { 
      context.Fail(); 
      throw new InvalidOperationException($"The Module Attribute is required on basecontroller {controllerName}.", ex); 
     } 

JsonExceptionFilter называется прекрасно, когда есть исключение в контроллерах. Однако он не вызывается, когда в AuthorizationHandler имеется ошибка.


Так что вопрос:

Как я могу получить Исключения должны быть пойманным JsonExceptionFilter? Что я делаю неправильно?

Решение:

Startup.cs:

public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory) 
    { 
     // For Windows Auth! 
     app.UseIISPlatformHandler(); 

     app.UseStaticFiles(); 

     app.UseExceptionHandler(AppSumExceptionMiddleware.JsonHandler()); 

     app.UseMvc(); 
    } 

И мой промежуточный слой:

public class AppSumExceptionMiddleware 
{ 
    public static Action<IApplicationBuilder> JsonHandler() 
    { 
     return errorApp => 
     { 
      errorApp.Run(async context => 
      { 
       var exception = context.Features.Get<IExceptionHandlerFeature>(); 
       if (exception != null) 
       { 
        var exceptionJson = Encoding.UTF8.GetBytes(
         JsonConvert.SerializeObject(new AppSumException(exception.Error), 
         new JsonSerializerSettings 
         { 
          ContractResolver = new CamelCasePropertyNamesContractResolver() 
         }) 
        ); 
        context.Response.ContentType = "application/json"; 
        await context.Response.Body.WriteAsync(exceptionJson, 0, exceptionJson.Length); 
       } 
      }); 
     }; 
    } 
} 
+0

Пожалуйста, не используйте тег MVC6 больше. Это для будущей версии ASP.NET MVC на основе старого webstack (MVC5). ASP.NET Core - это совершенно новая и несовместимая портативная версия на базе .NET Core. Используйте теги [tag: asp.net-core-mvc] и/или [tag: asp.net-core], и ​​ваш вопрос чаще встречается людьми, которые могут помочь вам в решении проблемы. Также переключитесь на ASP.NET Core 1.0 ASAP. DNX больше не поддерживается, и все версии за пределами RC1 работают только в цепочке оснастки dotnet-cli. Чем раньше вы переключитесь на меньшую боль, тем больше вы перейдете к новой оснастке. – Tseng

+0

Здравствуйте, я использую «var ex = context.Features.Get (); чтобы получить трассировку стека и внутреннее исключение, но она показывает нулевое значение Значение не может помочь мне. –

ответ

3

Действия фильтр может быть использован в качестве метода фильтра, регулятор фильтра или глобального фильтра только для HTTP-запросы MVC. В вашем случае вы должны использовать middleware как

Middleware является компонентом, который «сидит» на трубопроводе HTTP и исследовать все запросы и ответы.

Как вы хотите, чтобы работа с исключением, вы можете использовать готовые к использованию ExceptionHandler промежуточному программному обеспечения:

 app.UseExceptionHandler(errorApp => 
     { 
      errorApp.Run(async context => 
      { 
       context.Response.StatusCode = 500; // for example 

       var error = context.Features.Get<IExceptionHandlerFeature>(); 
       if (error != null) 
       { 
        var ex = error.Error; 
        // custom logic 
       } 
      }); 
     }); 
+0

Спасибо, это действительно решило проблему! Я добавил эту строку в свой Startup.cs: app.UseExceptionHandler (AppSumExceptionMiddleware.JsonHandler()), а метод JsonHandler() задает ответ Я обновляю свой пост, чтобы помочь другим с той же проблемой. – AppSum

+0

пока я реализовал это var ex = context.Features.Get (); показывает значение null в ex , как это возможно пожалуйста Помогите –

Смежные вопросы