Search code examples
asp.net-coresignalrblazor-server-side

How can I make my Blazor Web App save the login infor entered as it would in InteractiveServer but still be able to use the HttpContext for login?


I'm trying to create a Blazor login page that uses cookies, but without rendermode InteractiveServer, the information I enter on the form won't be saved and sent. If I turn it on, SignalR will make HttpContext null. I tried leaving the data available without import and turning off rendermode, it worked perfectly. Can someone help me how to make rendermode and SignalR make HttpContext not null or is there any other way to login with SignalR using Cookie? How can I make the website work? Sorry for my bad English. Here is my Login.razor:

@page "/Account/Login"

@using System.ComponentModel.DataAnnotations
@using DBDATA.Models
@using MUDTEMPLATE.Services
@using System.Security.Claims
@using Microsoft.AspNetCore.Authentication
@using Microsoft.AspNetCore.Authentication.Cookies

@inject INguoidungService nguoiDungService
@inject NavigationManager NavigationManager
@inject IHttpContextAccessor _httpContectAccessor

@rendermode InteractiveServer

<div class="row">
    <div class="col-lg-4 offset-lg-4 pt-4 pb border">
        <EditForm Model="@Model" OnValidSubmit="Auth" FormName="LoginForm">
            <DataAnnotationsValidator />
            <div class="mb-3 text-center flex-column">
                <h3>Login</h3>
            </div>
            <div class="mb-3">
                <label>User Name</label>
                <InputText @bind-Value="Model.Name" class="form-control" placeholder="Username"></InputText>
                <ValidationMessage For="() => Model.Name" />
            </div>
            <div class="mb-3">
                <label>User Name</label>
                <InputText @bind-Value="Model.Pass" class="form-control" placeholder="Password"></InputText>
                <ValidationMessage For="() => Model.Pass"/>
            </div>
            <div class = "mb-3 text-center">
                @if(!string.IsNullOrEmpty(errorMessage)){
                    <span class="text-danger">errorMessage</span>
                }  
            </div>
            <div class="mb-3 d-grid gap-2">
                <button type="submit" class="btn btn-primary">Login</button>
            </div>
        </EditForm>
    </div>
</div>

@code{
    public class LoginVM
    {
        [Required(ErrorMessage = "Name cannot null")]
        public string? Name { get; set; }// = "quyet";
        [Required(ErrorMessage = "Pass cannot null")]
        public string? Pass { get; set; }// = "123456";
    }

    public LoginVM Model = new();

    private string? errorMessage;

    [CascadingParameter]
    public HttpContent httpContent { get; set; }

    private async Task Auth()
    {
        var user = await userService.FindByInfo(Model.Name, Model.Pass);
        if (user is null)
        {
            errorMessage = "Wrong information";
            return;
        }
        var claims = new List<Claim>
        {
            new Claim(ClaimTypes.Name, user.Name),
            new Claim(ClaimTypes.Role, user.Role)
        };

        var identity = new ClaimsIdentity(claims, CookieAuthenticationDefaults.AuthenticationScheme);
        var principal = new ClaimsPrincipal(identity);
        await _httpContectAccessor.HttpContext.SignInAsync(principal);
        NavigationManager.NavigateTo("/");
    }
}

Solution

  • Editform works in SSR. Just delete @rendermode InteractiveServer and replace the "public LoginVM Model = new();" with following:

        [SupplyParameterFromForm]
        public LoginVM Model { get; set; }
        protected override void OnInitialized() => Model ??= new();
    

    Then the "Model" won't be null after submit.

    Reference: https://learn.microsoft.com/en-us/aspnet/core/blazor/forms/?view=aspnetcore-8.0#input-components-and-forms