Пользовательское ограничение маршрута вызывает периодические ошибки 404
У меня есть Asp.Net Core 1 RC1
приложение, которое использует настраиваемое ограничение маршрута для управления доступом к приложению. Приложение (размещено на работающем сервере IIS 7.5
) получает периодические ошибки 404, которые, как я подозреваю, вызваны этим ограничением маршрутизации. Здесь вы можете увидеть скриншот с ошибками 404:
Я подозреваю, что эта проблема связана с кодом, который определяет ограничение маршрута не является потокобезопасным. Пользовательское ограничение маршрута требует DbContext
потому что он должен проверить в базе данных, если приложение включено для бренда, указанного в маршруте, и я подозреваю, что это DbContext
экземпляр может быть причиной проблемы. Вот как определяется маршрутизация в приложении:
// Add MVC to the request pipeline.
var appDbContext = app.ApplicationServices.GetRequiredService<AppDbContext>();
app.UseMvc(routes =>
{
routes.MapRoute(
name: "branding",
template: "branding/{brand}/{controller}/{action}/{id?}",
defaults: new { controller="Home", action="Index" },
constraints: new { brand = new BrandingRouteConstraint(appDbContext) });
});
А вот и пользовательское ограничение маршрута:
// Custom route constraint
public class BrandingRouteConstraint : IRouteConstraint
{
AppDbContext _appDbContext;
public BrandingRouteConstraint(AppDbContext appDbContext) : base() {
_appDbContext = appDbContext;
}
public bool Match(HttpContext httpContext, IRouter route, string routeKey, IDictionary<string, object> values, RouteDirection routeDirection)
{
if (values.Keys.Contains(routeKey))
{
var whiteLabel = _appDbContext.WhiteLabels.Where(w => w.Url == values[routeKey].ToString()).FirstOrDefault();
if (whiteLabel != null && whiteLabel.EnableApplication != null && (bool)whiteLabel.EnableApplication)
{
return true;
}
}
return false;
}
}
Может кто-нибудь подтвердить, что эта проблема вызвана тем, что код не является потокобезопасным, и порекомендовать способ изменить реализацию так, чтобы она была поточно-ориентированной?
1 ответ
Я не могу комментировать RouteContraint's, не использовал их много, но вы пробовали вместо этого авторизацию на основе ресурсов? Похоже, это больше подходит для того, что вы пытаетесь достичь?
Запросить услугу аутентификации внутри вашего контроллера
public class DocumentController : Controller
{
IAuthorizationService authorizationService;
public DocumentController(IAuthorizationService authorizationService)
{
this.authorizationService = authorizationService;
}
}
Примените проверки авторизации в своем действии:
public async Task<IActionResult> Edit(Guid documentId)
{
Document document = documentRepository.Find(documentId);
if (document == null)
{
return new HttpNotFoundResult();
}
if (await authorizationService.AuthorizeAsync(User, document, Operations.Edit))
{
return View(document);
}
else
{
return new HttpUnauthorizedResult();
}
}
Я использовал класс OperationAuthorizationRequirement в этом примере, поэтому определите этот класс в своем проекте:
public static class Operations
{
public static OperationAuthorizationRequirement Create =
new OperationAuthorizationRequirement { Name = "Create" };
public static OperationAuthorizationRequirement Read =
new OperationAuthorizationRequirement { Name = "Read" };
public static OperationAuthorizationRequirement Update =
new OperationAuthorizationRequirement { Name = "Update" };
public static OperationAuthorizationRequirement Delete =
new OperationAuthorizationRequirement { Name = "Delete" };
}
Реализуйте обработчик авторизации (используя встроенное требование OperationAuthorizationRequirement):
public class DocumentAuthorizationHandler : AuthorizationHandler<OperationAuthorizationRequirement, Document>
{
protected override void Handle(AuthorizationContext context,
OperationAuthorizationRequirement requirement,
Document resource)
{
// Validate the requirement against the resource and identity.
// Sample just checks "Name"field, put your real logic here :)
if (resource.Name == "Doc1")
context.Succeed(requirement);
else
context.Fail();
}
}
И не забывая ConfigureServices:
services.AddInstance<IAuthorizationHandler>(
new DocumentAuthorizationHandler());
Это немного больше работы, но добавляет большую гибкость.