0
votes

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.

1
Your question is all-inclusive... You should ask specific questions. As for instance...see your previous question, which I've quoted before answering it. And the title of your question should be in the form of a question...enet
Will try to be more specific, one challenge though is not having sufficient information to be able to ask the correct question. For example, its unclear to me if using Identity is even the appropriate solution. So my question is two fold 1) is aspnet identity the correct approach, and 2) if it is, how do I overcome the exception..user2179721
Where do the logged in users come from? Where did they login?Schwarzie2478
Auth happens withing the Blazor Server side app. Presently, I'm using AspNetCore.Identity to provide user management and auth implemented in the Blazor Server Side app to handle SignUp and SignIn. In this model, I've created a toy blazor page to handle both operations (see code in question). However setting signing in and trying to set the auth cookie results in an exception (Request already started). I am unclear if I'm missing something or if Identity isn't the correct way to go in the first place.user2179721
I wouldn't expect this to work: AspNetCore.Identity is built for (around) the HTTP request/response model. But Blazor isn't running on HTTP, setting the cookie is meaningless. You might be able to use some parts of Identtity, but not SignIn.Henk Holterman

1 Answers

1
votes

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.