簡體   English   中英

如何在 Asp.Net Core 2.2 中在運行時禁用/啟用身份驗證?

[英]How do I disable/enable authentication at runtime in Asp.Net Core 2.2?

網站默認只能匿名訪問。

管理員有一個按鈕可以將站點切換到維護模式,它應該使用內置的 CookieAuthentication 啟用授權(在數據庫中稍微翻轉一下,與本文無關)。

為了實現這一點,我首先配置了 cookie 身份驗證(在 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
}

這非常有效 - 當存在授權屬性時,cookie 身份驗證開始。 到現在為止還挺好。

現在我想在維護模式關閉時在運行禁用授權。

嘗試的解決方案

這是我經過大量反復試驗和研究后得出的結論。

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
}

當站點處於維護模式時,這很有效。

當站點未處於維護模式時,cookie 身份驗證仍會啟動並需要身份驗證。 我可以刪除它並嘗試實現我自己的身份驗證,但是當我們已經內置了精心設計的解決方案時,這將是愚蠢的。

當站點未處於維護模式(運行時)時,如何禁用授權?

筆記:

問:為什么不通過執行 x(這需要服務器端訪問配置、環境變量、服務器或類似內容)來處理這個問題?

答:因為非技術管理員用戶需要通過單擊后端中的按鈕立即訪問它。

是的你可以!

ASP.NET Core 中的授權系統是可擴展的,您可以使用基於策略的授權輕松實現您的場景。

開始前需要知道的兩個主要事項:

  • 授權策略由一個或多個要求組成
  • 必須滿足所有要求才能使政策成功

我們的目標是創建一個要求,如果以下任何陳述為真,則該要求得到滿足:

  • 未啟用維護模式,或
  • 用戶已通過身份驗證

讓我們看看代碼!

第一步是創建我們的需求:

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();
}

恐怕做不到。授權的接受與身份驗證不同,當context.HttpContext.User.Identity.IsAuthenticatedfalse ,它將始終重定向到登錄頁面。

最好將必須或可能需要在控制器中授權的操作放在一起,並在單獨的控制器中使用[AllowAnonymous]未經授權的操作。

if (!user.IsMaintenanceModeEnabled)
{
    context.Result = new RedirectResult("Another controller with [AllowAnonymous]");
     return;
}

由於當前頁面需要在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.cshtml 頁面,檢查是否 Maintancer Maintancer Login ,然后輸入switch button
  2. 在可以匿名訪問的操作或頁面中,檢查是否“ IsMaintenanceMode登錄”&& IsMaintenanceMode ,然后顯示IsMaintenanceMode Maintancer-authorized elements ,例如Delete PostEdit Content 、...
  3. 在僅適用於Maintancer Controller.Actions(如Delete Post )中,添加[Authorize(Roles="Maintancer")][Authorize(Policy="Maintancer")]或您自定義授權。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM