JWT Authentication And Authorization In .NET 6.0 401Unauthorized Error - asp.net-core

i am creating a token and it does not accept the token I created, the error code 401 returns
appsettings.json
{
"TokenOptions": {
"Audience": "https://localhost:7098",
"Issuer": "https://localhost:7098",
"AccessTokenExpiration": 500,
"SecurityKey": "mysecretkeymysecretkey"
},
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning"
}
},
"AllowedHosts": "*"
}
TokenOptions.cs
namespace Shared.Utilities.Security.Jwt;
public class TokenOptions
{
public string Audience { get; set; }
public string Issuer { get; set; }
public int AccessTokenExpiration { get; set; }
public string SecurityKey { get; set; }
}
JwtHelper.cs
using System.IdentityModel.Tokens.Jwt;
using System.Security.Claims;
using Microsoft.Extensions.Configuration;
using Microsoft.IdentityModel.Tokens;
using Shared.Entities.Concrete;
using Shared.Extensions;
using Shared.Utilities.Security.Encyption;
namespace Shared.Utilities.Security.Jwt;
public class JwtHelper : ITokenHelper
{
public IConfiguration Configuration { get; }
private TokenOptions _tokenOptions;
private DateTime _accessTokenExpiration;
public JwtHelper(IConfiguration configuration)
{
Configuration = configuration;
_tokenOptions = Configuration.GetSection(key: "TokenOptions").Get<TokenOptions>();
}
public AccessToken CreateToken(User user, List<OperationClaim> operationClaims)
{
_accessTokenExpiration = DateTime.Now.AddMinutes(_tokenOptions.AccessTokenExpiration);
var securityKey = SecurityKeyHelper.CreateSecurityKey(_tokenOptions.SecurityKey);
var signingCredentials = SigningCredentialsHelper.CreateSigningCredentials(securityKey);
var jwt = CreateJwtSecurityToken(_tokenOptions, user, signingCredentials, operationClaims);
var jwtSecurityTokenHandler = new JwtSecurityTokenHandler();
var token = jwtSecurityTokenHandler.WriteToken(jwt);
return new AccessToken
{
Token = token,
Expiration = _accessTokenExpiration
};
}
public JwtSecurityToken CreateJwtSecurityToken(TokenOptions tokenOptions, User user, SigningCredentials signingCredentials, List<OperationClaim> operationClaims)
{
var Jwt = new JwtSecurityToken(
issuer: tokenOptions.Issuer,
audience: tokenOptions.Audience,
expires: _accessTokenExpiration,
notBefore: DateTime.Now,
claims: SetClains(user, operationClaims),
signingCredentials: signingCredentials
);
return Jwt;
}
private IEnumerable<Claim> SetClains(User user, List<OperationClaim> operationClaims)
{
var claims = new List<Claim>();
claims.AddNameIdentifier(user.Id.ToString());
claims.AddEmail(user.Email);
claims.AddName($"{user.FirstName} {user.LastName}");
claims.AddRole(operationClaims.Select(c => c.Name).ToArray());
return claims;
}
}
ITokenHelper.cs
using Shared.Entities.Concrete;
namespace Shared.Utilities.Security.Jwt;
public interface ITokenHelper
{
AccessToken CreateToken(User user, List<OperationClaim> operationClaims);
}
AccessToken.cs
namespace Shared.Utilities.Security.Jwt
{
public class AccessToken
{
public string Token { get; set; }
public DateTime Expiration { get; set; }
}
}
HashingHelper.cs
using System.Text;
namespace Shared.Utilities.Security.Hashing;
public class HashingHelper
{
public static void CreatePasswordHash(string password, out byte[] passwordHash, out byte[] passwordSalt)
{
using (var hmac = new System.Security.Cryptography.HMACSHA512())
{
passwordSalt = hmac.Key;
passwordHash = hmac.ComputeHash(Encoding.UTF8.GetBytes(password));
}
}
public static bool VerifyPasswordHash(string password, byte[] passwordHash, byte[] passwordSalt)
{
using (var hmac = new System.Security.Cryptography.HMACSHA512(passwordSalt))
{
var computedHash = hmac.ComputeHash(Encoding.UTF8.GetBytes(password));
for (int i = 0; i < computedHash.Length; i++)
{
if (computedHash[i] != passwordHash[i])
{
return false;
}
}
}
return true;
}
}
SigningCredentialsHelper.cs
using Microsoft.IdentityModel.Tokens;
namespace Shared.Utilities.Security.Encyption;
public class SigningCredentialsHelper
{
public static SigningCredentials CreateSigningCredentials(SecurityKey securityKey)
{
return new SigningCredentials(securityKey, SecurityAlgorithms.HmacSha256Signature);
}
}
SecurityKeyHelper.cs
using System.Text;
using Microsoft.IdentityModel.Tokens;
namespace Shared.Utilities.Security.Encyption;
public class SecurityKeyHelper
{
public static SecurityKey CreateSecurityKey(string securityKey)
{
return new SymmetricSecurityKey(Encoding.UTF8.GetBytes(securityKey));
}
}
ClaimExtensions.cs
using System.Security.Claims;
using Microsoft.IdentityModel.JsonWebTokens;
namespace Shared.Extensions;
public static class ClaimExtensions
{
public static void AddEmail(this ICollection<Claim> claims, string email)
{
claims.Add(new Claim(type: JwtRegisteredClaimNames.Email, value: email));
}
public static void AddName(this ICollection<Claim> claims, string name)
{
claims.Add(new Claim(type: ClaimTypes.Name, value: name));
}
public static void AddNameIdentifier(this ICollection<Claim> claims, string nameIdentifier)
{
claims.Add(new Claim(type: ClaimTypes.NameIdentifier, value: nameIdentifier));
}
public static void AddRole(this ICollection<Claim> claims, string[] roles)
{
roles.ToList().ForEach(role => claims.Add(new Claim(type: ClaimTypes.Role, value: role)));
}
}
AutofacBusinessModule.cs
using Autofac;
using Data.Abstract;
using Data.Concrete.EntityFramework;
using Services.Abstract;
using Services.Concrete;
using Shared.Utilities.Security.Jwt;
namespace Services.DependencyResolvers.Autofac
{
public class AutofacBusinessModule : Module
{
protected override void Load(ContainerBuilder builder)
{
builder.RegisterType<ProductManager>().As<IProductService>();
builder.RegisterType<EfProductRepository>().As<IProductRepository>();
builder.RegisterType<CategoryManager>().As<ICategoryService>();
builder.RegisterType<EfCategoryRepository>().As<ICategoryRepository>();
builder.RegisterType<UserManager>().As<IUserService>();
builder.RegisterType<EfUserRepository>().As<IUserRepository>();
builder.RegisterType<AuthManager>().As<IAuthService>();
builder.RegisterType<JwtHelper>().As<ITokenHelper>();
}
}
}
AuthController.cs
using Entities.Dtos;
using Microsoft.AspNetCore.Mvc;
using Services.Abstract;
namespace WebAPI.Controllers
{
[Route("api/[controller]")]
[ApiController]
public class AuthController : ControllerBase
{
private IAuthService _authService;
public AuthController(IAuthService authService)
{
_authService = authService;
}
[HttpPost("login")]
public async Task<IActionResult> Login(UserForLoginDto userForLoginDto)
{
var userToLogin = await _authService.Login(userForLoginDto);
if (!userToLogin.IsSuccess)
return BadRequest(userToLogin.Message);
var result = await _authService.CreateAccessToken(userToLogin.Data);
if (result.IsSuccess)
return Ok(result.Data);
return BadRequest(result.Message);
}
[HttpPost("register")]
public async Task<IActionResult> Register(UserForRegisterDto userForRegisterDto)
{
var userExists = await _authService.UserExists(userForRegisterDto.Email);
if (!userExists.IsSuccess)
return BadRequest(userExists.Message);
var registerResult = await _authService.Register(userForRegisterDto);
var result = await _authService.CreateAccessToken(registerResult.Data);
if (result.IsSuccess)
return Ok(result.Data);
return BadRequest(result.Message);
}
}
}
Program.cs
using Autofac;
using Autofac.Extensions.DependencyInjection;
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.IdentityModel.Tokens;
using Services.DependencyResolvers.Autofac;
using Shared.Utilities.Security.Encyption;
using Shared.Utilities.Security.Jwt;
var builder = WebApplication.CreateBuilder(args);
builder.Host.UseServiceProviderFactory(new AutofacServiceProviderFactory()).ConfigureContainer<ContainerBuilder>(builder =>
{
builder.RegisterModule(new AutofacBusinessModule());
});
var tokenOptions = builder.Configuration.GetSection(key: "TokenOptions").Get<TokenOptions>();
builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme).AddJwtBearer(options =>
{
options.TokenValidationParameters = new TokenValidationParameters
{
ValidIssuer = tokenOptions.Issuer,
ValidAudience = tokenOptions.Audience,
IssuerSigningKey = SecurityKeyHelper.CreateSecurityKey(tokenOptions.SecurityKey),
ValidateIssuerSigningKey = true,
ValidateAudience = true,
ValidateIssuer = true,
ValidateLifetime = true,
ClockSkew = TimeSpan.Zero
};
});
builder.Services.AddControllers();
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();
var app = builder.Build();
if (app.Environment.IsDevelopment())
{
app.UseSwagger();
app.UseSwaggerUI();
}
app.UseHttpsRedirection();
app.UseAuthentication();
app.UseAuthorization();
app.MapControllers();
app.Run();
CreateTokenPostman.cs
enter image description here
401ErrorPostman.cs
enter image description here

