c# – How to add Logout method in .NET core 3.1 with storing jwt token in cookies

I’m new to c# and dot net. i am unable to understand how to implement logout method with jwt token here i’m attaching my whole code. i have implemented the authentication and authorization with jwt i’m accessing the credentials for login from the appssetting.json.

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": "*"
}

DataAcessUserRepository

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.DataAccess
{

    public class UserRepository : IUserRepository
    {
        
        private List<User> _users = new List<User>
        {
          
        };

        private readonly AppSettings _appSettings;
        private readonly IConfiguration _configuration;

        public UserRepository(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;
                   
                     _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);
        }

        public IEnumerable<User> GetAll()
        {
            return _users;
        }

        public User GetByUserName(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);
        }
    }
}

DataAccessIUserRepository

using loginApi.Models;
using System.Collections.Generic;

namespace loginApi.DataAccess
{
    public interface IUserRepository
    {
        AuthenticateResponse Authenticate(AuthenticateRequest model);
        IEnumerable<User> GetAll();
        User GetByUserName(string username);
    }

}

controllersUserController.cs

using Microsoft.AspNetCore.Mvc;
using loginApi.Models;
using loginApi.DataAccess;

namespace loginApi.Controllers
{
    [ApiController]
    [Route("[controller]")]
    public class UserController : ControllerBase
    {
        private IUserRepository _userRepository;

        public UserController(IUserRepository userRepository)
        {
            _userRepository = userRepository;
        }

        [HttpPost("Controller")]
        public IActionResult Authenticate(AuthenticateRequest model)
        {
            var response = _userRepository.Authenticate(model);

            if (response == null)
                return BadRequest(new { message = "Username or password is incorrect" });

            return Ok(response);
        }

    }
}

Helpers Folder:-

HelpersAuthorizeAttribute.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 };
        }
    }
}

HelpersJwtMiddleware.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.DataAccess;
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, IUserRepository userRepository)
        {
            var token = context.Request.Headers["Authorization"].FirstOrDefault()?.Split(" ").Last();

            if (token != null)
                attachUserToContext(context, userRepository, token);

            await _next(context);
        }

        private void attachUserToContext(HttpContext context, IUserRepository userRepository, 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 userName = jwtToken.Claims.First(x => x.Type == "username").Value;
                
                context.Items["User"] = userRepository.GetByUserName(userName);
            }
            catch
            {
                
            }
        }
    }
}

Models Folder

ModelsAppSettings.cs

namespace loginApi.Models
{
    public class AppSettings
    {
        public string Secret { get; set; }
    }
}

ModelsAuthenticateRequest.cs

using System.ComponentModel.DataAnnotations;

namespace loginApi.Models
{
    public class AuthenticateRequest
    {
        [Required]
        public string Username { get; set; }

        [Required]
        public string Password { get; set; }
    }
}

ModelsAuthenticateResponse.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;
        }
    }
}

ModelsUser.cs

using System.Text.Json.Serialization;

namespace loginApi.Models
{
    public class User
    {
        public string Username { get; set; }

        [JsonIgnore]
        public string Password { get; set; }
    }
}

Startup.cs

using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using loginApi.Helpers;
using loginApi.DataAccess;
using loginApi.Models;

namespace loginApi
{
    public class Startup
    {
        public IConfiguration Configuration { get; }

        public Startup(IConfiguration configuration)
        {
            Configuration = configuration;
        }

        // add services to the DI container
        public void ConfigureServices(IServiceCollection services)
        {
            services.AddCors();
            services.AddControllers();
             services.AddSwaggerGen(); 

            // configure strongly typed settings object
            services.Configure<AppSettings>(Configuration.GetSection("AppSettings"));
            services.Configure<User>(Configuration.GetSection("UserCred"));
            // configure DI for application services
            services.AddScoped<IUserRepository, UserRepository>();
        }

        // configure the HTTP request pipeline
        public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
        {
            app.UseRouting();

            // global cors policy
            app.UseCors(x => x
                .AllowAnyOrigin()
                .AllowAnyMethod()
                .AllowAnyHeader());

            // custom jwt auth middleware
            app.UseMiddleware<JwtMiddleware>();

            app.UseEndpoints(x => x.MapControllers());

            app.UseSwagger();  
            app.UseSwaggerUI(c => {  
            c.SwaggerEndpoint("/swagger/v1/swagger.json", "My API V2");  
            }); 
        }
    }
}

Leave a Comment