Manage User Login by Database and get a user ID from a JWT Java Web Token

Bernhard Giesriegl
CODE AUTHOR
Posts: 1
 8 months 4 weeks ago #594 by Bernhard Giesriegl
Bernhard Giesriegl created the code: Manage User Login by Database and get a user ID from a JWT Java Web Token

This example modifies the Appeon Project 'Secure a Web API with a JWT Token':

  • Logon process loads a user from a database, user are no more hardcoded
  • Creating JWT wraps a UserID into the token
  • Requests to API extract UserID from token to know from which user request comes.

 

 

1  Create a table WebAPIUser on your database:

 

 

2  Create a Model for WebAPIUser:

Use here: ID, UserID, Password

 

[Table("WebAPIUser", Schema = "dbo")]
    public class WebAPIUser
    {
        [Key]
        [Identity]
        [SqlColumn("Id")]
        public int Id { get; set; }

        [SqlColumn("UserName")]
        public string? UserName { get; set; }

        [SqlColumn("Password")]
        public string? Password { get; set; }

        [SqlColumn("Role")]
        public string? Role { get; set; }

        [SqlColumn("Token")]
        public string Token { get; set; }
    }

 

 

3  Create a Service for WebAPIUser:

Loads the table webapiuser and compares login and password.

More nice would be to realize a parameter in the WHERE CLAUSE (and also to work with hashed values) - maybe I will do in future.

Notice the line, where UserID is added into the Claim:

 

using WebAPI.Models;

using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.IdentityModel.Tokens;
using System.IdentityModel.Tokens.Jwt;
using System.Security.Claims;
using System.Text;
using Microsoft.AspNetCore.Authorization;


namespace WebAPI.Services.Impl
{
    /// <summary>
    /// The service needs to be injected into the ConfigureServices method of the Startup class. The sample code is as follows:
    /// services.AddScoped<I<WebAPIUserService>, WebAPIUserService>();
    /// </summary>
    public class WebAPIUserService : ServiceBase<WebAPIUser>, IWebAPIUserService
    {
        public async Task<string> Login(string userName, string password, CancellationToken cancellationToken)
        {
            var result = await _dataContext.SqlModelMapper
                        .LoadAsync<WebAPIUser>(new object[] { }, cancellationToken);

            var webapiuser = result.ToList().SingleOrDefault(x => x.UserName == userName && x.Password == password);
            if (webapiuser == null)
            {
                return string.Empty;
            }
            var x = webapiuser.Id;
            var tokenHandler = new JwtSecurityTokenHandler();
            var key = Encoding.UTF8.GetBytes(SecretInfo.SECRET);

            var tokenDesciptor = new SecurityTokenDescriptor
            {
                Subject = new ClaimsIdentity(new Claim[]
              {
                new Claim(ClaimTypes.Name, userName),
                new Claim(ClaimTypes.Role, "admin"),

 

 

                new Claim("UserID", webapiuser.Id.ToString())                  // Adds Entry UserID to Token with value of UserID.


              }),
                Expires = DateTime.UtcNow.AddMinutes(5),
                SigningCredentials = new SigningCredentials(new SymmetricSecurityKey(key), SecurityAlgorithms.HmacSha256Signature)
            };

            var token = tokenHandler.CreateToken(tokenDesciptor);
            webapiuser.Token = tokenHandler.WriteToken(token);
            return webapiuser.Token;         // + webapiuser.Id.ToString();

        }

        public WebAPIUserService(WebAPIDataContext dataContext) : base(dataContext)
        {
        }

 

 

 

4  Create a Controller:

Controller for WebAPIUser.

 

using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using WebAPI.Models;
using WebAPI.Services;

namespace WebAPI.Controllers
    
{
    [Route("api/[controller]")]
    [ApiController]
    public class WebAPIUserController : ControllerBase
    {
        private readonly IWebAPIUserService _iwebapiuserService;
        public WebAPIUserController(IWebAPIUserService iwebapiuserService)
        {
            _iwebapiuserService = iwebapiuserService;
        }
        
        [AllowAnonymous]
        [HttpPost]
        public async Task<ActionResult<string>> Login([FromBody] WebAPIUser webapiuser)
        {

            var token = await _iwebapiuserService.Login(webapiuser.UserName, webapiuser.Password, default);
            if (string.IsNullOrEmpty(token))
//            if (token == null)                      //(string.IsNullOrEmpty(token))
            {
                return BadRequest(new { message = "Username or password is incorrect" });
            }
            return Ok(token);
        }
    }
}    

 

 

 

 

Now we are able to login with a user and password from our table WebAPIUser in our database. The token we return contains the userid.

 

For further requests now we can extract the userid from the token submitted in the httpcontext:

 

5  Create a class to get the userid from a token:

 

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using System.IdentityModel.Tokens.Jwt;


namespace WebAPI
{
    public class GetUserIDFromToken
    {
        public int GetUserId(HttpContext httpcontext)
        {
          var reqheader = httpcontext.Request.Headers;                                                        // Get header from HTTP Header
          var tokenget = reqheader.Authorization;                                                             // Get token from Header
          var jwtToken = tokenget.First().Split(new[] { ' ' }, StringSplitOptions.RemoveEmptyEntries)[1];     // Remove "Bearer"
          var tokenHandler = new JwtSecurityTokenHandler();                                                   // create a tokenhandler
            var token = tokenHandler.ReadJwtToken(jwtToken);
          var claims = token.Claims;                                                                          // read data from Claim
          return Convert.ToInt32(claims.Where(reqheader => reqheader.Type.Equals("UserID")).First().Value);   // read and returns first entry matches with 'UserID'.
        }
    }
}

 

 

 

 

6  How to use in a post request:

 

        //POST api/Purchase/Create
        [HttpPost]
        [Authorize(Roles = "admin")]
        [ProducesResponseType(typeof(int), StatusCodes.Status200OK)]
        [ProducesResponseType(StatusCodes.Status500InternalServerError)]
        public async Task<ActionResult<int>> CreateAsync([FromBody] Purchase model)
        {
            try
            {
                
              var GUIFT = new GetUserIDFromToken();                               // creates a GetUserIDFromToken Objekt
              model.PCHWebAPIUserID = GUIFT.GetUserId(HttpContext);               // reads WebAPIUserID (The UserID from sending user from httpcontext and puts it in model of your record to save
                var result = await _ipurchaseservice.CreateAsync(model, default);
                return Ok(result);
            }
            catch (Exception ex)
            {
                return StatusCode(StatusCodes.Status500InternalServerError, ex.Message);
            }
        }

 

 

6  How to use in a get request:

 

 

        [HttpGet("{clientnr}/{projectnr}")]
        [Authorize(Roles = "admin")]
        [ProducesResponseType(typeof(IDataStore<PurchaseGetData>), StatusCodes.Status200OK)]
        [ProducesResponseType(StatusCodes.Status500InternalServerError)]
        public async Task<ActionResult<IDataStore<PurchaseGetData>>> RetrieveAsync(int? clientnr, string projectnr)
        {
            try
          {var GUIFT = new GetUserIDFromToken(); // create object
              var result = await _ipurchasegetdataservice.RetrieveAsync(GUIFT.GetUserId(HttpContext), clientnr, projectnr, default);

                      // reads WebAPIUserID from token and uses this for WHERE CLAUSE.
                return Ok(result);
            }
            catch (Exception ex)
            {
                return StatusCode(StatusCodes.Status500InternalServerError, ex.Message);
            }
        }

 

Please Log in or Create an account to join the conversation.