0

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;
        }
    }
}
arp
  • 1
  • 1
  • 8
  • Aren't you using wndows authentication? [HttpPost("authenticate")] If windows fails then your code will not work. See : https://learn.microsoft.com/en-us/aspnet/web-api/overview/security/authentication-and-authorization-in-aspnet-web-api – jdweng Jul 10 '22 at 13:44
  • is your credentials being read properly from appsettings.json file. ? – CodingMytra Jul 10 '22 at 14:51
  • If authorization works for the hard coded values and not working for the appsetting.json values, probably the issue is in reading the appsetting json values. Can you debug and see whether you get the expected data from appsetting file (username, password etc.)? – shehanpathi Jul 10 '22 at 16:37
  • 1
    @shehanpathirathna I'm getting the correct values from appsetting .json but after debugging i saw that first my list object get's called so controller passing null values. can you check my UserService.cs and tell me how can i access values under private list obect _users. – arp Jul 11 '22 at 07:57
  • @CodingMytra yes i printed those on console – arp Jul 11 '22 at 07:57
  • 1
    so your token generation is not happening ? or validation is not happening ? by the way i ran your code and token generation is working for me. – CodingMytra Jul 11 '22 at 08:12
  • @CodingMytra yes i want help in authorization when i am passing hardcoded values authorization also working – arp Jul 11 '22 at 08:59
  • it is not clear from your comment which part is not working , token generation or validation ? – CodingMytra Jul 11 '22 at 09:16
  • @CodingMytra validation not working – arp Jul 11 '22 at 09:43
  • check my ans below. – CodingMytra Jul 11 '22 at 09:48
  • When you hard code here the project's authorization works well? When you get value from `appsetting.json`, Does the project show the error like `IDX12709: CanReadToken() returned false. JWT is not well formed: 'System.String'.....`? in `attachUserToContext`? I think you can check the value readed from appsetting.json – Xinran Shen Jul 11 '22 at 09:49
  • @XinranShen i was not getting any error when i'm calling get method i was getting unauthorized. it's working now i have made changes according to below code – arp Jul 11 '22 at 10:15

1 Answers1

1

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);
    }
CodingMytra
  • 2,234
  • 1
  • 9
  • 21
  • How Can i add business layer to UserService? – arp Jul 12 '22 at 10:23
  • what do you mean by business layer. i would suggest you write a new question with specific details to avoid mixing up issues – CodingMytra Jul 12 '22 at 10:26
  • plz check https://stackoverflow.com/questions/73023253/how-to-add-logout-method-in-net-core-3-1-with-storing-jwt-token-in-cookies – arp Jul 18 '22 at 13:48