Thanks. I found the error related to the latest version of JWT. The error was fixed when I downloaded the old version of JWT.
The version I used is 6.0.7:
<PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="6.0.7" />

I have compared your code with this repo. And I find something, it maybe useful to you.
You should change your code like below.
options.TokenValidationParameters = new TokenValidationParameters
{
ValidIssuer = tokenOptions.Issuer,
ValidAudience = tokenOptions.Audience,
IssuerSigningKey = SecurityKeyHelper.CreateSecurityKey(tokenOptions.SecurityKey),
ValidateIssuerSigningKey = true,
ValidateAudience = true,
ValidateIssuer = true,
ValidateLifetime = true,
//ClockSkew = TimeSpan.Zero
};
Or
options.TokenValidationParameters = new TokenValidationParameters
{
ValidIssuer = tokenOptions.Issuer,
ValidAudience = tokenOptions.Audience,
IssuerSigningKey = SecurityKeyHelper.CreateSecurityKey(tokenOptions.SecurityKey),
ValidateIssuerSigningKey = true,
ValidateAudience = true,
ValidateIssuer = true,
ValidateLifetime = true,
ClockSkew = TimeSpan.Zero,
// add this line
RequireExpirationTime = true
};

Related

.Net Core microservice and inspecting Cognito JWT claims for use in authorization

