I am trying to authenticate my username and password with Jwt in ASP.NET Core but it gives me an error when executing it with Postman , I already created my connection string and called it in my startup , I also created my UserModel model and my LoginController controller in which This is all my method, where am I failing? What mistake am I making? I would like to test so that I can later connect it with my database and test with real data
this is my connection string
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft": "Warning",
"Microsoft.Hosting.Lifetime": "Information"
}
},
"AllowedHosts": "*",
"Jwt": {
"Key": "AshProgHelpSecretKey",
"Issuer": "ashproghelp.com"
}
}
this is my startup
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.HttpsPolicy;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using Microsoft.IdentityModel.Tokens;
using Microsoft.OpenApi.Models;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace JwtPrueba
{
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.AddControllers();
services.AddSwaggerGen(c =>
{
c.SwaggerDoc("v1", new OpenApiInfo { Title = "JwtPrueba", Version = "v1" });
});
services.AddCors(options =>
{
options.AddPolicy("CorsPolicy", builder => builder.AllowAnyOrigin().AllowAnyMethod().AllowAnyHeader().AllowCredentials().Build());
});
services.AddControllers();
services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
.AddJwtBearer(options =>
{
options.TokenValidationParameters = new TokenValidationParameters
{
ValidateIssuer = true,
ValidateAudience = true,
ValidateLifetime = true,
ValidateIssuerSigningKey = true,
ValidIssuer = Configuration["Jwt:Issuer"],
ValidAudience = Configuration["Jwt:Issuer"],
IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(Configuration["Jwt:Key"]))
};
});
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
app.UseSwagger();
app.UseSwaggerUI(c => c.SwaggerEndpoint("/swagger/v1/swagger.json", "JwtPrueba v1"));
}
app.UseHttpsRedirection();
app.UseRouting();
app.UseAuthentication();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
});
}
}
}
this is my model
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace JWTAuthDemo.Models
{
public class UserModel
{
public string UserName { get; set; }
public string Password { get; set; }
public string EmailAddres { get; set; }
}
}
this is my controller
using JWTAuthDemo.Models;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Http;
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.Security.Claims;
using System.Text;
using System.Threading.Tasks;
namespace JWTAuthDemo.Controllers
{
[Route("api/[controller]")]
[ApiController]
public class LoginController : ControllerBase
{
private IConfiguration _config;
public LoginController (IConfiguration config)
{
_config = config;
}
[HttpGet]
public IActionResult Login(string username,string pass)
{
UserModel login = new UserModel();
login.UserName = username;
login.Password = pass;
IActionResult response = Unauthorized();
var user = AuthenticateUser(login);
if(user !=null)
{
var tokenStr = GenerateJSONWebToken(user);
response = Ok(new { token = tokenStr });
}
return response;
}
private UserModel AuthenticateUser(UserModel login)
{
UserModel user = null;
if(login.UserName=="ashproghelp" && login.Password == "123")
{
user = new UserModel { UserName = "AshprogHelp", EmailAddres = "[email protected]", Password = "123" };
}
return user;
}
private string GenerateJSONWebToken(UserModel userinfo)
{
var securutyKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(_config["Jwt:Key"]));
var credentials = new SigningCredentials(securutyKey, SecurityAlgorithms.HmacSha256);
var claims = new[]
{
new Claim(JwtRegisteredClaimNames.Sub,userinfo.UserName),
new Claim(JwtRegisteredClaimNames.Email,userinfo.EmailAddres),
new Claim(JwtRegisteredClaimNames.Jti,Guid.NewGuid().ToString())
};
var token = new JwtSecurityToken(
issuer: _config["Jwt:Issuer"],
audience: _config["Jwt:Issuer"],
claims,
expires: DateTime.Now.AddMinutes(120),
signingCredentials: credentials);
var encodetoken = new JwtSecurityTokenHandler().WriteToken(token);
return encodetoken;
}
[Authorize]
[HttpPost("Post")]
public string Post()
{
var identity = HttpContext.User.Identity as ClaimsIdentity;
IList<Claim> claim = identity.Claims.ToList();
var userName = claim[0].Value;
return "BInevenido :" + userName;
}
[Authorize]
[HttpGet("GetValue")]
public ActionResult<IEnumerable<string>> Get()
{
return new string[] { "value1", "value2", "value3" };
}
}
}
error generated in postman
{
"type": "https://tools.ietf.org/html/rfc7235#section-3.1",
"title": "Unauthorized",
"status": 401,
"traceId": "00-e5297a6378850547b2d1f6b413649999-bec907f814c9bb4d-00"
}
The problem is in the call.
When using the GET method you should not include the parameters in the body of the request, but in the url as a query string.
Also, the action expects a named parameter
pass
and in the call you are using a propertyPassword
.The url should be:
https://localhost:44374/api/Login?username=ashproghelp&pass=123
Although this will work for you, it is not a good practice to use GET to send data such as passwords, as it is sent flat and is very easy to intercept. Better use an action with POST method.
To do this, simply change the attribute of the action to
HttpPost
and make it receive an object directly as a parameterUserModel
. Mark that parameter with the attributeFromBody
so that asp.net looks for it in the request body:In Postman's request use the POST method instead of GET and pass it, as you were doing, the login information in the request body:
P.S. Although it has nothing to do with it, and you won't have any problems with it, you call the method twice
AddControllers
in the Startup.Change the first claim in
GenerateJSONWebToken()
By
AND/OR you have to tell authorization that you want to use Jwt