最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

asp.net core - Blazor Server .NET 8 with API auth - AuthState is always false - Stack Overflow

programmeradmin2浏览0评论

The issue: AuthState is always false, even after successful API auth and after HttpContext.SignInAsync.

I'm stuck with this as I don't understand why Blazor is not updating the authState.

Before .NET 8, I was using custom AuthProvider to update user:

public class WebAuthStateProvider(IHttpContextAccessor httpContextAccessor)
    : AuthenticationStateProvider, IAuthProvider
{
    private ClaimsPrincipal user = httpContextAccessor.HttpContext?.User ?? new ClaimsPrincipal(new ClaimsIdentity());

    public override Task<AuthenticationState> GetAuthenticationStateAsync()
    {
        return Task.FromResult(new AuthenticationState(user));
    }

    public async Task SaveUser(IEnumerable<Claim> claims)
    {
        var identity = new ClaimsIdentity(claims, CookieAuthenticationDefaults.AuthenticationScheme);
        user = new(identity);
        NotifyAuthenticationStateChanged(Task.FromResult(new AuthenticationState(user)));
    }

    public async Task Logout()
    {
        user = new ClaimsPrincipal(new ClaimsIdentity());
        NotifyAuthenticationStateChanged(Task.FromResult(new AuthenticationState(user)));
    }

    public void NotifyUserAuthentication()
    {
        NotifyAuthenticationStateChanged(GetAuthenticationStateAsync());
    }
}

Login.razor:

private async Task LoginWithEmail()
{
    errorMessage = null;

    var loginRequest = new LoginRequestModel()
    {
        Platform = IsWeb ? "web" : "mobile",
        Email = email,
        Password = password
    };

    try
    {
        var baseUrl = IsWeb ? Navigation.BaseUri : "https://mydomain/";
        var requestUrl = $"{baseUrl}api/v1/auth/login";
        var response = await Http.PostAsJsonAsync(requestUrl, loginRequest);

        if (response.StatusCode == HttpStatusCode.Unauthorized)
        {
            errorMessage = "Invalid email or password.";
            return;
        }

        if (!response.IsSuccessStatusCode)
        {
            errorMessage = "An error occurred while logging in. Please try again.";
            return;
        }

        var authResponse = await response.Content.ReadFromJsonAsync<AuthResponse>();

        if (authResponse != null)
        {
            var claims = new List<Claim>
            {
                new(ClaimTypes.Email, authResponse.Email),
                new("Avatar", authResponse.Avatar),
                new("Id", authResponse.Id),
                new("JWT", authResponse.Token),
            };
            claims.AddRange(authResponse.Roles.Select(role => new Claim(ClaimTypes.Role, role)));

            var test = AuthState.User; // always null (isAuthenticated = false)

            Navigation.NavigateTo("/feed", true);
        }
    }
    catch
    {
        errorMessage = "An unexpected error occurred. Please try again later.";
    }
}

Program.cs:

builder.Services.AddAuthentication(options =>
    {
        options.DefaultAuthenticateScheme = CookieAuthenticationDefaults.AuthenticationScheme;
        options.DefaultChallengeScheme = CookieAuthenticationDefaults.AuthenticationScheme;
        options.DefaultSignInScheme = CookieAuthenticationDefaults.AuthenticationScheme;
    })
    .AddCookie(CookieAuthenticationDefaults.AuthenticationScheme, options =>
    {
        options.LoginPath = "/identity/login";
        options.LogoutPath = "/identity/logout";
        options.AccessDeniedPath = "/identity/access-denied";
        options.ExpireTimeSpan = TimeSpan.FromDays(7);
        options.Cookie.HttpOnly = true;
        options.Cookie.SecurePolicy = CookieSecurePolicy.Always;
    })
    .AddJwtBearer(JwtBearerDefaults.AuthenticationScheme, options =>
    {
        options.TokenValidationParameters = new()
        {
            ValidateIssuer = true,
            ValidateAudience = true,
            ValidateLifetime = true,
            ValidateIssuerSigningKey = true,
            ValidIssuer = builder.Configuration["AuthConfiguration:jwtTokenConfig:issuer"],
            ValidAudience = builder.Configuration["AuthConfiguration:jwtTokenConfig:issuer"],
            IssuerSigningKey = new SymmetricSecurityKey(
                Encoding.UTF8.GetBytes(builder.Configuration["AuthConfiguration:jwtTokenConfig:secret"])
            )
        };
    })
    .AddGoogle("Google", options =>
    {
        options.ClientId = builder.Configuration["Google:ClientId"];
        options.ClientSecret = builder.Configuration["Google:ClientSecret"];
        options.ClaimActions.MapJsonKey("urn:google:profile", "link");
        options.ClaimActions.MapJsonKey("urn:google:image", "picture");
        options.CorrelationCookie.SecurePolicy = CookieSecurePolicy.Always;
        options.SaveTokens = true;
    });

builder.Services.AddAuthorization();
builder.Services.AddCascadingAuthenticationState();
builder.Services.AddHttpContextAccessor();
...

app.UseAuthentication();
app.UseAuthorization();
app.UseRouting();

App.Razor - wrapped into CascadingAuthenticationState.

AuthController.cs:

[HttpPost("register")]
public async Task<IActionResult> Register([FromBody] RegisterRequestModel requestModel)
{
    if (await userManager.FindByEmailAsync(requestModel.Email) != null)
        return Conflict("User with this email already exists.");

    var user = new UserEntity
    {
        UserName = SanitizeUserName(requestModel.Name),
        Email = requestModel.Email,
        AvatarUrl = "default-avatar.png"
    };

    var result = await userManager.CreateAsync(user, requestModel.Password);

    if (!result.Succeeded)
        return BadRequest(result.Errors);

    var roles = await userManager.GetRolesAsync(user);
    var token = GenerateJwtToken(user, roles);

    var claims = new List<Claim>
    {
        new(ClaimTypes.Email, user.Email),
        new("Avatar", user.AvatarUrl),
        new("Id", user.Id)
    };
    claims.AddRange(roles.Select(role => new Claim(ClaimTypes.Role, role)));

    var claimsIdentity = new ClaimsIdentity(claims, CookieAuthenticationDefaults.AuthenticationScheme);
    var authProperties = new AuthenticationProperties { IsPersistent = true };

    await HttpContext.SignInAsync(
        CookieAuthenticationDefaults.AuthenticationScheme,
        new(claimsIdentity),
        authProperties);

    logger.LogInformation($"User registered: {requestModel.Name} {requestModel.Email}");
    return Ok(new AuthResponse
    {
        Token = token,
        Email = user.Email,
        Avatar = user.AvatarUrl,
        Roles = roles.ToList(),
        Id = user.Id
    });
}
发布评论

评论列表(0)

  1. 暂无评论