I am developing a .net service that I am passing a Cognito generated JWT in the client that has a group claim that I hope to use to restrict API access as the JWT is passed in as a Bearer token with each API call from the front-end. e.g.
"cognito:groups":["Guest"]
In my code now I have added:
services.AddAuthentication(DefaultScheme = JwtBearerDefaults.AuthenticationScheme)
.AddJwtBearer(options =>
{
options.TokenValidationParameters = new TokenValidationParameters
{
ValidateAudience = false,
RoleClaimType = "cognito:groups"
};
});
I have setup up my roles and my permissions using the HeimGuard project. In testing as I change roles in the Bearer token none of my APIs that restrict access to Guest do not deny access when decorated with [Authorize]. So, nothing is restricted. Any thoughts or ideas you have in how to solve this problem helps immensly. Thank you!!
I tried custom AuthorizeAttribute as below:
To create the Token:
public class UserModel
{
public string Username { get; set; }
public string Role { get; set; }
public string EmailAddress { get; set; }
public string PassWord { get; set; }
public string Right { get; set; }
}
[HttpPost]
public IActionResult Authenticate(UserModel someuser)
{
var claims = new Claim[]
{
new Claim(JwtRegisteredClaimNames.Jti, Guid.NewGuid().ToString()),
new Claim(ClaimTypes.Role, someuser.Role),
new Claim(ClaimTypes.Name, someuser.Username),
new Claim("Right", someuser.Right)
};
var securityKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(_config["Jwt:Key"]));
var credentials = new SigningCredentials(securityKey, SecurityAlgorithms.HmacSha256);
var token = new JwtSecurityToken(
_config["Jwt:Issuer"],
_config["Jwt:Issuer"],
signingCredentials: credentials,
expires: DateTime.Now.AddMinutes(2),
claims: claims
);
string jwtToken = new JwtSecurityTokenHandler().WriteToken(token);
return Content(jwtToken);
}
codes in appsettings.json:
"Jwt": {
"Key": "ThisismySecretKey",
"Issuer": "Test.com"
}
Custom requirement:
public class WriteRequirement : AuthorizationHandler<WriteRequirement>, IAuthorizationRequirement
{
protected override Task HandleRequirementAsync(AuthorizationHandlerContext context, WriteRequirement requirement)
{
var right = context.User.FindFirst("Right").Value;
if(right=="Write")
{
context.Succeed(requirement);
}
else
{
context.Fail();
}
return Task.CompletedTask;
}
}
in startup class:
public void ConfigureServices(IServiceCollection services)
{
...
services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
.AddJwtBearer(options =>
{
options.TokenValidationParameters = new TokenValidationParameters
{
ValidateIssuer = false,
ValidateAudience = false,
ValidateLifetime = false,
ValidateIssuerSigningKey = false,
ValidIssuer = Configuration["Jwt:Issuer"],
ValidAudience = Configuration["Jwt:Issuer"],
IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(Configuration["Jwt:Key"]))
};
});
services.AddSingleton<IAuthorizationHandler, WriteRequirement>();
services.AddAuthorization(opyions => { opyions.AddPolicy("Write", policy => policy.Requirements.Add(new WriteRequirement())); });
...
}
The Action need Authrization:
[HttpGet]
[Authorize(Roles ="Admin")]
[Authorize(Policy="Write")]
public ActionResult<IEnumerable<string>> Get()
{
return new string[] { "value1", "value2", "value3", "value4", "value5" };
}
The Result:

