I am new in C# and struggling with the token based authorization from last 5 days. when i am passing hardcoded username and password my authorization is working but when i am accessing username and password from my authorization is not working.
here is my appsetting.json where i have mentioned username,password and secret key
{"UserCred":{
"Username":"test",
"Password":"test"
},
"AppSettings": {
"Secret": "This is my secret key"
},
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft": "Warning",
"Microsoft.Hosting.Lifetime": "Information"
}
},
"AllowedHosts": "*"
}
here is my UserService.cs where i am accessing the values from appsetting.json and generating the token. when i am passing the hardcoded values in private list object authorization working fine and when accessing from appsetting it does not working help me to accessing the values inside private list object if i acccess those values there it will work.
Services\UserService.cs
using Microsoft.Extensions.Options;
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 loginApi.Helpers;
using loginApi.Models;
using Microsoft.Extensions.Configuration;
namespace loginApi.Services
{
public interface IUserService
{
AuthenticateResponse Authenticate(AuthenticateRequest model);
IEnumerable<User> GetAll();
User GetById(string username);
}
public class UserService : IUserService
{
private List<User> _users = new List<User>
{
// new User { Username = "test", Password = "test" }
};
private readonly AppSettings _appSettings;
private readonly IConfiguration _configuration;
public UserService(IOptions<AppSettings> appSettings,IConfiguration configuration)
{
_appSettings = appSettings.Value;
_configuration = configuration;
}
public AuthenticateResponse Authenticate(AuthenticateRequest model)
{
var _username = _configuration.GetSection("UserCred").GetSection("Username").Value;
var _Password = _configuration.GetSection("UserCred").GetSection("Password").Value;
Console.WriteLine(_username.ToString());
Console.WriteLine(_Password.ToString());
_users = new List<User>
{
new User { Username = _username.ToString(), Password = _Password.ToString()}
};
var user = _users.SingleOrDefault(x => x.Username == model.Username && x.Password == model.Password);
if (user == null) return null;
var token = generateJwtToken(user);
return new AuthenticateResponse(user, token);
}
public IEnumerable<User> GetAll()
{
return _users;
}
public User GetById(string username)
{
return _users.FirstOrDefault(x => x.Username== username);
}
private string generateJwtToken(User user)
{
var tokenHandler = new JwtSecurityTokenHandler();
var key = Encoding.ASCII.GetBytes(_appSettings.Secret);
var tokenDescriptor = new SecurityTokenDescriptor
{
Subject = new ClaimsIdentity(new[] { new Claim("username", user.Username.ToString()) }),
Expires = DateTime.UtcNow.AddDays(7),
SigningCredentials = new SigningCredentials(new SymmetricSecurityKey(key), SecurityAlgorithms.HmacSha256Signature)
};
var token = tokenHandler.CreateToken(tokenDescriptor);
return tokenHandler.WriteToken(token);
}
}
}
i am attaching the whole code for reference
controllers\UsersController.cs
using Microsoft.AspNetCore.Mvc;
using loginApi.Models;
using loginApi.Services;
namespace loginApi.Controllers
{
[ApiController]
[Route("[controller]")]
public class UsersController : ControllerBase
{
private IUserService _userService;
public UsersController(IUserService userService)
{
_userService = userService;
}
[HttpPost("authenticate")]
public IActionResult Authenticate(AuthenticateRequest model)
{
var response = _userService.Authenticate(model);
if (response == null)
return BadRequest(new { message = "Username or password is incorrect" });
return Ok(response);
}
[Authorize]
[HttpGet]
public IActionResult GetAll()
{
var users = _userService.GetAll();
return Ok(users);
}
}
}
Helpers\AuthorizeAttribute.cs
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Filters;
using System;
using loginApi.Models;
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method)]
public class AuthorizeAttribute : Attribute, IAuthorizationFilter
{
public void OnAuthorization(AuthorizationFilterContext context)
{
var user = (User)context.HttpContext.Items["User"];
if (user == null)
{
context.Result = new JsonResult(new { message = "Unauthorized" }) { StatusCode = StatusCodes.Status401Unauthorized };
}
}
}
Helpers\JWTMiddleware.cs
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Options;
using Microsoft.IdentityModel.Tokens;
using System;
using System.IdentityModel.Tokens.Jwt;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using loginApi.Services;
using loginApi.Models;
namespace loginApi.Helpers
{
public class JwtMiddleware
{
private readonly RequestDelegate _next;
private readonly AppSettings _appSettings;
public JwtMiddleware(RequestDelegate next, IOptions<AppSettings> appSettings)
{
_next = next;
_appSettings = appSettings.Value;
}
public async Task Invoke(HttpContext context, IUserService userService)
{
var token = context.Request.Headers["Authorization"].FirstOrDefault()?.Split(" ").Last();
if (token != null)
attachUserToContext(context, userService, token);
await _next(context);
}
private void attachUserToContext(HttpContext context, IUserService userService, string token)
{
try
{
var tokenHandler = new JwtSecurityTokenHandler();
var key = Encoding.ASCII.GetBytes(_appSettings.Secret);
tokenHandler.ValidateToken(token, new TokenValidationParameters
{
ValidateIssuerSigningKey = true,
IssuerSigningKey = new SymmetricSecurityKey(key),
ValidateIssuer = false,
ValidateAudience = false,
ClockSkew = TimeSpan.Zero
}, out SecurityToken validatedToken);
var jwtToken = (JwtSecurityToken)validatedToken;
//var userId = int.Parse(jwtToken.Claims.First(x => x.Type == "id").Value);
var userName = jwtToken.Claims.First(x => x.Type == "username").Value;
context.Items["User"] = userService.GetById(userName);
}
catch
{
}
}
}
}
Models\Appsettings.cs
namespace loginApi.Models
{
public class AppSettings
{
public string Secret { get; set; }
}
}
Models\User.cs
using System.Text.Json.Serialization;
namespace loginApi.Models
{
public class User
{
public string Username { get; set; }
[JsonIgnore]
public string Password { get; set; }
}
}
Models\AuthenticateRequest.cs
using System.ComponentModel.DataAnnotations;
namespace loginApi.Models
{
public class AuthenticateRequest
{
[Required]
public string Username { get; set; }
[Required]
public string Password { get; set; }
}
}
Models\AuthenticateResponce.cs
using loginApi.Models;
namespace loginApi.Models
{
public class AuthenticateResponse
{
public string Username { get; set; }
public string Token { get; set; }
public AuthenticateResponse(User user, string token)
{
Username = user.Username;
Token = token;
}
}
}
CodePudding user response:
try doing this.
public UserService(IOptions<AppSettings> appSettings,IConfiguration configuration)
{
_appSettings = appSettings.Value;
_configuration = configuration;
var _username = _configuration.GetSection("UserCred").GetSection("Username").Value;
var _Password = _configuration.GetSection("UserCred").GetSection("Password").Value;
Console.WriteLine(_username.ToString());
Console.WriteLine(_Password.ToString());
_users = new List<User>
{
new User { Username = _username.ToString(), Password = _Password.ToString()}
};
}
public AuthenticateResponse Authenticate(AuthenticateRequest model)
{
var user = _users.SingleOrDefault(x => x.Username == model.Username && x.Password == model.Password);
if (user == null) return null;
var token = generateJwtToken(user);
return new AuthenticateResponse(user, token);
}