我使用这个回购实现了基于^的Blazor服务器上的cookie身份验证和授权。
我知道我不能使用HttpContextAccessor,因为Microsoft建议,但是,我在登录和注销的.cshtml
文件中使用了与此链接相同的HttpContext
,而不是在Blazor组件中。
windows服务器IIS服务器(2022)上的生产阶段的问题是,如果第一个用户使用他的用户名登录到应用程序,其他用户也会在其计算机浏览器中使用相同的第一个用户名进行身份验证。现在,如果第二个用户使用他的用户名输入,那么所有用户都将使用第二个用户名进行身份验证,依此类推。现在,如果用户按下注销键,他将被注销,他的cookie将从浏览器中删除,但在刷新浏览器页面一次之后,他将再次与上一次验证的登录用户一起登录,而无需经过登录过程。即使如此,他的浏览器里也没有饼干。为了更好地澄清,我已经给出了它是如何工作的(当然,为了在实验室环境中记录屏幕,我已经在IIS Express上进行了模拟)。
我几乎可以猜到问题在于HttpContext
的使用。但是,我在网上看到的所有用于Blazor的cookies实现,都没有提到这个问题。因此,我猜想我在实现方面可能犯了一个错误。
有没有办法解决我的问题提供的解决方案?
我已经看到了这些问题的答案-- ^,^,^,然而,没有一个是我的问题的答案。
我用.Net6。这是我在startup.cs上的身份验证配置
services.AddScoped<IUnitOfWork, ApplicationDbContext>();
services.AddScoped<IUsersService, UsersService>();
services.AddScoped<IRolesService, RolesService>(); services.AddScoped<ISecurityService, SecurityService>();
services.AddScoped<ICookieValidatorService, CookieValidatorService>();
services.AddScoped<IDbInitializerService, DbInitializerService>();
services.AddSingleton<AuthenticationStateProvider, CustomAuthenticationStateProvider>();
services
.AddAuthentication(options =>
{
options.DefaultChallengeScheme = CookieAuthenticationDefaults.AuthenticationScheme;
options.DefaultSignInScheme = CookieAuthenticationDefaults.AuthenticationScheme;
options.DefaultAuthenticateScheme = CookieAuthenticationDefaults.AuthenticationScheme;
})
.AddCookie(options =>
{
options.SlidingExpiration = false;
options.LoginPath = "/";
options.LogoutPath = "/";
//options.AccessDeniedPath = new PathString("/Home/Forbidden/");
options.Cookie.Name = ".my.app1.cookie";
options.Cookie.HttpOnly = true;
options.Cookie.SecurePolicy = CookieSecurePolicy.SameAsRequest;
options.Cookie.SameSite = SameSiteMode.Lax;
options.Events = new CookieAuthenticationEvents
{
OnValidatePrincipal = context =>
{
var cookieValidatorService = context.HttpContext.RequestServices.GetRequiredService<ICookieValidatorService>();
return cookieValidatorService.ValidateAsync(context);
}
};
});
更新:(问题解决了)
我使用了像下面这样的类来获取当前用户。
public class CustomAuthenticationStateProvider : RevalidatingServerAuthenticationStateProvider
{
private readonly IServiceScopeFactory _scopeFactory;
public CustomAuthenticationStateProvider(ILoggerFactory loggerFactory, IServiceScopeFactory scopeFactory)
: base(loggerFactory) =>
_scopeFactory = scopeFactory ?? throw new ArgumentNullException(nameof(scopeFactory));
protected override TimeSpan RevalidationInterval { get; } = TimeSpan.FromMinutes(30);
protected override async Task<bool> ValidateAuthenticationStateAsync(
AuthenticationState authenticationState, CancellationToken cancellationToken)
{
// Get the user from a new scope to ensure it fetches fresh data
var scope = _scopeFactory.CreateScope();
try
{
var userManager = scope.ServiceProvider.GetRequiredService<IUsersService>();
return await ValidateUserAsync(userManager, authenticationState?.User);
}
finally
{
if (scope is IAsyncDisposable asyncDisposable)
{
await asyncDisposable.DisposeAsync();
}
else
{
scope.Dispose();
}
}
}
private async Task<bool> ValidateUserAsync(IUsersService userManager, ClaimsPrincipal? principal)
{
if (principal is null)
{
return false;
}
var userIdString = principal.FindFirst(ClaimTypes.UserData)?.Value;
if (!int.TryParse(userIdString, out var userId))
{
return false;
}
var user = await userManager.FindUserAsync(userId);
return user is not null;
}
}
此类以下列方式注入到项目中。
services.AddSingleton<AuthenticationStateProvider, CustomAuthenticationStateProvider>();
问题就在这里。不应该将该类作为AddSingleton
注入到Blazor项目中,因为我使用.cshtml
文件进行登录和注销。如果我把它改为AddScoped
,问题就解决了。您可以看到这个这里的原因。然而,之前在这个问题中出现的问题再次出现:()
发布于 2022-11-30 13:19:16
我认为static
的问题。尝试这样添加您的策略:
services.AddAuthorization(config =>
{
config.AddPolicy("Admin", policy => policy.RequireClaim("IsAdmin", "true"));
});
在控制器中,您可以使用以下内容:
[Authorize(Policy = “IsAdmin”)]
public IActionResult LogIn()
{
// ...
}
构成部分:
@page "/somepage"
@attribute [Authorize(Policy = "IsAdmin")]
或
<AuthorizeView Policy="IsAdmin">
<p>You can only see this if you are admin</p>
</AuthorizeView>
https://stackoverflow.com/questions/74626721
复制相似问题