how to solve 401 unauthorized error in postman when calling a .Net API

I have a .net core webapi working fine and tested with swagger, also the method has set to allow anonymous access so no authentication should be required. But when testing the POST method with Postman, I always get the 401 error.. Appreciate any help!
Since I am not clear about your specific code implementation, I wrote a demo here, which is an example of generating token from user login to access permission API. You can refer to it, maybe it will help you a little:
First,open the appsettings.json file and change the section named Jwt:
"Jwt": {
"Issuer": "testUser",
"Audience": "user",
"Key": "this is my custom Secret key for authnetication"
}
Enable the JWT authentication scheme and swagger authorization configuration when the configuration starts, the entire code is as follows:
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.IdentityModel.Tokens;
using Microsoft.OpenApi.Models;
using System;
using System.Collections.Generic;
using System.IO;
using System.Reflection;
using System.Text;
using WebApplication129.Controllers.conf;
namespace WebApplication129
{
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
//services.AddSingleton<IConfiguration>(Configuration);
services.AddAuthentication(opt => {
opt.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
opt.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
})
.AddJwtBearer(options =>
{
options.TokenValidationParameters = new TokenValidationParameters
{
ValidateIssuer = true,
ValidateAudience = true,
ValidateLifetime = true,
ValidateIssuerSigningKey = true,
ValidIssuer = Configuration["Jwt:Issuer"],
ValidAudience = Configuration["Jwt:Audience"],
IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(Configuration["Jwt:Key"]))
};
});
services.AddControllers(options =>
{
options.Conventions.Add(new GroupingByNamespaceConvention());
});
services.AddSwaggerGen(config =>
{
config.AddSecurityDefinition("Bearer", new OpenApiSecurityScheme
{
Description =
"JWT Authorization header using the Bearer scheme. \r\n\r\n Enter 'Bearer' [space] and then your token in the text input below.\r\n\r\nExample: \"Bearer 12345abcdef\"",
Name = "Authorization",
In = ParameterLocation.Header,
Type = SecuritySchemeType.ApiKey,
Scheme = "Bearer",
BearerFormat="JWT"
});
config.AddSecurityRequirement(new OpenApiSecurityRequirement()
{
{
new OpenApiSecurityScheme
{
Reference = new OpenApiReference
{
Type = ReferenceType.SecurityScheme,
Id = "Bearer"
},
Scheme = "oauth2",
Name = "Bearer",
In = ParameterLocation.Header,
},
new List<string>()
}
});
var titleBase = "Test API";
var description = "This is a Web API for Test operations";
var TermsOfService = new Uri("https://xxxxxx");
var License = new OpenApiLicense()
{
Name = "MIT"
};
var Contact = new OpenApiContact()
{
Name = "Test",
Email = "Test#hotmail.com",
Url = new Uri("https://xxxxxx")
};
config.SwaggerDoc("v1", new OpenApiInfo
{
Version = "v1",
Title = titleBase + " v1",
Description = description,
TermsOfService = TermsOfService,
License = License,
Contact = Contact
});
config.SwaggerDoc("v2", new OpenApiInfo
{
Version = "v2",
Title = titleBase + " v2",
Description = description,
TermsOfService = TermsOfService,
License = License,
Contact = Contact
});
var xmlFile = $"{Assembly.GetExecutingAssembly().GetName().Name}.xml";
var xmlPath = Path.Combine(AppContext.BaseDirectory, xmlFile);
config.IncludeXmlComments(xmlPath);
});
}
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
app.UseSwagger();
app.UseSwaggerUI(config =>
{
config.SwaggerEndpoint("/swagger/v1/swagger.json", "Test v1");
//config.SwaggerEndpoint("/swagger/v2/swagger.json", "Test v2");
});
app.UseHttpsRedirection();
app.UseAuthentication();
app.UseRouting();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
});
}
}
}
Log in and generate the jwt part as follows. Since I did not use it with a database, I customized a user:
Model:
public class Usuario
{
public string NomeUsuario { get; set; }
public string Senha { get; set; }
}
Controller:
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Configuration;
using Microsoft.IdentityModel.Tokens;
using System;
using System.Collections.Generic;
using System.IdentityModel.Tokens.Jwt;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using WebApplication129.Model;
namespace WebApplication129.Controllers.V1
{
[Route("api/[controller]")]
[ApiController]
public class SegurancaController : Controller
{
private IConfiguration _config;
public SegurancaController(IConfiguration Configuration)
{
_config = Configuration;
}
[HttpPost]
[Route("login")]
public IActionResult Login([FromBody] Usuario loginDetalhes)
{
bool resultado = ValidarUsuario(loginDetalhes);
if (resultado)
{
var tokenString = GerarTokenJWT();
return Ok(new { token = tokenString });
}
else
{
return Unauthorized();
}
}
private string GerarTokenJWT()
{
var issuer = _config["Jwt:Issuer"];
var audience = _config["Jwt:Audience"];
var expiry = DateTime.Now.AddMinutes(120);
var securityKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(_config["Jwt:Key"]));
var credentials = new SigningCredentials(securityKey, SecurityAlgorithms.HmacSha256);
var token = new JwtSecurityToken(issuer: issuer, audience: audience,
expires: expiry, signingCredentials: credentials);
var tokenHandler = new JwtSecurityTokenHandler();
var stringToken = tokenHandler.WriteToken(token);
return stringToken;
}
private bool ValidarUsuario(Usuario loginDetalhes)
{
if (loginDetalhes.NomeUsuario == "TestName" && loginDetalhes.Senha == "TestPwd")
{
return true;
}
else
{
return false;
}
}
}
}
Test and verify API:
[ApiController]
[Route("api/v1/[controller]")]
public class HomeController : ControllerBase
{
/// <summary>
/// Add the description information you need
/// </summary>
///
///
[Route("test")]
[HttpGet]
public string Test( int userID)
{
return "v1 test";
}
[Route("list_data")]
[HttpGet]
[Authorize]
public Object Data()
{
User user = new User();
user.id = 1;
user.userName = "Test";
user.email = "test#xxx.com";
user.address = "testAddress";
return user;
}
}
The above shows two APIs, one requires authorization and the other does not require authorization to access.
Resutl:
Still If anyone can't figure out the error after #Tupac answer, check that you have included proper
app.UseAuthentication();
app.UseAuthorization();
in Program.cs file

