У меня есть приложение в 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);
}
});
};
}
}
Пожалуйста, не используйте тег 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
Здравствуйте, я использую «var ex = context.Features.Get(); чтобы получить трассировку стека и внутреннее исключение, но она показывает нулевое значение Значение не может помочь мне. –