Пользовательское ограничение маршрута вызывает периодические ошибки 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());

Это немного больше работы, но добавляет большую гибкость.

Другие вопросы по тегам