Role based Authentication: Bearer Token to Cookie using Microsoft .NetCore 3.1

I'm trying to transform.NetCore 3.1 Code from Bearer Token implementation to Cookie-based implementation Also trying to make Role-based authorization work with existing code. Can you please help me to change this code? The below code shows currently how Bearer Token is retrieved and the next part shows how role-based authorization is implemented in code.
Here is the current Bearer Token implementation.
var key = Encoding.ASCII.GetBytes(Configuration["AppSettings:Secret"]);
var signingKey = new SymmetricSecurityKey(key);
services.AddAuthentication(x =>
{
x.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
x.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
})
.AddJwtBearer(x =>
{
x.RequireHttpsMetadata = false;
x.SaveToken = true;
x.TokenValidationParameters = new TokenValidationParameters
{
ValidateIssuerSigningKey = true,
ValidateLifetime = true,
IssuerSigningKey = signingKey,
ValidateIssuer = false,
ValidateAudience = false
};
});
Following annotation currently used for Role-based Authorization -
[Authorize(Roles = "1")]
[Route("api/[controller]")]
[ApiController]
public class JobLogsController : ControllerBase
{
private readonly EtpRepoContext _context;
private IJobLogsRepository _jobLogsRepository;
private IConfiguration _configuration;
public JobLogsController(EtpRepoContext context, IJobLogsRepository jobLogsRepository, IConfiguration configuration)
{
_context = context;
_jobLogsRepository = jobLogsRepository;
_configuration = configuration;
}
// GET: api/JobLogs
[HttpGet]
public async Task<ActionResult<IEnumerable<JobLog>>> GetJobLog()
{
return await _context.JobLog.ToListAsync();
}
// GET: api/JobLogs/5
[HttpGet("{id}")]
[ProducesResponseType(typeof(JobDetail), 200)]
[ProducesResponseType(typeof(string), 400)]
public IActionResult FindById([FromRoute] String id)
{
string contentStr = "";
try
{
if(id.Length >= 10)
{
contentStr = _jobLogsRepository.GetLogById(id);
}
else
{
contentStr = _jobLogsRepository.GetFileById(id);
}
var content = Newtonsoft.Json.JsonConvert.SerializeObject(new { content = contentStr });
return Ok(content);
}
catch (Exception ex)
{
return StatusCode(500, "Internal server error");
}
}
This is how the Microsoft identity model is used to claim the token.
public class ClaimsTransformer : IClaimsTransformation
{
public Task<ClaimsPrincipal> TransformAsync(ClaimsPrincipal principal)
{
ClaimsIdentity claimsIdentity = (ClaimsIdentity)principal.Identity;
// flatten realm_access because Microsoft identity model doesn't support nested claims
// by map it to Microsoft identity model, because automatic JWT bearer token mapping already processed here
if (claimsIdentity.IsAuthenticated && claimsIdentity.HasClaim((claim) => claim.Type == "identity"))
{
var realmAccessClaim = claimsIdentity.FindFirst((claim) => claim.Type == "identity");
dynamic realmAccessAsDict = JsonConvert.DeserializeObject<Object>(realmAccessClaim.Value);
string role = realmAccessAsDict.role.ToString();
claimsIdentity.AddClaim(new Claim("http://schemas.microsoft.com/ws/2008/06/identity/claims/role", role));
//var role = realmAccessClaim.
//var realmAccessAsDict = JsonConvert.DeserializeObject<Object>(realmAccessClaim.Value);
/*if (realmAccessAsDict["role"] != null)
{
foreach (var role in realmAccessAsDict["role"])
{
claimsIdentity.AddClaim(new Claim("http://schemas.microsoft.com/ws/2008/06/identity/claims/role", role));
}
}*/
}
return Task.FromResult(principal);
}
}
}

