services, startup Jwt, Helpers
This commit is contained in:
parent
441e75e639
commit
62ba58e391
|
|
@ -1,3 +1,4 @@
|
|||
using BackEndAaaapero.Models;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Models;
|
||||
namespace BackEndAaaapero.Data
|
||||
|
|
@ -7,5 +8,6 @@ namespace BackEndAaaapero.Data
|
|||
public Context(DbContextOptions<Context> options) : base(options) {}
|
||||
|
||||
public DbSet<Customers> customers { get; set; }
|
||||
public DbSet<User> User {get; set; }
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,19 @@
|
|||
using System;
|
||||
using System.Globalization;
|
||||
|
||||
namespace BackEndAaaapero.Helpers
|
||||
{
|
||||
// Custom exception class for throwing application specific exceptions (e.g. for validation)
|
||||
// that can be caught and handled within the application
|
||||
public class AppException : Exception
|
||||
{
|
||||
public AppException() : base() {}
|
||||
|
||||
public AppException(string message) : base(message) { }
|
||||
|
||||
public AppException(string message, params object[] args)
|
||||
: base(String.Format(CultureInfo.CurrentCulture, message, args))
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
using AutoMapper;
|
||||
using DTO;
|
||||
using Models;
|
||||
using BackEndAaaapero.Models;
|
||||
|
||||
namespace BackEndAaaapero.Helpers
|
||||
{
|
||||
public class AutoMapperProfile : Profile
|
||||
{
|
||||
public AutoMapperProfile()
|
||||
{
|
||||
//<source class, destination class>
|
||||
CreateMap<User, UserModel>();
|
||||
CreateMap<RegisterModel, User>();
|
||||
CreateMap<UpdateModel, User>();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
namespace BackEndAaaapero.Models
|
||||
{
|
||||
public class User
|
||||
{
|
||||
public int Id { get; set; }
|
||||
public string FirstName { get; set; }
|
||||
public string LastName { get; set; }
|
||||
public string Username { get; set; }
|
||||
public string PasswordHash { get; set; }
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,163 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Security.Cryptography;
|
||||
using System.Text;
|
||||
using BackEndAaaapero.Data;
|
||||
using BackEndAaaapero.Helpers;
|
||||
using BackEndAaaapero.Models;
|
||||
|
||||
namespace Services
|
||||
{
|
||||
public interface IUserService
|
||||
{
|
||||
User Authenticate(string username, string password);
|
||||
IEnumerable<User> GetAll();
|
||||
User GetById(int id);
|
||||
User Create(User user, string password);
|
||||
void Update(User user, string currentPassword, string password, string confirmPassword);
|
||||
void Delete(int id);
|
||||
}
|
||||
|
||||
public class UserService : IUserService
|
||||
{
|
||||
private Context _context;
|
||||
|
||||
public UserService(Context context)
|
||||
{
|
||||
_context = context;
|
||||
}
|
||||
|
||||
public User Authenticate(string username, string password)
|
||||
{
|
||||
if (string.IsNullOrEmpty(username) || string.IsNullOrEmpty(password))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
var user = _context.User.FirstOrDefault(x => x.Username == username) ?? null;
|
||||
|
||||
// check if username exists
|
||||
if (user == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
// Granting access if the hashed password in the database matches with the password(hashed in computeHash method) entered by user.
|
||||
if(computeHash(password) != user.PasswordHash)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
return user;
|
||||
}
|
||||
|
||||
public IEnumerable<User> GetAll()
|
||||
{
|
||||
return _context.User;
|
||||
}
|
||||
|
||||
public User GetById(int id)
|
||||
{
|
||||
return _context.User.Find(id);
|
||||
}
|
||||
|
||||
public User Create(User user, string password)
|
||||
{
|
||||
// validation
|
||||
if (string.IsNullOrWhiteSpace(password))
|
||||
{
|
||||
throw new AppException("Password is required");
|
||||
}
|
||||
|
||||
if (_context.User.Any(x => x.Username == user.Username))
|
||||
{
|
||||
throw new AppException("Username \"" + user.Username + "\" is already taken");
|
||||
}
|
||||
|
||||
//Saving hashed password into Database table
|
||||
user.PasswordHash = computeHash(password);
|
||||
|
||||
_context.User.Add(user);
|
||||
_context.SaveChanges();
|
||||
|
||||
return user;
|
||||
}
|
||||
|
||||
public void Update(User userParam, string currentPassword = null, string password = null, string confirmPassword = null)
|
||||
{
|
||||
//Find the user by Id
|
||||
var user = _context.User.Find(userParam.Id);
|
||||
|
||||
if (user == null)
|
||||
{
|
||||
throw new AppException("User not found");
|
||||
}
|
||||
// update user properties if provided
|
||||
if (!string.IsNullOrWhiteSpace(userParam.Username) && userParam.Username != user.Username)
|
||||
{
|
||||
// throw error if the new username is already taken
|
||||
if (_context.User.Any(x => x.Username == userParam.Username))
|
||||
{
|
||||
throw new AppException("Username " + userParam.Username + " is already taken");
|
||||
}
|
||||
else
|
||||
{
|
||||
user.Username = userParam.Username;
|
||||
}
|
||||
}
|
||||
if (!string.IsNullOrWhiteSpace(userParam.FirstName))
|
||||
{
|
||||
user.FirstName = userParam.FirstName;
|
||||
}
|
||||
if (!string.IsNullOrWhiteSpace(userParam.LastName))
|
||||
{
|
||||
user.LastName = userParam.LastName;
|
||||
}
|
||||
if (!string.IsNullOrWhiteSpace(currentPassword))
|
||||
{
|
||||
if(computeHash(currentPassword) != user.PasswordHash)
|
||||
{
|
||||
throw new AppException("Invalid Current password!");
|
||||
}
|
||||
|
||||
if(currentPassword == password)
|
||||
{
|
||||
throw new AppException("Please choose another password!");
|
||||
}
|
||||
|
||||
if(password != confirmPassword)
|
||||
{
|
||||
throw new AppException("Password doesn't match!");
|
||||
}
|
||||
|
||||
//Updating hashed password into Database table
|
||||
user.PasswordHash = computeHash(password);
|
||||
}
|
||||
|
||||
_context.User.Update(user);
|
||||
_context.SaveChanges();
|
||||
}
|
||||
|
||||
public void Delete(int id)
|
||||
{
|
||||
var user = _context.User.Find(id);
|
||||
if (user != null)
|
||||
{
|
||||
_context.User.Remove(user);
|
||||
_context.SaveChanges();
|
||||
}
|
||||
}
|
||||
|
||||
private static string computeHash(string Password)
|
||||
{
|
||||
MD5 md5 = new MD5CryptoServiceProvider();
|
||||
var input = md5.ComputeHash(Encoding.UTF8.GetBytes(Password));
|
||||
var hashstring = "";
|
||||
foreach(var hashbyte in input)
|
||||
{
|
||||
hashstring += hashbyte.ToString("x2");
|
||||
}
|
||||
return hashstring;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,17 +1,17 @@
|
|||
using Microsoft.AspNetCore.Builder;
|
||||
using Microsoft.AspNetCore.Hosting;
|
||||
using Microsoft.AspNetCore.HttpsPolicy;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Hosting;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using BackEndAaaapero.Data;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.IdentityModel.Tokens;
|
||||
using Microsoft.AspNetCore.Authentication.JwtBearer;
|
||||
using System.Text;
|
||||
using AutoMapper;
|
||||
using Services;
|
||||
|
||||
namespace BackEndAaaapero
|
||||
{
|
||||
|
|
@ -32,7 +32,51 @@ namespace BackEndAaaapero
|
|||
opt.UseMySql(Configuration.GetConnectionString("DefaultConnection"));
|
||||
});
|
||||
|
||||
//--------------------------------------------------------------------------------
|
||||
|
||||
services.AddCors();
|
||||
services.AddControllers();
|
||||
services.AddAutoMapper(AppDomain.CurrentDomain.GetAssemblies());
|
||||
|
||||
// configure jwt authentication
|
||||
var key = Encoding.ASCII.GetBytes(Configuration["Secret"]);
|
||||
services.AddAuthentication(x =>
|
||||
{
|
||||
x.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
|
||||
x.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
|
||||
})
|
||||
.AddJwtBearer(x =>
|
||||
{
|
||||
x.Events = new JwtBearerEvents
|
||||
{
|
||||
OnTokenValidated = context =>
|
||||
{
|
||||
var userService = context.HttpContext.RequestServices.GetRequiredService<IUserService>();
|
||||
var userId = int.Parse(context.Principal.Identity.Name);
|
||||
var user = userService.GetById(userId);
|
||||
if (user == null)
|
||||
{
|
||||
// return unauthorized if user no longer exists
|
||||
context.Fail("Unauthorized");
|
||||
}
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
};
|
||||
x.RequireHttpsMetadata = false;
|
||||
x.SaveToken = true;
|
||||
x.TokenValidationParameters = new TokenValidationParameters
|
||||
{
|
||||
ValidateIssuerSigningKey = true,
|
||||
IssuerSigningKey = new SymmetricSecurityKey(key),
|
||||
ValidateIssuer = false,
|
||||
ValidateAudience = false
|
||||
};
|
||||
});
|
||||
|
||||
// configure DI for application services
|
||||
services.AddScoped<IUserService, UserService>();
|
||||
//------------------------------------------------------------------------
|
||||
|
||||
}
|
||||
|
||||
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
|
||||
|
|
@ -43,10 +87,17 @@ namespace BackEndAaaapero
|
|||
app.UseDeveloperExceptionPage();
|
||||
}
|
||||
|
||||
app.UseCors(x => x
|
||||
.AllowAnyOrigin()
|
||||
.AllowAnyMethod()
|
||||
.AllowAnyHeader());
|
||||
|
||||
app.UseHttpsRedirection();
|
||||
|
||||
app.UseRouting();
|
||||
|
||||
app.UseAuthentication();
|
||||
|
||||
app.UseAuthorization();
|
||||
|
||||
app.UseEndpoints(endpoints =>
|
||||
|
|
|
|||
Loading…
Reference in New Issue