forked from MDCPS/DamageAssessment_Backend
User Role and Authorization features added
This commit is contained in:
@ -0,0 +1,58 @@
|
||||
using DamageAssesment.Api.UsersAccess.Bases;
|
||||
using DamageAssesment.Api.UsersAccess.Interfaces;
|
||||
using DamageAssesment.Api.UsersAccess.Models;
|
||||
using Newtonsoft.Json;
|
||||
using System.Reflection;
|
||||
|
||||
namespace DamageAssesment.Api.SurveyResponses.Providers
|
||||
{
|
||||
public class EmployeeServiceProvider :ServiceProviderBase, IEmployeeServiceProvider
|
||||
{
|
||||
public EmployeeServiceProvider(IConfiguration configuration, HttpClient httpClient, ILogger<EmployeeServiceProvider> logger) : base(configuration, httpClient, logger, "/api/Employees", configuration.GetValue<string>("EndPointSettings:EmployeeUrlBase"))
|
||||
{
|
||||
}
|
||||
|
||||
public async Task<List<Employee>> getEmployeesAsync()
|
||||
{
|
||||
try
|
||||
{
|
||||
httpClient.BaseAddress = new Uri(urlBase);
|
||||
var response = await httpClient.GetAsync(ressource);
|
||||
response.EnsureSuccessStatusCode();
|
||||
var responseString = await response.Content.ReadAsStringAsync();
|
||||
var employees = JsonConvert.DeserializeObject<List<Employee>>(responseString);
|
||||
|
||||
if (employees == null || !employees.Any())
|
||||
return null;
|
||||
else return employees;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
logger?.LogError($"Exception Found : {ex.Message} - Ref: EmployeeServiceProvider.getEmployeesAsync()");
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<Employee> getEmployeeAsync(string employeeID)
|
||||
{
|
||||
try
|
||||
{
|
||||
httpClient.BaseAddress = new Uri(urlBase);
|
||||
//ressource = ressource + "/" + employeeID;
|
||||
var response = await httpClient.GetAsync("/api/Employees/"+ employeeID);
|
||||
response.EnsureSuccessStatusCode();
|
||||
var responseString = await response.Content.ReadAsStringAsync();
|
||||
var employee = JsonConvert.DeserializeObject<Employee>(responseString);
|
||||
|
||||
if (employee == null )
|
||||
return null;
|
||||
else return employee;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
logger?.LogError($"Exception Found : {ex.Message} - Ref: EmployeeServiceProvider.getEmployeeAsync()");
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,57 @@
|
||||
using System.IdentityModel.Tokens.Jwt;
|
||||
using System.Security.Claims;
|
||||
using System.Security.Cryptography;
|
||||
using System.Text;
|
||||
using DamageAssesment.Api.UsersAccess.Db;
|
||||
using DamageAssesment.Api.UsersAccess.Interfaces;
|
||||
using DamageAssesment.Api.UsersAccess.Models;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.Extensions.Options;
|
||||
using Microsoft.IdentityModel.Tokens;
|
||||
|
||||
public class TokenServiceProvider : ITokenServiceProvider
|
||||
{
|
||||
private readonly UsersAccessDbContext usersAccessDbContext;
|
||||
private readonly JwtSettings jwtSettings;
|
||||
public TokenServiceProvider(IOptions<JwtSettings> options,UsersAccessDbContext usersAccessDbContext)
|
||||
{
|
||||
this.usersAccessDbContext = usersAccessDbContext;
|
||||
this.jwtSettings = options.Value;
|
||||
}
|
||||
public async Task<string> GenerateToken(DamageAssesment.Api.UsersAccess.Models.User user)
|
||||
{
|
||||
var randomnumber = new byte[32];
|
||||
using (var ramdomnumbergenerator = RandomNumberGenerator.Create())
|
||||
{
|
||||
ramdomnumbergenerator.GetBytes(randomnumber);
|
||||
string refreshtoken = Convert.ToBase64String(randomnumber);
|
||||
var token = await usersAccessDbContext.Tokens.FirstOrDefaultAsync(item => item.UserId == user.Id);
|
||||
if (token != null)
|
||||
{
|
||||
token.RefreshToken = refreshtoken;
|
||||
}
|
||||
else
|
||||
{
|
||||
usersAccessDbContext.Tokens.Add(new DamageAssesment.Api.UsersAccess.Db.Token()
|
||||
{
|
||||
Id = new Random().Next().ToString(),
|
||||
UserId = user.Id,
|
||||
RefreshToken = refreshtoken,
|
||||
IsActive = true
|
||||
});
|
||||
}
|
||||
await usersAccessDbContext.SaveChangesAsync();
|
||||
|
||||
return refreshtoken;
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<TokenResponse> TokenAuthenticate(DamageAssesment.Api.UsersAccess.Models.User user, Claim[] claims)
|
||||
{
|
||||
var token = new JwtSecurityToken(claims: claims, expires: DateTime.Now.AddSeconds(20),
|
||||
signingCredentials: new SigningCredentials(new SymmetricSecurityKey(Encoding.UTF8.GetBytes(jwtSettings.securitykey)), SecurityAlgorithms.HmacSha256)
|
||||
);
|
||||
var jwttoken = new JwtSecurityTokenHandler().WriteToken(token);
|
||||
return new TokenResponse() { jwttoken = jwttoken, refreshtoken = await GenerateToken(user) };
|
||||
}
|
||||
}
|
@ -0,0 +1,341 @@
|
||||
using AutoMapper;
|
||||
using DamageAssesment.Api.UsersAccess.Db;
|
||||
using DamageAssesment.Api.UsersAccess.Interfaces;
|
||||
using DamageAssesment.Api.UsersAccess.Models;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.Extensions.Options;
|
||||
using Microsoft.IdentityModel.Tokens;
|
||||
using System.Data;
|
||||
using System.IdentityModel.Tokens.Jwt;
|
||||
using System.Security.Claims;
|
||||
using System.Text;
|
||||
|
||||
namespace DamageAssesment.Api.UsersAccess.Providers
|
||||
{
|
||||
public class UsersAccessProvider : IUsersAccessProvider
|
||||
{
|
||||
private readonly UsersAccessDbContext userAccessDbContext;
|
||||
private readonly ILogger<UsersAccessProvider> logger;
|
||||
private readonly IMapper mapper;
|
||||
private readonly IEmployeeServiceProvider employeeServiceProvider;
|
||||
private readonly JwtSettings jwtSettings;
|
||||
private readonly ITokenServiceProvider tokenServiceProvider;
|
||||
|
||||
public UsersAccessProvider(IOptions<JwtSettings> options, ITokenServiceProvider tokenServiceProvider, UsersAccessDbContext userAccessDbContext, IEmployeeServiceProvider employeeServiceProvider, ILogger<UsersAccessProvider> logger, IMapper mapper)
|
||||
{
|
||||
this.userAccessDbContext = userAccessDbContext;
|
||||
this.employeeServiceProvider = employeeServiceProvider;
|
||||
this.logger = logger;
|
||||
this.mapper = mapper;
|
||||
jwtSettings = options.Value;
|
||||
this.tokenServiceProvider = tokenServiceProvider;
|
||||
seedData();
|
||||
}
|
||||
|
||||
private void seedData()
|
||||
{
|
||||
if (!userAccessDbContext.Users.Any())
|
||||
{
|
||||
userAccessDbContext.Users.Add(new Db.User { Id = 1, EmployeeId = "Emp1", RoleId = 1 });
|
||||
userAccessDbContext.Users.Add(new Db.User { Id = 2, EmployeeId = "Emp2", RoleId = 2 });
|
||||
userAccessDbContext.Users.Add(new Db.User { Id = 3, EmployeeId = "Emp3", RoleId = 3 });
|
||||
userAccessDbContext.SaveChanges();
|
||||
}
|
||||
|
||||
if (!userAccessDbContext.Roles.Any())
|
||||
{
|
||||
userAccessDbContext.Roles.Add(new Db.Role { Id = 1, Name = "admin" });
|
||||
userAccessDbContext.Roles.Add(new Db.Role { Id = 2, Name = "user" });
|
||||
userAccessDbContext.Roles.Add(new Db.Role { Id = 3, Name = "survey" });
|
||||
userAccessDbContext.Roles.Add(new Db.Role { Id = 4, Name = "report" });
|
||||
userAccessDbContext.Roles.Add(new Db.Role { Id = 5, Name = "document" });
|
||||
userAccessDbContext.SaveChanges();
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<(bool IsSuccess, IEnumerable<Models.User> Users, string ErrorMessage)> GetUsersAsync()
|
||||
{
|
||||
try
|
||||
{
|
||||
logger?.LogInformation("Gell all Users from DB");
|
||||
var users = await userAccessDbContext.Users.ToListAsync();
|
||||
if (users != null)
|
||||
{
|
||||
logger?.LogInformation($"{users.Count} Items(s) found");
|
||||
var result = mapper.Map<IEnumerable<Db.User>, IEnumerable<Models.User>>(users);
|
||||
return (true, result, null);
|
||||
}
|
||||
return (false, null, "Not found");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
logger?.LogError(ex.ToString());
|
||||
return (false, null, ex.Message);
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<(bool IsSuccess, Models.User User, string ErrorMessage)> GetUsersAsync(int Id)
|
||||
{
|
||||
try
|
||||
{
|
||||
logger?.LogInformation("Querying Users table");
|
||||
var user = await userAccessDbContext.Users.SingleOrDefaultAsync(s => s.Id == Id);
|
||||
if (user != null)
|
||||
{
|
||||
logger?.LogInformation($"User Id: {Id} found");
|
||||
var result = mapper.Map<Db.User, Models.User>(user);
|
||||
return (true, result, null);
|
||||
}
|
||||
return (false, null, "Not found");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
logger?.LogError(ex.ToString());
|
||||
return (false, null, ex.Message);
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<(bool IsSuccess, Models.User User, string ErrorMessage)> PostUserAsync(Models.User user)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (user != null)
|
||||
{
|
||||
var users = await userAccessDbContext.Users.ToListAsync();
|
||||
int count = users.Where(u => u.EmployeeId == user.EmployeeId).Count();
|
||||
if (count == 0)
|
||||
{
|
||||
user.Id = users.Count + 1;
|
||||
userAccessDbContext.Users.Add(mapper.Map<Models.User, Db.User>(user));
|
||||
await userAccessDbContext.SaveChangesAsync();
|
||||
return (true, user, "Successful");
|
||||
}
|
||||
else
|
||||
{
|
||||
logger?.LogInformation($"Employee Id: {user.EmployeeId} is already exist");
|
||||
return (false, null, $"Employee Id: {user.EmployeeId} is already exist");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
logger?.LogInformation($"Employee Id: {user.EmployeeId} cannot be added");
|
||||
return (false, null, $"Employee Id: {user.EmployeeId} cannot be added");
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
logger?.LogError(ex.ToString());
|
||||
return (false, null, ex.Message);
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<(bool IsSuccess, Models.User User, string ErrorMessage)> PutUserAsync(int Id, Models.User user)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (user != null)
|
||||
{
|
||||
var _user = await userAccessDbContext.Users.Where(s => s.Id == Id).SingleOrDefaultAsync();
|
||||
|
||||
if (_user != null)
|
||||
{
|
||||
int count = userAccessDbContext.Users.Where(u => u.Id != user.Id && u.EmployeeId == user.EmployeeId).Count();
|
||||
if (count == 0)
|
||||
{
|
||||
_user.EmployeeId = user.EmployeeId;
|
||||
_user.RoleId = user.RoleId;
|
||||
_user.IsActive = user.IsActive;
|
||||
_user.UpdateDate = DateTime.Now;
|
||||
await userAccessDbContext.SaveChangesAsync();
|
||||
|
||||
|
||||
logger?.LogInformation($"Employee Id: {user.EmployeeId} updated successfuly");
|
||||
return (true, mapper.Map<Db.User, Models.User>(_user), $"Employee Id: {_user.EmployeeId} updated successfuly");
|
||||
}
|
||||
else
|
||||
{
|
||||
logger?.LogInformation($"Employee Id: {user.EmployeeId} is already exist");
|
||||
return (false, null, $"Employee Id: {user.EmployeeId} is already exist");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
logger?.LogInformation($"User Id : {Id} Not found");
|
||||
return (false, null, "Not Found");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
logger?.LogInformation($"User Id: {Id} Bad Request");
|
||||
return (false, null, "Bad request");
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
logger?.LogError(ex.ToString());
|
||||
return (false, null, ex.Message);
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<(bool IsSuccess, Models.User User, string ErrorMessage)> DeleteUserAsync(int Id)
|
||||
{
|
||||
try
|
||||
{
|
||||
var user = await userAccessDbContext.Users.Where(x => x.Id == Id).SingleOrDefaultAsync();
|
||||
|
||||
if (user != null)
|
||||
{
|
||||
userAccessDbContext.Users.Remove(user);
|
||||
await userAccessDbContext.SaveChangesAsync();
|
||||
logger?.LogInformation($"User Id: {Id} deleted Successfuly");
|
||||
return (true, mapper.Map<Db.User, Models.User>(user), $"User Id: {Id} deleted Successfuly");
|
||||
}
|
||||
else
|
||||
{
|
||||
logger?.LogInformation($"User Id : {Id} Not found");
|
||||
return (false, null, "Not Found");
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
logger?.LogError(ex.ToString());
|
||||
return (false, null, ex.Message);
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<(bool IsSuccess, TokenResponse TokenResponse, string ErrorMessage)> AuthenticateAsync(UserCredentials userCredentials)
|
||||
{
|
||||
|
||||
if (userCredentials != null)
|
||||
{
|
||||
//implementation for dadeschools authentication
|
||||
|
||||
var employee = await employeeServiceProvider.getEmployeeAsync(userCredentials.username);
|
||||
|
||||
if (employee != null)
|
||||
{
|
||||
var result = await GetUsersAsync();
|
||||
|
||||
if (result.IsSuccess)
|
||||
{
|
||||
var user = result.Users.Where(x => x.IsActive == true && x.EmployeeId.ToLower().Equals(userCredentials.username.ToLower())).SingleOrDefault();
|
||||
|
||||
if (user != null)
|
||||
{
|
||||
|
||||
var r = await GetRolesAsync();
|
||||
var role = r.Roles.Where(x => x.Id == user.RoleId).SingleOrDefault();
|
||||
|
||||
var authClaims = new List<Claim> {
|
||||
new Claim(ClaimTypes.Name, user.EmployeeId),
|
||||
new Claim(ClaimTypes.Role, role.Name),
|
||||
new Claim(JwtRegisteredClaimNames.Jti,Guid.NewGuid().ToString())
|
||||
|
||||
};
|
||||
|
||||
/// Generate Token
|
||||
var tokenhandler = new JwtSecurityTokenHandler();
|
||||
var tokenkey = Encoding.UTF8.GetBytes(jwtSettings.securitykey);
|
||||
var tokendesc = new SecurityTokenDescriptor
|
||||
{
|
||||
Audience = "",
|
||||
NotBefore = DateTime.Now,
|
||||
Subject = new ClaimsIdentity(authClaims),
|
||||
Expires = DateTime.Now.AddMinutes(30),
|
||||
SigningCredentials = new SigningCredentials(new SymmetricSecurityKey(tokenkey), SecurityAlgorithms.HmacSha256)
|
||||
};
|
||||
var token = tokenhandler.CreateToken(tokendesc);
|
||||
string finaltoken = tokenhandler.WriteToken(token);
|
||||
|
||||
var response = new TokenResponse() { jwttoken = finaltoken, refreshtoken = await tokenServiceProvider.GenerateToken(user) };
|
||||
|
||||
|
||||
return (true, response, "Authentication success and token issued.");
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
return (false, null, "user inactive or not exist.");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return (false, null, "users list empty.");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return (false, null, "Employee not exist.");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return (false, null, "Credentials are required to authenticate.");
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
public async Task<(bool IsSuccess, IEnumerable<Models.Role> Roles, string ErrorMessage)> GetRolesAsync()
|
||||
{
|
||||
try
|
||||
{
|
||||
logger?.LogInformation("Gell all Roles from DB");
|
||||
var roles = await userAccessDbContext.Roles.ToListAsync();
|
||||
if (roles != null)
|
||||
{
|
||||
logger?.LogInformation($"{roles.Count} Items(s) found");
|
||||
var result = mapper.Map<IEnumerable<Db.Role>, IEnumerable<Models.Role>>(roles);
|
||||
return (true, result, null);
|
||||
}
|
||||
return (false, null, "Not found");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
logger?.LogError(ex.ToString());
|
||||
return (false, null, ex.Message);
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<(bool IsSuccess, Models.TokenResponse TokenResponse, string ErrorMessage)> RefreshTokenAsync(TokenResponse tokenResponse)
|
||||
{
|
||||
//Generate token
|
||||
var tokenhandler = new JwtSecurityTokenHandler();
|
||||
var tokenkey = Encoding.UTF8.GetBytes(this.jwtSettings.securitykey);
|
||||
SecurityToken securityToken;
|
||||
var principal = tokenhandler.ValidateToken(tokenResponse.jwttoken, new TokenValidationParameters
|
||||
{
|
||||
ValidateIssuerSigningKey = true,
|
||||
IssuerSigningKey = new SymmetricSecurityKey(tokenkey),
|
||||
ValidateIssuer = false,
|
||||
ValidateAudience = false,
|
||||
|
||||
}, out securityToken);
|
||||
|
||||
var token = securityToken as JwtSecurityToken;
|
||||
if (token != null && !token.Header.Alg.Equals(SecurityAlgorithms.HmacSha256))
|
||||
{
|
||||
return (false, null, "Unauthorized");
|
||||
}
|
||||
var username = principal.Identity?.Name;
|
||||
|
||||
var tokens = await userAccessDbContext.Tokens.ToListAsync();
|
||||
var users = await userAccessDbContext.Users.ToListAsync();
|
||||
|
||||
var user = (from u in users
|
||||
join t in tokens
|
||||
on u.Id equals t.UserId
|
||||
where u.EmployeeId == username
|
||||
&& t.RefreshToken == tokenResponse.refreshtoken
|
||||
select u).FirstOrDefault();
|
||||
|
||||
if (user == null)
|
||||
return (false, null, "Invalid Token Response object provided");
|
||||
|
||||
var _user = mapper.Map<Db.User, Models.User>(user);
|
||||
var response = tokenServiceProvider.TokenAuthenticate(_user, principal.Claims.ToArray()).Result;
|
||||
return (true, response, "Token authenticated and refreshed.");
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user