简体   繁体   中英

ASP.NET Core WebApi Authentication with Identity

Okay let me start by saying that I'm rather new to ASP.NET Core and web development in general. Though I did some minor projects in the past.
I'm at a point where I'm pretty much lost and can't figure out what my issue is. I hope you can at least point me in the right direction.

What I want to do

TLDR: Authenticate and authorize a Blazor app with a WebApi

I want to create a Blazor WebAssembly app hosted by an ASP.Core 5 App. Business Logic will get executed by another WebApi.

So I have 3 relevant projects:

  • WebClient (Frontend)
  • WebHost (Host for WebClient)
  • WebApi (Backend)

The WebHost is just meant to be hosted in a docker container which will run behind a reverse proxy. So everything I do is running on http locally.

Blazor communicates with the Backend over WebApi ApiController (REST Api).

The Frontend has some areas which will need user authentication and authorization. The WebApi is meant to take care of this.

And here goes my problem.


What I've done

I've added the IdentityService to my WebApi with customized IdentityUser , IdentityRole , IUserStore and so on.
When I test my Api with Swagger the registration, login, changing password etc works just fine.

My Issue: The login is not remembered by the WebApi. That means I can log in and my SignInManager tells me everything is cool but the controller won't know anything about the User when I call an endpoint the next time.
When I successfully call the login endopint there is a cookie stored in the browser. When I check the HttpContext on my Backend I can see the cookie.


Implementation Details

I've tried to keep the snippets short and stripped unrelevant parts.

Startup Configure Method

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

app.UseSwagger();
app.UseSwaggerUI(...);

app.UseEndpoints(x => x.MapControllers());

Startup ConfigureServices Method

services.AddControllers();
services.AddSwaggerGen(...);

services.AddScoped<IUserManager, AppUserManager>();
services.AddScoped<ISignInManager, AppSignInManager>();
services.AddTransient<IUserStore<AppUser>, AppUserStore>();
services.AddTransient<IRoleStore<AppRole>, AppRoleStore>();
services.AddIdentity<AppUser, AppRole>()
        .AddDefaultTokenProviders();
services.Configure<IdentityOptions>(...);

services.AddHttpContextAccessor();
services.AddAuthentication();
services.AddAuthorization();

Auth Controller Endpoint

[HttpPost(nameof(Login))]
public async Task<IActionResult> Login([FromBody] LoginUserCommand command)
{
    // I've abstracted my logic into a Mediator Command
    // but simplified this is just
    // SignInManager.PasswordSignInAsync(user, pass, rememberMe)
    // ClaimsFactory.CreateAsync(user)
    var result = await Mediator.Send(command); 

    if (result.Succeeded)
    {
        // I've tried the following 2 methods to store the ClaimsPrincipal with no success
        await HttpContext.SignInAsync(result.Data);
        var signInResult = SignIn(result.Data); // positive result

        return Ok(...);
    }

    return BadRequest(...);
}

The POST request made by swagger

curl -X POST "http://localhost:4000/_api/v1/Auth/Login"
     -H "accept: */*"
     -H "Content-Type: application/json"
     -d "{\"password\":\"P4$$w0rd\",\"rememberMe\":true,\"username\":\"admin\"}"

The Cookie stored in the Browser

Name: Identity.External
Content: CfDJ8EGl21FYRChCvuGjMRYlEqvNaCBZMxNrNE8D [...]
Domain: localhost
Path: /
Created: 5 minutes ago
Expires: When the browsing session ends

Try adding the cookie scheme when you use the authentication service:

        services.AddAuthentication(options =>
        {
            options.DefaultChallengeScheme = CookieAuthenticationDefaults.AuthenticationScheme;
            options.DefaultAuthenticateScheme = CookieAuthenticationDefaults.AuthenticationScheme;
            options.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme;
        }).AddCookie(CookieAuthenticationDefaults.AuthenticationScheme);

Then, when you sign in use that same scheme:

        var claimsIdentity = new ClaimsIdentity(
            claims, CookieAuthenticationDefaults.AuthenticationScheme);

        var authProperties = new AuthenticationProperties
        {
            IsPersistent = true,
        };

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM