Skip to content

Commit

Permalink
fix:JwtAuth
Browse files Browse the repository at this point in the history
  • Loading branch information
moshdev2213 committed Sep 24, 2024
1 parent 72f5247 commit 4ac5ec2
Show file tree
Hide file tree
Showing 34 changed files with 612 additions and 202 deletions.
60 changes: 60 additions & 0 deletions Controllers/AuthController.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
using Microsoft.AspNetCore.Mvc;
using apekade.Enums;
using apekade.Services;
using apekade.Models.Dto.AuthDto;
using apekade.Models.Dto;
using apekade.Models.Validation;

namespace apekade.Controllers;

[ApiController]
[Route("api/[controller]")]
public class AuthController : ControllerBase
{
private readonly IAuthService _authService;

public AuthController(IAuthService authService)
{
_authService = authService;
}

[HttpPost("register")]
public async Task<IActionResult> Register([FromBody] RegisterDto registerDto)
{
var validator = new RegisterValidator();
var result = validator.Validate(registerDto);

if (!result.IsValid)
{
var firstError = result.Errors.Select(e => new { error = e.ErrorMessage }).FirstOrDefault();
return this.ApiRes(400, false, "Validation error", firstError);
}

var response = await _authService.Register(registerDto);
if (!response.Status)
{
return this.ApiRes(response.Code, response.Status, response.Message, response.Data);
}
return this.ApiRes(response.Code, response.Status, response.Message, response.Data);
}

[HttpPost("login")]
public async Task<IActionResult> Login([FromBody] LoginDto loginDto)
{
var validator = new LoginValidator();
var result = validator.Validate(loginDto);

if (!result.IsValid)
{
var firstError = result.Errors.Select(e => new { error = e.ErrorMessage }).FirstOrDefault();
return this.ApiRes(400, false, "Validation error", firstError);
}

var response = await _authService.Login(loginDto);
if (!response.Status)
{
return this.ApiRes(response.Code, response.Status, response.Message, response.Data);
}
return this.ApiRes(response.Code, response.Status, response.Message, response.Data);
}
}
21 changes: 8 additions & 13 deletions Controllers/TestController.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,58 +13,53 @@ public class TestController : ControllerBase
[HttpGet]
public IActionResult GetServerStatus()
{
var response = new ApiRes<object>{
Status = true,
Code= 200,
Data = new { Message = "Server Online" }
};
return Ok(response);
return this.ApiRes(200, true, "Server Online", new { Msg = "Server Online" });

}
// Only SuperAdmin can access this endpoint
[Authorize(Roles = "SUPER_ADMIN")]
[HttpGet("superadmin")]
public IActionResult SuperAdminOnly()
{
return Ok("Only SuperAdmin can access this.");
return this.ApiRes(200, true, "Only SuperAdmin can access this.", new {});
}

// Only Seller can access this endpoint
[Authorize(Roles = "SELLER")]
[HttpGet("seller")]
public IActionResult SellerOnly()
{
return Ok("Only Sellers can access this.");
return this.ApiRes(200, true, "Only Sellers can access this.", new {});
}

// Only Buyer can access this endpoint
[Authorize(Roles = "BUYER")]
[HttpGet("buyer")]
public IActionResult BuyerOnly()
{
return Ok("Only Buyers can access this.");
return this.ApiRes(200, true, "Only Buyers can access this.", new {});
}

// Both Seller and Buyer can access this endpoint
[Authorize(Roles = "SELLER,BUYER")]
[HttpGet("seller-buyer")]
public IActionResult SellerAndBuyerAccess()
{
return Ok("Both Sellers and Buyers can access this.");
return this.ApiRes(200, true, "Both Sellers and Buyers can access this.", new {});
}

// Any authenticated user can access this endpoint
[Authorize]
[HttpGet("common")]
public IActionResult CommonAccess()
{
return Ok("Any authenticated user can access this.");
return this.ApiRes(200, true, "Any authenticated user can access this.", new {});
}

// Any one can access this endpoint
[HttpGet("open")]
public IActionResult OpenAccess()
{
return Ok("Any one can access this.");
return this.ApiRes(200, true, "Anyone can access this.", new {});
}
}
10 changes: 5 additions & 5 deletions Controllers/UserController.cs
Original file line number Diff line number Diff line change
@@ -1,23 +1,23 @@
using Microsoft.AspNetCore.Mvc;
using apekade.Enums;
using apekade.Services;
using apekade.Models.Dto.UserDto;
using Microsoft.AspNetCore.Authorization;

namespace apekade.Controllers;

