简体   繁体   中英

Authenticate an User.Identity from JWT

I have API which return a JWT as string when we senc valid credentials to api/signin in POST method.

Now I want to connect my ASP.NET Core MVC application to this API to use the User.IsAuthenticated method and the [Authorize] annotation.

To do so, I'm trying to write a method which decodes the JWT and create claims to authenticate the user. Here is the given method:

private async void Authenticate(string token)
{
    //Ask API if the token is valid
    if(await ClientService.ValidateJWTAsync(token))
    {
        //Extract claims from token
        var tokenHandler = new JwtSecurityTokenHandler();
        var securityToken = tokenHandler.ReadToken(token) as JwtSecurityToken;

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

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

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

The idea behind this is, if the user try to access an [Authorize] View, he will be redirected to the /signin method (of the application, which displays a form then send the credentials to the api to get back a JWT). In this method, I check if the user has an httpOnly Cookie named "JWT" containing his JWToken.

If the user has this cookie, I send it to the Anthenticate method shown above. It allows me to avoid constantly making my users to enter their credentials if they have the JWT Cookie. If the httpOnly Cookie "JWT" does not exist, they will have to enter their credentials through the login form.

But when I try to execute this code, I have an error on the HttpContext.SignInAsync call:

System.ObjectDisposedException: 'IFeatureCollection has been disposed.'

I do not understand the problem here. Basically, the only configuration I added to my application is in the Startup.cs :

ConfigureServices method:

services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme).AddCookie("CookieAuthentication", config =>
{
    config.Cookie.Name = "UserLoginCookie";
    config.LoginPath = "/SignIn";
});

Configure method:

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

What should I do to authenticate my users from the JWT Cookie?

You can't use async void methods in the Controller if you plan to make use of the HttpContext. The HttpContext is not thread safe, and since you return a void the controller will not wait for your sign in to complete before returning and disposing the HttpContext.

This occurs because the the method returns to the caller at the first await and then the calling method will complete before the the rest of the async void method is executed.

Async void means "fire and forget", and that you don't care what happens afterwards. In this case you rely on what happens after the async method awaits, so you need to change this to an async task.

I would say additionally that it's almost never that you don't care what happens, and unless you have a very strong reason to do so, avoid using async void methods.

Change this:

private async void Authenticate(string token)

To this:

private async Task Authenticate(string token)

And make sure your controller methods are changed accordingly.

See here for more info: https://docs.microsoft.com/en-us/aspnet/core/performance/performance-best-practices?view=aspnetcore-3.1#do-not-use-the-httpcontext-after-the-request-is-complete

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