user2179721
user2179721

Reputation:

Blazer Server Side + AspNetCore.Identity

How can I implement authentication in Blazor Server Side (Razor Components). I'm using .net 3 preview 5. I'm currently using AspNetCore.Identity. Registering users works fine, but calling any SignIn method causes an exception (Response already started).

Here's some code - its only toy/prototype, so its a bit of a mess/hack together. Will rewrite once I've proven to myself its actually possible to use Identity and Blazor Server Side!

@page "/signup"
@using System.Security.Claims
@using AuthProto.Data
@using AuthProto.Entities
@using Microsoft.AspNetCore.Authentication
@using Microsoft.AspNetCore.Authentication.Cookies
@using Microsoft.AspNetCore.Http
@using Microsoft.AspNetCore.Http.Extensions
@using Microsoft.AspNetCore.Identity
@using Microsoft.AspNetCore.Identity.EntityFrameworkCore
@inject WeatherForecastService ForecastService
@inject SignInManager<AppUser> SignInManager
@inject UserManager<AppUser> UserManager
@inject UserDb db;
<h1>Signup</h1>

<h2>@message</h2>
<EditForm Model="@data" OnValidSubmit="@HandleValidSubmit">
    <DataAnnotationsValidator />
    <ValidationSummary />

    <InputText id="name" bind-Value="@data.Email" />
    <InputText id="password" bind-Value="@data.Password" />

    <button type="submit">Submit</button>
</EditForm>
<h2>Login</h2>
<EditForm Model="@login" OnValidSubmit="@HandleLogin">
    <DataAnnotationsValidator />
    <ValidationSummary />

    <InputText id="name" bind-Value="@login.email" />
    <InputText id="password" bind-Value="@login.password" />

    <button type="submit">Submit</button>
</EditForm>

@functions {

    private SignupApi data = new SignupApi();
    private LoginApi login = new LoginApi();
    private string message;

    WeatherForecast[] forecasts;

    protected override async Task OnInitAsync()
    {
        forecasts = await ForecastService.GetForecastAsync(DateTime.Now);
    }

    private void HandleValidSubmit()
    {
        var user = new AppUser() { Email = data.Email, UserName = data.Email };
        IdentityResult result = UserManager.CreateAsync(user, data.Password).Result;

        if (result.Succeeded)
        {
            message = string.Format("User {0} was created successfully!", user.UserName);

            //   var signInResult = SignInManager.PasswordSignInAsync(
            //     user, data.Password, false, false).Result;
        }
        else
        {
            message = result.Errors.FirstOrDefault()?.Description;
        }
    }

    private async void HandleLogin()
    {
        var x = db.Users.SingleOrDefault(u => u.Email == data.Email);

        var result = SignInManager.CheckPasswordSignInAsync(x, data.Password, true).Result;
        await SignInManager.SignInAsync(x, true);
    }
}

I've also tried using the HttpAssessor to access HttpContext.SigninAsync manually - no exception but no cookie is set.

I'm guessing the problem is that Identity isnt currently compatable with Blazor Server Side, and the SignIn methods so something like start the response and then add to it later in the call. I presume this is causing a problem with SignalR communication back to the client.

Upvotes: 0

Views: 1777

Answers (1)

sufpapou
sufpapou

Reputation: 11

Identity is included in Blazor project model so I assume it's the good way to authenticate. Therefore, you still need a C# class SignInManager to provide your authentication behaviour (it must be set in the Startup.cs file, in the ConfigureService method) As it inherits from the SignInManager interface, it has a Context property which corresponds to the HttpContext. It can be used to carry ClaimsPrincipal and cookies details. For cookies though, you'll need to add the good service in Startup.cs :

service.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme)
.AddCookie(CookieAuthenticationDefaults.AuthenticationScheme);

Startup.cs exemple I used this to create a new application where database is not used for authentication, and it works.

Upvotes: 1

Related Questions