[英]Using the Authorize Attribute with Custom Cookie Authentication in ASP.NET Core
[英]Why is the Authentication Cookie not working against the [Authorize] attribute?
我們嘗試在 Blazor-WebAssembly 應用程序中通過 Cookies 實現身份驗證。
Controller:設置 Auth-Cookie:
[Route("[controller]")]
[ApiController]
public class AuthController : ControllerBase
{
[HttpPost]
public async Task<AdUser> Login(Credentials pCredentials)
{
// [...] credential check jere
var lClaims = new List<Claim> {
new Claim(ClaimTypes.Name, "SamAccountName"),
};
var lClaimsIdentity = new ClaimsIdentity(lClaims, CookieAuthenticationDefaults.AuthenticationScheme);
// set cookie
await HttpContext.SignInAsync(
CookieAuthenticationDefaults.AuthenticationScheme,
new ClaimsPrincipal(lClaimsIdentity),
new AuthenticationProperties
{
IsPersistent = true,
ExpiresUtc = DateTime.UtcNow.AddYears(1),
RedirectUri = this.Request.Host.Value
});
// [...]
}
}
當我查看邊緣瀏覽器的開發人員工具時,我可以看到,cookie 已設置:
現在下面的Controller
有一個 Search-Action 並且應該通過添加 [Authorize] 屬性來限制訪問:
[Route("[controller]")]
[ApiController]
public class ClientsController : ControllerBase
{
[HttpGet("search")]
[Authorize]
public ActionResult<List<Shared.Client>> Search(string pText)
{
// [...] Code here
return lResult;
}
}
當我對 ClientsController 執行 HTTP-Request /Clients?search=My Search Text
時,Edge 的開發人員工具向我顯示,有一個對/Account/Login
的請求。 這讓我很困惑,因為響應代碼是 200,但我的項目中不存在 Account-Controller。
為什么我的身份驗證 Cookie 對[Authorize]
屬性不起作用?
有關我的配置的更多詳細信息:
Startup.cs (服務器端)
namespace BlazorWebAssemblyApp.Server
{
public class Startup
{
/// [...]
public void ConfigureServices(IServiceCollection services)
{
// [...]
services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme).AddCookie(); // This line is required for the authentication cookie
// [...]
}
}
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
// [...]
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapRazorPages();
endpoints.MapControllers();
endpoints.MapFallbackToFile("index.html");
});
}
}
如果您在使用 cookie 身份驗證方案顯式登錄后發現用戶在將來的請求中無法識別,則表明您沒有正確配置身份驗證中間件。 根據文檔,您不僅需要使用services.AddAuthentication(…)
添加身份驗證服務,還必須配置身份驗證中間件以作為請求管道的一部分運行。 這通常看起來像這樣:
app.UseRouting();
// add the call to `UseAuthentication`
app.UseAuthentication();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
});
通過將UseAuthentication()
調用添加到中間件中,您將導致默認身份驗證方案(在您的情況下為 cookie 方案)嘗試對用戶進行身份驗證。 這確保如果請求中有一個身份驗證 cookie,那么它將用於對用戶進行身份驗證,無論您是否要訪問授權路由。
一旦中間件運行,僅使用[Authorize]
屬性保護的操作也將起作用,因為 cookie 方案的身份驗證已經發生(因為它是默認方案)。
否則,如果默認情況下不調用中間件,則需要確保在需要訪問用戶信息時始終顯式調用身份驗證方案。 這就是[Authorize(AuthenticationSchemes = "scheme-name")]
所做的:在授權運行之前,它將嘗試對指定的方案進行身份驗證。 – 如果您使用身份驗證中間件並具有正確的默認方案,則可以跳過此步驟,因為該方案將默認進行身份驗證。
在您的原始代碼中,沒有運行身份驗證,這也為您解釋了您被重定向的原因:由於沒有運行身份驗證方案來對用戶進行身份驗證,因此沒有登錄用戶(即使用戶有 cookie) . 所以當用戶被授權時,沒有用戶在那里,你被重定向到登錄頁面。
/Account/Login
? cookie 身份驗證方案是在需要身份驗證(例如通過[Authorize]
屬性)但用戶還沒有身份驗證 cookie 時將用戶重定向到登錄頁面所涉及的方案。 在這種情況下,身份驗證將受到“挑戰”,這對於 cookie 方案意味着用戶將被重定向到他們應該登錄的登錄頁面。
默認情況下,登錄頁面的路由配置為/Account/Login
。 當您使用 ASP.NET 核心標識時,此默認值與默認行為相匹配。 您可以通過更改CookieAuthenticationOptions.LoginPath
輕松配置此路由以匹配您的實際登錄頁面。 例如,您可以使用AddCookie()
調用來做到這一點:
services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme)
.AddCookie(options =>
{
options.LoginPath = "/Auth/Login"; // using the AuthController instead
});
現在,當用戶受到挑戰時,他們將被重定向到您的AuthController.Login
操作,而不是他們應該登錄的地方。
請注意,cookie 方案將向登錄操作添加請求參數ReturnUrl
,其中包含用戶最初嘗試訪問的頁面的路徑。 例如,當訪問您的搜索操作時,它們將被重定向到/Auth/Login?ReturnUrl=%2FClients%2Fsearch
。 因此,您應該接受此路由參數並在登錄完成后返回該路由,例如:
[HttpPost]
public async Task<IActionResult> Login(Credentials pCredentials, string returnUrl)
{
// do login
return LocalRedirect(returnUrl);
}
您還可以通過更改CookieAuthenticationOptions.ReturnUrlParameter
將參數ReturnUrl
的名稱更改為您喜歡的任何名稱。
您將被重定向到“登錄頁面”或 returnURL,因為您的身份驗證無法正常工作並且您正在獲得未經授權。 默認情況下,ASP.Net Core 在驗證失敗時會重定向您,而不是返回 401 代碼。
確保按照https://docs.microsoft.com/es-es/aspnet/core/security/authentication/identity?view=aspnetcore-3.1&tabs=visual-studio中所述的正確方式實施它。
不要忘記在 Startup.cs class 的 Configure 方法中添加以下行以添加 auth 中間件:
app.UseAuthentication();
app.UseAuthorization();
請檢查您的順序是否正確。(順序很重要,因為您首先進行身份驗證,然后檢查您的角色)。
它們還必須放在app.UseRouting()
和app.UseEndpoints()
調用之間。
我自己得到了它,使用[Authorize(AuthenticationSchemes = AuthSchemes)]
fpr 我在 controller 中的操作。 這是代碼:
[Route("[controller]")]
[ApiController]
public class ClientsController : ControllerBase
{
private const string AuthSchemes = CookieAuthenticationDefaults.AuthenticationScheme;
[HttpGet("search")]
[Authorize(AuthenticationSchemes = AuthSchemes)]
public ActionResult<List<Shared.Client>> Search(Shared.Client.SearchProperty pProperty, string pText)
{
// [...]
}
}
您可以在此處閱讀有關此主題的更多信息: https://docs.microsoft.com/de-de/aspnet/core/security/authorization/limitingidentitybyscheme?view=aspnetcore-3.1
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.