DOTNET CORE JWT Error converting value \"Username\" to type 'jwt_example.Model.LoginModel ERROR

I'm trying to write an API with dotnet core 3.1 + JWT.
I created LoginModel and authController when I try to get a token
postman says to me:
"Error converting value \"Username\" to type 'jwt_example.Model.LoginModel"
That is my authController code :
public class AuthController : ControllerBase
{
private UserManager<ApplicationUser> userManger;
public AuthController(UserManager<ApplicationUser> userManger)
{
this.userManger = userManger;
}
[HttpPost]
[Route("login")]
public async Task<IActionResult> Login([FromBody] LoginModel model)
{
var user = await userManger.FindByNameAsync((model.Username).ToString());
//var user = await
if (user != null && await userManger.CheckPasswordAsync(user, model.Password))
{
var claims = new List<Claim>
{
new Claim(JwtRegisteredClaimNames.Sub, user.UserName),
new Claim(JwtRegisteredClaimNames.Jti, Guid.NewGuid().ToString())
};
var signinKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes("ŞanlıFenerbahçe."));
JwtSecurityToken token = new JwtSecurityToken
(
issuer: "https://localhost:5001",
audience: "https://localhost:5001",
claims: claims,
signingCredentials: new SigningCredentials(signinKey, SecurityAlgorithms.HmacSha256),
expires: DateTime.Now.AddHours(1)
);
return Ok(new
{
token = new JwtSecurityTokenHandler().WriteToken(token),
expiration = token.ValidTo
});
}
else
{
return BadRequest(new
{
message = "Kullanıcı adı veya şifre hatalı!"
});
}
}
}
And, that is loginModel.cs:
public class LoginModel
{
[Required(ErrorMessage = "Kullanıcı adı boş geçilemez.")]
public string Username { get; set; }
[Required(ErrorMessage = "Parola boş geçilemez.")]
public string Password { get; set; }
}