[ApiController]
[Route("api/[controller]")]
[Authorize]
public class UserController : ControllerBase{
private readonly IUserService _userService;

public UserController(IUserService userService){
_userService = userService;
}

[HttpPost]
public async Task<IActionResult> CreateUser([FromBody] UserReqtDto userReqtDto){
[HttpPost("test")]
public IActionResult CreateUser([FromBody] string email){

var response = await _userService.CreateNewUser(userReqtDto);
var response = email;
return Ok(response);
}
}
41 changes: 0 additions & 41 deletions Helpers/GenerateJwtToken.cs

This file was deleted.

38 changes: 28 additions & 10 deletions Helpers/HashPassword.cs
Original file line number Diff line number Diff line change
@@ -1,19 +1,37 @@
using System.Security.Cryptography;

using Microsoft.AspNetCore.Cryptography.KeyDerivation;
namespace apekade.Helpers;

public class HashPassword{
public static void CreatePasswordHash(string password, out string passwordHash, out string passwordSalt)
public class HashPassword
{
public static string CreatePasswordHash(string password)
{
using var hmac = new HMACSHA512();
passwordSalt = Convert.ToBase64String(hmac.Key);
passwordHash = Convert.ToBase64String(hmac.ComputeHash(System.Text.Encoding.UTF8.GetBytes(password)));
var salt = new byte[16];
RandomNumberGenerator.Fill(salt);

var hashed = Convert.ToBase64String(KeyDerivation.Pbkdf2(
password: password,
salt: salt,
prf: KeyDerivationPrf.HMACSHA256,
iterationCount: 10000,
numBytesRequested: 256 / 8));

return Convert.ToBase64String(salt) + ":" + hashed;
}

public static bool VerifyPasswordHash(string password, string storedHash, string storedSalt)
public static bool VerifyPasswordHash(string hashedPassword, string password)
{
using var hmac = new HMACSHA512(Convert.FromBase64String(storedSalt));
var computedHash = Convert.ToBase64String(hmac.ComputeHash(System.Text.Encoding.UTF8.GetBytes(password)));
return computedHash == storedHash;
var parts = hashedPassword.Split(':');
var salt = Convert.FromBase64String(parts[0]);
var storedHash = parts[1];

var hash = Convert.ToBase64String(KeyDerivation.Pbkdf2(
password: password,
salt: salt,
prf: KeyDerivationPrf.HMACSHA256,
iterationCount: 10000,
numBytesRequested: 256 / 8));

return hash == storedHash;
}
}
75 changes: 75 additions & 0 deletions Helpers/JwtHelper.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
using System.IdentityModel.Tokens.Jwt;
using System.Security.Claims;
using System.Text;
using Microsoft.IdentityModel.Tokens;
using apekade.Models;

namespace apekade.Helpers;

public class JwtHelper
{
private readonly IConfiguration _configuration;

public JwtHelper(IConfiguration configuration)
{
_configuration = configuration;
}

public string GenerateJwt(User user)
{
var tokenHandler = new JwtSecurityTokenHandler();

var appSettingToken = _configuration.GetSection("AppSettings:Token").Value;
if (appSettingToken is null)
throw new Exception("AppSettings Token is null!");

var key = Encoding.UTF8.GetBytes(appSettingToken);

var tokenDescriptor = new SecurityTokenDescriptor
{
Subject = new ClaimsIdentity(new[]
{
new Claim(ClaimTypes.NameIdentifier, user.Id),
new Claim(ClaimTypes.Email, user.Email),
new Claim(ClaimTypes.Role, user.Role.ToString())
}),
Expires = DateTime.UtcNow.AddHours(1),
SigningCredentials = new SigningCredentials(new SymmetricSecurityKey(key), SecurityAlgorithms.HmacSha256Signature)
};

var token = tokenHandler.CreateToken(tokenDescriptor);
return tokenHandler.WriteToken(token);
}

public ClaimsPrincipal? ValidateToken(string token)
{
var tokenHandler = new JwtSecurityTokenHandler();
var appSettingToken = _configuration.GetSection("AppSettings:Token").Value;
if (appSettingToken is null)
throw new Exception("AppSettings Token is null!");
var key = Encoding.UTF8.GetBytes(appSettingToken);

try
{
var tokenValidationParameters = new TokenValidationParameters
{
ValidateIssuerSigningKey = true,
IssuerSigningKey = new SymmetricSecurityKey(key),
ValidateIssuer = false,
ValidateAudience = false,
ClockSkew = TimeSpan.Zero // Remove delay of token when expire
};

// Validate the token and return the claims principal
var principal = tokenHandler.ValidateToken(token, tokenValidationParameters, out SecurityToken validatedToken);
return principal; // Return the ClaimsPrincipal
}
catch (Exception)
{
// Token is invalid
return null;
}
}


}
32 changes: 32 additions & 0 deletions Middleware/ExceptionMiddleware.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
using System;
using System.Net;
using apekade.Models.Response;

namespace apekade.Middleware;

public class ExceptionMiddleware
{
private readonly RequestDelegate _next;
public ExceptionMiddleware(RequestDelegate next){
_next = next;
}
public async Task InvokeAsync(HttpContext context){
try
{
await _next(context);
}
catch (Exception e)
{
context.Response.ContentType = "application/json";
context.Response.StatusCode = (int) HttpStatusCode.InternalServerError;
var error = new ErrorRes{
Code = context.Response.StatusCode,
Status = false,
Data= new {},
Message = e.Message
};
await context.Response.WriteAsync(error.ToString());
}
}

}
Loading

0 comments on commit 4ac5ec2

Please sign in to comment.