简体   繁体   中英

ASP.Net Core 3.0 JWT Bearer Token No SecurityTokenValidator available

I am using a ASP.Net Core 3.0 API with EntityFramework Core as UserStorage. Startup.cs:

        public void ConfigureServices(IServiceCollection services)
            {
             using Microsoft.AspNetCore.Authentication.JwtBearer;
             using Microsoft.AspNetCore.Builder;
             using Microsoft.AspNetCore.Hosting;
             using Microsoft.AspNetCore.Identity;
             using Microsoft.AspNetCore.SpaServices.AngularCli;
             using Microsoft.EntityFrameworkCore;
             using Microsoft.Extensions.Configuration;
             using Microsoft.Extensions.DependencyInjection;
             using Microsoft.Extensions.Hosting;
             using Microsoft.IdentityModel.Tokens;
             using System;
             using System.Collections.Generic;
             using System.Linq;
             using System.Text;
             using System.Threading.Tasks;
                .
                .
                .

                //Add Identity Provider with EntityFramework
                services.AddIdentity<User, IdentityRole>()
                .AddEntityFrameworkStores<ApplicationDBContext>()
                .AddDefaultTokenProviders();

                //Initialize EntityFramework
                services.AddDbContext<ApplicationDBContext>(options => options.UseSqlite(Configuration.GetConnectionString("localDB")));

                //Initialize JWT Authentication
                services.AddAuthentication(options => {
                    options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
                    options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
                }).AddJwtBearer(jwtBearerOptions =>
                {
                    jwtBearerOptions.TokenValidationParameters = new TokenValidationParameters()
                    {
                        ValidateIssuer = true,
                        ValidateAudience = true,
                        ValidateLifetime = true,
                        ValidateIssuerSigningKey = true,

                        ValidIssuer = "http://localhost:44352",
                        ValidAudience = "http://localhost:44352",
                        IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(Configuration.GetSection("Secrets")["jwt"]))
                    };
                }
                );
                services.AddMvc(options => options.EnableEndpointRouting = false)
                    .AddNewtonsoftJson();

                // In production, the Angular files will be served from this directory
                services.AddSpaStaticFiles(configuration =>
                {
                    configuration.RootPath = "ClientApp/dist";
                });
            }

            .
            .
            .


                app.UseHttpsRedirection();
                app.UseStaticFiles();
                app.UseSpaStaticFiles();

                //Enable Authentication
                app.UseAuthentication();
                app.UseAuthorization();

                .
                .
                .

                app.UseMvc(routes =>
                {
                    routes.MapRoute(
                        name: "default",
                        template: "{controller}/{action=Index}/{id?}");
                });


    .
    .
    .

This is my code issuing a JWT token:


public async Task<IActionResult> Login()
        {
            using (var reader = new StreamReader(Request.Body))
            {
                var body = await reader.ReadToEndAsync();
                var cred = JsonConvert.DeserializeObject<Credentials>(body);
                var result = (await userService.LoginUser(cred.userName, cred.password));
                if (result == 200)
                {

                    var secretKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(configuration.GetSection("Secrets")["jwt"]));
                    var signinCredentials = new SigningCredentials(secretKey, SecurityAlgorithms.HmacSha256Signature);

                    var roles = await userService.GetRoleFromUsername(cred.userName);
                    var rolesString = JsonConvert.SerializeObject(roles);

                    var tokeOptions = new JwtSecurityToken(
                                issuer: "http://localhost:44352",
                                audience: "http://localhost:44352",
                                claims: new List<Claim>(new List<Claim> {
                                        new Claim("userName",cred.userName),
                                        new Claim("roles", rolesString)
                                }),
                                expires: DateTime.Now.AddHours(1),
                                signingCredentials: signinCredentials
                    );

This is my API call using Authorization:


[Route("api/videos/add")]
[Authorize(Roles = "Admin")]
[HttpPost]
public async Task<IActionResult> AddVideo()
{
    using (var reader = new StreamReader(Request.Body))
    {
        var body = await reader.ReadToEndAsync();
        var video = JsonConvert.DeserializeObject<Video>(body);
        await videoService.AddVideo(video);
        return Ok();
    }
}

My NuGet Packages are:

  • Microsoft.EntityFrameworkCore {3.0.0-preview5.19227.1}
  • Microsoft.EntityFrameworkCore.Sqlite {3.0.0-preview5.19227.1}
  • Microsoft.AspNetCore.Authentication.JwtBearer {3.0.0-preview4-19216-03}
  • Microsoft.EntityFrameworkCore.Sqlite.Core {3.0.0-preview5.19227.1}
  • Microsoft.NETCore.Platforms {3.0.0-preview4.19212.13}
  • Microsoft.AspNetCore.Mvc.NewtonsoftJson {3.0.0-preview5-19227-01}
  • Microsoft.AspNetCore.SpaServices.Extensions {3.0.0-preview5-19227-01}
  • Microsoft.AspNetCore.Identity.EntityFrameworkCore {3.0.0-preview5-19227-01}
  • runtime.win-x64.Microsoft.NETCore.DotNetAppHost {3.0.0-preview4-27615-11}

The problem I have, is that if I call that API part, I get the error:

Information: Bearer was not authenticated. Failure message: No SecurityTokenValidator available for token:

Any help would be much appreciated, since I can't find the error

Try to use ClaimTypes.Role instead of roles if you want to add a Role as claim.

var tokeOptions = new JwtSecurityToken(
                            issuer: "http://localhost:44352",
                            audience: "http://localhost:44352",
                            claims: new List<Claim>(new List<Claim> {
                                    new Claim("userName",cred.userName),
                                    new Claim(ClaimTypes.Role, "Admin")                                      
                            }),
                            expires: DateTime.Now.AddHours(1),
                            signingCredentials: signinCredentials
                );

Thanks to Xing Zou, I got to the root of the error. The problem was that I sent the bearer token with quotation marks.

要求

The error in the API now is gone, the problem is that the authorization now fails in the API and it returns 403.

EDIT:

I found the issue concerning error 403. It seems that you are only allowed to send ONE role in the bearer token for ASP.Net to validate it. The return type of userManager.GetRolesAsync suggests that a user can have multiple roles which can be included in a JWT bearer token.

That means my issue is fixed.

I want to thank everybody for their answers. I would not have gotten it without you!

I managed this issue like this:

client.DefaultRequestHeaders.Add("Authorization", $"Bearer {token.Replace("\"", "")}");

Not the best solution, but it worked.

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