asp.net core controller not authorize with jwt

I use Microsoft.AspNetCore.Authentication.JwtBearer Library for jwt authentication in ASP.Net Core Web Api.When i request a token, it work fine and i get a token.
But when i send request to secure Action i get 401 status code.
in my Startup Class:
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory,IOptionsSnapshot<SiteSettings> siteSettings)
{
var jwtOption = siteSettings.Value.JwtOption;
var tokenValidationParameters = new TokenValidationParameters
{
ValidateIssuer = true,
ValidIssuer = jwtOption.Issuer,
ValidateAudience = true,
ValidAudience = jwtOption.Audience,
ValidateIssuerSigningKey = true,
IssuerSigningKey = _signingKey,
RequireExpirationTime = false,
ValidateLifetime = false,
ClockSkew = TimeSpan.Zero
};
app.UseMvc();
app.UseApiCustomIdentityServices();
app.UseJwtBearerAuthentication(new JwtBearerOptions
{
AutomaticAuthenticate = true,
AutomaticChallenge = true,
Audience = jwtOption.Audience,
Authority = jwtOption.Audience,
RequireHttpsMetadata = false,
TokenValidationParameters = tokenValidationParameters
});
}
And my TokenController:
public class TokenController : Controller
{
private readonly IUserManager _userManager;
private readonly IJwtService _jwtService;
private readonly IOptionsSnapshot<SiteSettings> _siteSettings;
private readonly JsonSerializerSettings _serializerSettings;
public TokenController(
IUserManager userManager,
IJwtService jwtService,
IOptionsSnapshot<SiteSettings> siteSettings
)
{
_userManager = userManager;
_jwtService = jwtService;
_siteSettings = siteSettings;
_serializerSettings = new JsonSerializerSettings
{
Formatting = Formatting.Indented
};
}
[HttpPost]
public async Task<IActionResult> Post([FromBody]LoginViewModel model)
{
if (!ModelState.IsValid)
return BadRequest();
var identity = await GetClaimsIdentity(model.Username, model.Password);
if (identity == null)
{
return BadRequest();
}
var response = new
{
id = identity.Claims.Single(c => c.Type == "id").Value,
auth_token = await _jwtService.GenerateEncodedToken(model.Username, identity),
expires_in = (int)_siteSettings.Value.JwtOption.ValidFor.TotalSeconds
};
var json = JsonConvert.SerializeObject(response, _serializerSettings);
return new OkObjectResult(json);
}
private async Task<ClaimsIdentity> GetClaimsIdentity(string userName, string password)
{
if (!string.IsNullOrEmpty(userName) && !string.IsNullOrEmpty(password))
{
var userToVerify = await _userManager.FindByNameAsync(userName);
if (userToVerify != null)
{
if (await _userManager.CheckPasswordAsync(userToVerify, password))
{
return await Task.FromResult(_jwtService.GenerateClaimsIdentity(userName, userToVerify.Id.ToString()));
}
}
}
return await Task.FromResult<ClaimsIdentity>(null);
}
what's wrong?