为什么 Authentication Cookie 对 [Authorize] 属性不起作用?
Why is the Authentication Cookie not working against the [Authorize] attribute?
我们尝试在我们的 Blazor-WebAssembly 应用程序中通过 Cookie 实施身份验证。
控制器: 设置 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
});
// [...]
}
}
当我查看 edge 浏览器的开发人员工具时,我发现 cookie 已设置:
现在以下 Controller
有一个搜索操作,应该通过添加 [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 请求 /Clients?search=My Search Text
时,Edge 的开发人员工具向我显示,有一个向 /Account/Login
发出的请求。这让我感到困惑,因为响应代码是 200 但我的项目中不存在帐户控制器。
为什么我的身份验证 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 身份验证方案显式登录后发现用户在以后的请求中无法被识别,则表明您没有正确配置身份验证中间件。作为 per the docs,您不仅需要使用 services.AddAuthentication(…)
添加身份验证服务,还必须将身份验证中间件配置为 运行 作为请求管道的一部分。这通常看起来像这样:
app.UseRouting();
// add the call to `UseAuthentication`
app.UseAuthentication();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
});
通过将 UseAuthentication()
调用添加到中间件中,您将导致默认身份验证方案(在您的情况下为 cookie 方案)运行 尝试对用户进行身份验证。这确保如果请求中有身份验证 cookie,那么它将用于对用户进行身份验证,无论您是否要访问授权路由。
一旦中间件 运行s,仅受 [Authorize]
属性保护的操作也将起作用,因为 cookie 方案的身份验证已经发生(因为它是默认方案)。
否则,如果默认情况下不调用中间件,则需要确保在需要访问用户信息时始终显式调用身份验证方案。这就是 [Authorize(AuthenticationSchemes = "scheme-name")]
所做的:在 授权 运行 之前,它将尝试验证指定的方案。 – 如果您使用身份验证中间件并且具有正确的默认方案,那么您可以跳过此步骤,因为该方案将默认进行身份验证。
在您的原始代码中,没有身份验证 运行ning,这也解释了您被重定向的原因:由于身份验证方案没有 运行 对用户进行身份验证,因此没有登录用户(即使用户有 cookie)。因此,当用户 已授权 时,没有用户在那里,您将被重定向到登录页面。
为什么会重定向到 /Account/Login
?
cookie 身份验证方案涉及在需要身份验证(例如通过 [Authorize]
属性)但用户还没有身份验证 cookie 时将用户重定向到登录页面。在这种情况下,身份验证将受到“挑战”,对于 cookie 方案而言,这意味着用户将被重定向到他们应该登录的登录页面。
默认情况下,登录页面的路由配置为/Account/Login
。当您使用 ASP.NET Core Identity 时,此默认值与默认行为相匹配。您可以通过更改 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
。因此,您应该接受此路由参数,并在登录完成后 return 返回该路由,例如:
[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)]
作为我的操作。这是代码:
[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
我们尝试在我们的 Blazor-WebAssembly 应用程序中通过 Cookie 实施身份验证。
控制器: 设置 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
});
// [...]
}
}
当我查看 edge 浏览器的开发人员工具时,我发现 cookie 已设置:
现在以下 Controller
有一个搜索操作,应该通过添加 [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 请求 /Clients?search=My Search Text
时,Edge 的开发人员工具向我显示,有一个向 /Account/Login
发出的请求。这让我感到困惑,因为响应代码是 200 但我的项目中不存在帐户控制器。
为什么我的身份验证 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 身份验证方案显式登录后发现用户在以后的请求中无法被识别,则表明您没有正确配置身份验证中间件。作为 per the docs,您不仅需要使用 services.AddAuthentication(…)
添加身份验证服务,还必须将身份验证中间件配置为 运行 作为请求管道的一部分。这通常看起来像这样:
app.UseRouting();
// add the call to `UseAuthentication`
app.UseAuthentication();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
});
通过将 UseAuthentication()
调用添加到中间件中,您将导致默认身份验证方案(在您的情况下为 cookie 方案)运行 尝试对用户进行身份验证。这确保如果请求中有身份验证 cookie,那么它将用于对用户进行身份验证,无论您是否要访问授权路由。
一旦中间件 运行s,仅受 [Authorize]
属性保护的操作也将起作用,因为 cookie 方案的身份验证已经发生(因为它是默认方案)。
否则,如果默认情况下不调用中间件,则需要确保在需要访问用户信息时始终显式调用身份验证方案。这就是 [Authorize(AuthenticationSchemes = "scheme-name")]
所做的:在 授权 运行 之前,它将尝试验证指定的方案。 – 如果您使用身份验证中间件并且具有正确的默认方案,那么您可以跳过此步骤,因为该方案将默认进行身份验证。
在您的原始代码中,没有身份验证 运行ning,这也解释了您被重定向的原因:由于身份验证方案没有 运行 对用户进行身份验证,因此没有登录用户(即使用户有 cookie)。因此,当用户 已授权 时,没有用户在那里,您将被重定向到登录页面。
为什么会重定向到 /Account/Login
?
cookie 身份验证方案涉及在需要身份验证(例如通过 [Authorize]
属性)但用户还没有身份验证 cookie 时将用户重定向到登录页面。在这种情况下,身份验证将受到“挑战”,对于 cookie 方案而言,这意味着用户将被重定向到他们应该登录的登录页面。
默认情况下,登录页面的路由配置为/Account/Login
。当您使用 ASP.NET Core Identity 时,此默认值与默认行为相匹配。您可以通过更改 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
。因此,您应该接受此路由参数,并在登录完成后 return 返回该路由,例如:
[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)]
作为我的操作。这是代码:
[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