简体   繁体   中英

ASP.NET Core 2.1 Jwt Authentication Token not recognised

I am trying to implement Jwt Authentication for my application and so far I have managed to generate the token and when I decoded it, it looks fine. However, when I use Postman to try to access areas of my code that is for Authorized only, I get an UnAuthorized error. I have discovered that its because of a setting in the Startup.cs.

Startup.cs

var key = Encoding.ASCII.GetBytes(Configuration["JwtAuthentication:SecurityKey"]);
services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
.AddJwtBearer(x =>
{
    x.RequireHttpsMetadata = false;
    x.SaveToken = true;
    x.TokenValidationParameters = new TokenValidationParameters
    {
        ValidateIssuerSigningKey = true,
        IssuerSigningKey = new SymmetricSecurityKey(key),
        ValidIssuer = Configuration["JwtAuthentication:Issuer"],
        ValidateIssuer = true,
        ValidateLifetime = true,
        ValidateAudience = true
    };
});

If I set ValidateIssuer to false, I can get access to the [Authorized] controller, otherwise it will block me from it. Also, ValidateLifeTime doesn't seem to work for me. It will continue to show the result even though the token has expired.

This is how I generate my token in another class

public class GenerateToken : Controller
{
    private IConfiguration configuration;
    public GenerateToken(IConfiguration configuration)
    {
        this.configuration = configuration;
    }

    public String Generate(GenerateTokenViewModel Input)
    {
        var tokenHandler = new JwtSecurityTokenHandler();
        List<Claim> claims = new List<Claim>();
        claims.Add(new Claim("UserName", Input.User.UserName));
        claims.Add(new Claim("Email", Input.User.Email));
        claims.Add(new Claim("PhoneNumber", Input.User.PhoneNumber));
        claims.Add(new Claim("FirstName", Input.User.FirstName));
        claims.Add(new Claim("LastName", Input.User.LastName));
        claims.Add(new Claim("Id", Input.User.Id));
        foreach (var item in Input.Roles)
        {
            var currentItem = new UserRoleDetailsViewModel
            {
                Id = item.Id,
                Name = item.Name,
                ApplicationId = item.ApplicationId,
                ApplicationName = item.ApplicationName
            };
            var convertedItem = JsonConvert.SerializeObject(currentItem);
            claims.Add(new Claim("Roles", convertedItem));
        }

        var key = Encoding.ASCII.GetBytes(configuration["JwtAuthentication:SecurityKey"]);
        var tokenDescriptor = new SecurityTokenDescriptor
        {
            Subject = new ClaimsIdentity(claims),
            Issuer = configuration["JwtAuthentication:Issuer"],
            Audience = configuration["JwtAuthentication:Audience"],
            IssuedAt = DateTime.UtcNow,
            NotBefore = DateTime.UtcNow,
            Expires = DateTime.UtcNow.AddDays(7),
            SigningCredentials = new SigningCredentials(new SymmetricSecurityKey(key), SecurityAlgorithms.HmacSha256Signature)
        };
        var token = tokenHandler.CreateToken(tokenDescriptor);
        var output = tokenHandler.WriteToken(token);
        return output;
    }
}

I'm not sure what I can do to solve it. Alternatively, is there a guide to generating and validating jwt for .net core 2.1?

EDIT:

Added Controller

[Authorize]
[Route("api/[controller]")]
[ApiController]
public class AccountsController : ControllerBase
{
    private AccountsData accountsData;
    private readonly ILogger<AccountsController> logger;
    private UserRolesData userRolesData;
    private GenerateToken generateToken;
    public AccountsController(ILogger<AccountsController> logger, GenerateToken generateToken, AccountsData accountsData, UserRolesData userRolesData)
    {
        this.accountsData = accountsData;
        this.logger = logger;
        this.userRolesData = userRolesData;
        this.generateToken = generateToken;
    }

    [HttpGet]
    [AllowAnonymous]
    [Route("Item")]
    public ActionResult Item()
    {
        return Ok("test");
    }

    [HttpGet]
    [Route("GetThis")]
    public ActionResult<IEnumerable<string>> Get()
    {
        return new string[] { "value1", "value2" };
    }

    [HttpPost]
    [AllowAnonymous]
    [Route("Authenticate")]
    public ActionResult Authenticate([FromBody]AccountsDto Input)
    {
        LoginViewModel lvm = new LoginViewModel
        {
            Email = Input.Email,
            Password = Input.Password
        };
        var user = accountsData.Authenticate(lvm);
        var token = "";
        if(user == null)
        {
            return NotFound(LoggingGlobals.NotFound);
        }
        else
        {
            var roles = userRolesData.GetUserRoles(user.Id);
            GenerateTokenViewModel gtvm = new GenerateTokenViewModel
            {
                User = user,
                Roles = roles
            };
            token = generateToken.Generate(gtvm);
        }
        return Ok(token);
    }

}

I am not entirely sure what is causing the problem you are facing. I did notice that you have ValidateAudience = true but do not provide a ValidAudience .

In any case, here is a demo that does work. You can find it on GitHub here . These are the most relevant snippets of code.

Startup.cs

public void ConfigureServices(IServiceCollection services)
{
    services.AddMvc();

    var key = Encoding.ASCII.GetBytes("this-is-the-secret");
    services
        .AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
        .AddJwtBearer(x =>
        {
            x.RequireHttpsMetadata = false;
            x.SaveToken = true;
            x.TokenValidationParameters = new TokenValidationParameters
            {
                IssuerSigningKey = new SymmetricSecurityKey(key),
                ValidateIssuerSigningKey = true,
                // 
                ValidIssuer = "my-auth-server",
                ValidateIssuer = true,
                // 
                ValidAudience = "my-resource-server",
                ValidateAudience = true,
                //
                ValidateLifetime = true,
            };
        });
}

ValuesController.cs

public class ValuesController : ControllerBase
{
    [HttpGet("/api/values")]
    [Authorize(AuthenticationSchemes = JwtBearerDefaults.AuthenticationScheme)]
    public ActionResult<string> Values()
    {
        return $"You have authorized access";
    }

    [HttpGet("/api/jwt")]
    public ActionResult<string> Jwt()
    {
        var key = new SymmetricSecurityKey(Encoding.ASCII.GetBytes("this-is-the-secret"));
        var descriptor = new SecurityTokenDescriptor
        {
            Subject = new ClaimsIdentity(new Claim[] { /* add claims */}),
            Issuer = "my-auth-server",
            Audience = "my-resource-server",
            SigningCredentials =
                new SigningCredentials(key, SecurityAlgorithms.HmacSha256Signature),
            IssuedAt = DateTime.Now,
            NotBefore = DateTime.Now,
            Expires = DateTime.Now.AddDays(1)
        };

        var jwtHandler = new JwtSecurityTokenHandler();
        var token = jwtHandler.CreateToken(descriptor);
        return jwtHandler.WriteToken(token);

        // alternatively
        // return jwtHandler.CreateEncodedJwt(descriptor);
    }
}      

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