Как отключить / включить аутентификацию во время выполнения в Asp. Net Core 2.2? - PullRequest
0 голосов
/ 05 марта 2020

Веб-сайт по умолчанию предназначен только для анонимного доступа.

Администратор имеет кнопку, чтобы переключить сайт в режим обслуживания, который должен разрешить авторизацию с использованием встроенной функции CookieAuthentication (переключать бит в базе данных, а не релевантный для этого поста).

Для того, чтобы это работало, я сначала настроил аутентификацию cook ie (в файле startup.cs):

public void ConfigureServices(IServiceCollection services)
{
    services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme)
            .AddCookie(CookieAuthenticationDefaults.AuthenticationScheme,
                options =>
                {
                    options.LoginPath = new PathString("/auth/login");
                });
} 

public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
   app.UseAuthentication();
}

Затем на соответствующих контроллерах я поставил атрибут [Authorize].

[Authorize]
public class HomeController : Controller
{
  //removed
}

Это отлично работает - готовит ie auth, когда атрибут авторизации присутствует. Пока все хорошо.

Теперь я хочу отключить авторизацию во время выполнения при выключенном режиме обслуживания.

Попытка решения

Это то, чем я закончил после многих проб и ошибок и исследований.

public void OnAuthorization(AuthorizationFilterContext context)
    {
        IMaintenanceModeDataService ds = context.HttpContext.RequestServices.GetService<IMaintenanceModeDataService>();

        if (!ds.IsMaintenanceModeEnabled)
        {
            //Maintenance mode is off, no need for authorization
            return;
        }
        else
        {
            ClaimsPrincipal user = context.HttpContext.User;
            if (user.Identity.IsAuthenticated)
            {
                //when the user is authenticated, we don't need to do anything else.
                return;
            }
            else
            {
                //we're in maintenance mode AND the user is not 
                //It is outside the scope of this to redirect to a login
                //We just want to display maintenancemode.html
                context.Result = new RedirectResult("/maintenancemode.html");
                return;
            }
        }
    }

[MaintenanceModeAwareAuthorize]
public class HomeController : Controller
{
  //removed
}

Это прекрасно работает, когда сайт находится в режиме обслуживания.

Когда сайт НЕ находится в В режиме обслуживания аутентификация cook ie все еще активна и требует авторизации. Я мог бы удалить это и попытаться реализовать мою собственную аутентификацию, но это было бы глупо, если у нас уже есть встроенные решения, идеально продуманные до совершенства.

Как отключить авторизацию, когда сайт НЕ находится в режиме обслуживания ( во время выполнения )?

Примечания:

В: Почему бы не справиться с этим, выполнив x (что требует доступа на стороне сервера к конфигурации, переменным среды, серверу или аналогичным)?

A: Потому что это должно быть немедленно доступно нетехническим администраторам, нажав кнопку в бэкэнде.

Ответы [ 3 ]

1 голос
/ 07 марта 2020

Да, вы можете!

Система авторизации в ASP. NET Ядро расширяемо, и вы можете легко реализовать свой сценарий с авторизацией на основе poliy .

Для начала необходимо знать две основные вещи:

  • политика авторизации состоит из одного или нескольких требований
  • все требования должны быть выполнены для политика для достижения успеха

Наша цель состоит в том, чтобы затем создать требование, которое удовлетворяется, если выполняется любое из следующих утверждений:

  • режим обслуживания не включен или
  • пользователь аутентифицирован

Давайте посмотрим код!

Первый шаг - создать наше требование:

public class MaintenanceModeDisabledOrAuthenticatedUserRequirement : IAuthorizationRequirement
{
}

Затем мы должен реализовать обработчик для этого требования, который будет определять, удовлетворен ли он или нет. Хорошая новость заключается в том, что обработчики поддерживают внедрение зависимостей:

public class MaintenanceModeDisabledOrAuthenticatedUserRequirementHandler : AuthorizationHandler<MaintenanceModeDisabledOrAuthenticatedUserRequirement>
{
    private readonly IMaintenanceModeDataService _maintenanceModeService;

    public MaintenanceModeDisabledOrAuthenticatedUserRequirementHandler(IMaintenanceModeDataService maintenanceModeService)
    {
        _maintenanceModeService = maintenanceModeService;
    }

    protected override Task HandleRequirementAsync(AuthorizationHandlerContext context, MaintenanceModeDisabledOrAuthenticatedUserRequirement requirement)
    {
        if (!_maintenanceModeService.IsMaintenanceModeEnabled || context.User.Identities.Any(x => x.IsAuthenticated))
        {
            context.Succeed(requirement);
        }

        return Task.CompletedTask;
    }
}

Далее нам нужно создать политику авторизации, которая использует это требование, и у вас есть 2 варианта:

  • , которые вы можете переопределить политику по умолчанию, используемую при использовании «пустых» атрибутов [Authorize], или
  • создать явную политику, на которую вам придется ссылаться в ваших атрибутах, например [Authorize(Policy = "<your-policy-name>")]

Там нет правильного или неправильного ответа; Я бы выбрал первый вариант, если у моего приложения была только одна политика авторизации, и второй, если у него было несколько из них. Мы увидим, как это сделать:

services
    .AddAuthorization(options =>
    {
        // 1. This is how you redefine the default policy
        // By default, it requires the user to be authenticated
        //
        // See https://github.com/dotnet/aspnetcore/blob/30eec7d2ae99ad86cfd9fca8759bac0214de7b12/src/Security/Authorization/Core/src/AuthorizationOptions.cs#L22-L28
        options.DefaultPolicy = new AuthorizationPolicyBuilder()
            .AddRequirements(new MaintenanceModeDisabledOrAuthenticatedUserRequirement())
            .Build();

        // 2. Define a specific, named policy that you can reference from your [Authorize] attributes
        options.AddPolicy("MaintenanceModeDisabledOrAuthenticatedUser", builder => builder
            .AddRequirements(new MaintenanceModeDisabledOrAuthenticatedUserRequirement()));
    });

Далее вам необходимо зарегистрировать обработчик требований как IAuthorizationHandler, как указано в официальных документах

// The lifetime you pick is up to you
// You just need to remember that it's got a dependency on IMaintenanceModeDataService, so if you
// registered the implementation of IMaintenanceModeDataService as a scoped service, you shouldn't
// register the handler as a singleton
// See this captive dependency article from Mark Seeman: https://blog.ploeh.dk/2014/06/02/captive-dependency/
services.AddScoped<IAuthorizationHandler, MaintenanceModeDisabledOrAuthenticatedUserRequirementHandler>();

Последний шаг - применение атрибутов [Authorize] к контроллерам / действиям по мере необходимости.

// 1. If you redefined the default policy
[Authorize]
public IActionResult Index()
{
    return View();
}

// 2. If you defined an explicit policy
[Authorize(Policy = "MaintenanceModeDisabledOrAuthenticatedUser")]
public IActionResult Index()
{
    return View();
}
1 голос
/ 06 марта 2020

Боюсь, что это невозможно сделать. Принятие авторизации отличается от аутентификации, когда context.HttpContext.User.Identity.IsAuthenticated равно false, оно всегда будет перенаправлять на страницу входа.

Лучше иметь действия, которые должны или могут потребовать авторизацию в контроллере вместе, и несанкционированные действия в отдельном контроллере с [AllowAnonymous].

if (!user.IsMaintenanceModeEnabled)
{
    context.Result = new RedirectResult("Another controller with [AllowAnonymous]");
     return;
}
0 голосов
/ 06 марта 2020

Поскольку текущие страницы должны прекрасно работать в режиме anonymous, то аутентификация НЕ должна быть на уровне Controller.

Я думаю, что ваши запросы:

  1. Если Maintancer система входа в систему,

    • запустить дополнительный код, чтобы показать maintance elements ( кнопка или другие) на странице, поэтому Maintancer может переключать страницу в другом режиме и выполнять maintancer actions
  2. Если пользователь посещает сайт anonymously, anonymous-mode elements будет отображаться в браузер
  3. Если логин пользователя, но не Maintancer, normal-user-mode elements будет отображаться в браузере

Чтобы разрешить их, ключ заключается в том, чтобы заблокировать неавторизованному пользователю посещение Maintancer ACTIONS, вместо controller.

мои предложения:

  1. на странице _Layout.cs html, проверьте, если Maintancer Login, то добавьте switch button
  2. в действия или страницы который может посещать ненормально, проверьте «Вход в Maintancer» && IsMaintenanceMode, затем покажите Maintancer-authorized elements, например Delete Post, Edit Content, ...
  3. в Controller.Actions, который работает только для Maintancer (например, Delete Post), добавьте [Authorize(Roles="Maintancer")] или [Authorize(Policy="Maintancer")] или вы настроили авторизацию.
...