[英]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.IsAuthenticated
為false
,它將始終重定向到登錄頁面。
最好將必須或可能需要在控制器中授權的操作放在一起,並在單獨的控制器中使用[AllowAnonymous]
未經授權的操作。
if (!user.IsMaintenanceModeEnabled)
{
context.Result = new RedirectResult("Another controller with [AllowAnonymous]");
return;
}
由於當前頁面需要在anonymous
模式下完美工作,因此身份驗證不應在Controller
級別。
我認為您的要求是:
如果Maintancer
登錄系統,
maintance elements
(切換按鈕或其他),以便Maintancer
可以在不同模式下切換頁面,並執行maintancer actions
anonymously
訪問站點, anonymous-mode elements
將呈現給瀏覽器Maintancer
,則normal-user-mode elements
將呈現給瀏覽器要解決這些問題,關鍵是阻止未經授權的用戶訪問Maintancer ACTIONS
,而不是controller
。
我的建議是:
Maintancer Login
,然后輸入switch button
IsMaintenanceMode
登錄”&& IsMaintenanceMode
,然后顯示IsMaintenanceMode
Maintancer-authorized elements
,例如Delete Post
、 Edit Content
、...Maintancer
Controller.Actions(如Delete Post
)中,添加[Authorize(Roles="Maintancer")]
或[Authorize(Policy="Maintancer")]
或您自定義授權。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.