首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >基于Blazor Server Cookie的身份验证,为所有客户端设置最后登录用户

基于Blazor Server Cookie的身份验证,为所有客户端设置最后登录用户
EN

Stack Overflow用户
提问于 2022-11-30 11:03:48
回答 1查看 50关注 0票数 0

我使用这个回购实现了基于^的Blazor服务器上的cookie身份验证和授权。

我知道我不能使用HttpContextAccessor,因为Microsoft建议,但是,我在登录注销.cshtml文件中使用了与此链接相同的HttpContext,而不是在Blazor组件中。

windows服务器IIS服务器(2022)上的生产阶段的问题是,如果第一个用户使用他的用户名登录到应用程序,其他用户也会在其计算机浏览器中使用相同的第一个用户名进行身份验证。现在,如果第二个用户使用他的用户名输入,那么所有用户都将使用第二个用户名进行身份验证,依此类推。现在,如果用户按下注销键,他将被注销,他的cookie将从浏览器中删除,但在刷新浏览器页面一次之后,他将再次与上一次验证的登录用户一起登录,而无需经过登录过程。即使如此,他的浏览器里也没有饼干。为了更好地澄清,我已经给出了它是如何工作的(当然,为了在实验室环境中记录屏幕,我已经在IIS Express上进行了模拟)。

我几乎可以猜到问题在于HttpContext的使用。但是,我在网上看到的所有用于Blazor的cookies实现,都没有提到这个问题。因此,我猜想我在实现方面可能犯了一个错误。

有没有办法解决我的问题提供的解决方案?

我已经看到了这些问题的答案-- ^^^,然而,没有一个是我的问题的答案。

我用.Net6。这是我在startup.cs上的身份验证配置

代码语言:javascript
运行
复制
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);
                    }
                };
            });

更新:(问题解决了)

我使用了像下面这样的类来获取当前用户。

代码语言:javascript
运行
复制
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;
    }
}

此类以下列方式注入到项目中。

代码语言:javascript
运行
复制
services.AddSingleton<AuthenticationStateProvider, CustomAuthenticationStateProvider>();

问题就在这里。不应该将该类作为AddSingleton注入到Blazor项目中,因为我使用.cshtml文件进行登录和注销。如果我把它改为AddScoped,问题就解决了。您可以看到这个这里的原因。然而,之前在这个问题中出现的问题再次出现:()

EN

回答 1

Stack Overflow用户

发布于 2022-11-30 13:19:16

我认为static的问题。尝试这样添加您的策略:

代码语言:javascript
运行
复制
services.AddAuthorization(config =>
{
  config.AddPolicy("Admin", policy => policy.RequireClaim("IsAdmin", "true"));
});

在控制器中,您可以使用以下内容:

代码语言:javascript
运行
复制
[Authorize(Policy = “IsAdmin”)]
public IActionResult LogIn()
{
  // ...
}

构成部分:

代码语言:javascript
运行
复制
@page "/somepage"
@attribute [Authorize(Policy = "IsAdmin")]

代码语言:javascript
运行
复制
<AuthorizeView Policy="IsAdmin">
    <p>You can only see this if you are admin</p>
</AuthorizeView>
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/74626721

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档