db and auth refactoring

This commit is contained in:
Michele 2021-02-20 00:18:07 +00:00
parent 0e1c16ab91
commit aa472f9e29
45 changed files with 2182 additions and 697 deletions

View file

@ -0,0 +1,184 @@
using MediatR;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Options;
using Microsoft.IdentityModel.Tokens;
using Sledgemapper.Api.Commands;
using Sledgemapper.Api.Notifications;
using Sledgemapper.Entities;
using Sledgemapper.Models.Users;
using Sledgemapper.Shared.Entities;
using System;
using System.Collections.Generic;
using System.IdentityModel.Tokens.Jwt;
using System.Linq;
using System.Security.Claims;
using System.Text;
using System.Threading.Tasks;
namespace Sledgemapper.Api.Controllers
{
[Route("[controller]")] // api/authmanagement
[ApiController]
public class AuthManagementController : ControllerBase
{
private readonly UserManager<User> _userManager;
private readonly JwtConfig _jwtConfig;
public AuthManagementController(UserManager<User> userManager,
IOptionsMonitor<JwtConfig> optionsMonitor)
{
_userManager = userManager;
_jwtConfig = optionsMonitor.CurrentValue;
}
[HttpPost]
[Route("Register")]
public async Task<IActionResult> Register([FromBody] Sledgemapper.Models.Users.RegisterModel user)
{
// Check if the incoming request is valid
if (ModelState.IsValid)
{
// check i the user with the same email exist
var existingUser = await _userManager.FindByEmailAsync(user.Email);
if (existingUser != null)
{
return BadRequest(new Sledgemapper.Models.Users.RegistrationResponse()
{
Result = false,
Errors = new List<string>(){
"Email already exist"
}
});
}
var newUser = new User() { Email = user.Email, UserName = user.UserName };
var isCreated = await _userManager.CreateAsync(newUser, user.Password);
if (isCreated.Succeeded)
{
var jwtToken = GenerateJwtToken(newUser);
return Ok(new Sledgemapper.Models.Users.RegistrationResponse()
{
Result = true,
Token = jwtToken
});
}
return new JsonResult(new Sledgemapper.Models.Users.RegistrationResponse()
{
Result = false,
Errors = isCreated.Errors.Select(x => x.Description).ToList()
}
)
{ StatusCode = 500 };
}
return BadRequest(new Sledgemapper.Models.Users.RegistrationResponse()
{
Result = false,
Errors = new List<string>(){
"Invalid payload"
}
});
}
private string GenerateJwtToken(User user)
{
// Now its ime to define the jwt token which will be responsible of creating our tokens
var jwtTokenHandler = new JwtSecurityTokenHandler();
// We get our secret from the appsettings
var key = Encoding.ASCII.GetBytes(_jwtConfig.Secret);
// we define our token descriptor
// We need to utilise claims which are properties in our token which gives information about the token
// which belong to the specific user who it belongs to
// so it could contain their id, name, email the good part is that these information
// are generated by our server and identity framework which is valid and trusted
var tokenDescriptor = new SecurityTokenDescriptor
{
Subject = new ClaimsIdentity(new[]
{
new Claim("Id", user.Id.ToString()),
new Claim(JwtRegisteredClaimNames.Sub, user.Email),
new Claim(JwtRegisteredClaimNames.Email, user.Email),
// the JTI is used for our refresh token which we will be convering in the next video
new Claim(JwtRegisteredClaimNames.Jti, Guid.NewGuid().ToString())
}),
// the life span of the token needs to be shorter and utilise refresh token to keep the user signedin
// but since this is a demo app we can extend it to fit our current need
Expires = DateTime.UtcNow.AddHours(6),
// here we are adding the encryption alogorithim information which will be used to decrypt our token
SigningCredentials = new SigningCredentials(new SymmetricSecurityKey(key), SecurityAlgorithms.HmacSha512Signature)
};
var token = jwtTokenHandler.CreateToken(tokenDescriptor);
var jwtToken = jwtTokenHandler.WriteToken(token);
return jwtToken;
}
[HttpPost]
[Route("Login")]
public async Task<IActionResult> Login([FromBody] UserLoginRequest user)
{
if (ModelState.IsValid)
{
// check if the user with the same email exist
var existingUser = await _userManager.FindByEmailAsync(user.Email);
if (existingUser == null)
{
// We dont want to give to much information on why the request has failed for security reasons
return BadRequest(new RegistrationResponse()
{
Result = false,
Errors = new List<string>(){
"Invalid authentication request"
}
});
}
// Now we need to check if the user has inputed the right password
var isCorrect = await _userManager.CheckPasswordAsync(existingUser, user.Password);
if (isCorrect)
{
var jwtToken = GenerateJwtToken(existingUser);
return Ok(new RegistrationResponse()
{
Result = true,
Token = jwtToken
});
}
else
{
// We dont want to give to much information on why the request has failed for security reasons
return BadRequest(new RegistrationResponse()
{
Result = false,
Errors = new List<string>(){
"Invalid authentication request"
}
});
}
}
return BadRequest(new RegistrationResponse()
{
Result = false,
Errors = new List<string>(){
"Invalid payload"
}
});
}
}
}

View file

@ -0,0 +1,39 @@
using MediatR;
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Sledgemapper.Api.Commands;
using Sledgemapper.Api.Notifications;
using Sledgemapper.Shared.Entities;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace Sledgemapper.Api.Controllers
{
[Authorize(AuthenticationSchemes = JwtBearerDefaults.AuthenticationScheme)]
[Route("[controller]")]
public class CampaignController : ControllerBase
{
private readonly IMediator _mediator;
private string UserId => HttpContext.User.Claims.FirstOrDefault(m => m.Type == "Id").Value;
public CampaignController(IMediator mediator) => _mediator = mediator;
[HttpPost]
[Route("{campaignName}")]
public async Task<bool> Post(string campaignName)
{
var result = await _mediator.Send(new NewCampaignCommand(campaignName, UserId.ToString()));
return result;
}
[HttpGet]
public async Task<List<Core.Entities.Campaign>> Get()
{
var result = await _mediator.Send(new GetCampaignsCommand(UserId));
return result;
}
}
}

View file

@ -9,98 +9,82 @@ using System.Threading.Tasks;
namespace Sledgemapper.Api.Controllers
{
[Authorize]
[Route("[controller]/{sessionName}")]
public class SessionController : ControllerBase
[Route("[controller]/{mapName}")]
public class MapController : ControllerBase
{
private readonly IMediator _mediator;
private int UserId => int.Parse(HttpContext.User.Identity.Name);
public SessionController(IMediator mediator) => _mediator = mediator;
public MapController(IMediator mediator) => _mediator = mediator;
[HttpPost]
public async Task<bool> Post(string sessionName)
public async Task<bool> Post(string mapName)
{
var result = await _mediator.Send(new NewSessionCommand(sessionName, UserId));
var result = await _mediator.Send(new NewSessionCommand(mapName, UserId));
return result;
}
[HttpGet]
public async Task<Session> Get(string sessionName)
public async Task<Session> Get(string mapName)
{
var result = await _mediator.Send(new GetMapSnapshotCommand(sessionName));
var result = await _mediator.Send(new GetMapSnapshotCommand(mapName));
return result;
}
// [HttpPost("ping")]
// public async Task Post(string sessionName, [FromBody] Ping pingLocation)
// {
// await _mediator.Send(new PingCommand(sessionName, pingLocation, UserId));
// }
[HttpPost("snapshot")]
public async Task Post(string sessionName, [FromBody] Session session)
public async Task Post(string mapName, [FromBody] Session session)
{
await _mediator.Send(new NewSnapshotCommand(sessionName, session, UserId));
}
[HttpPost("tile")]
public async Task Post(string sessionName, [FromBody] Tile tile)
{
await _mediator.Send(new NewTileCommand(sessionName, tile, UserId));
await _mediator.Send(new NewSnapshotCommand(mapName, session, UserId));
}
[HttpPost("overlay")]
public async Task Post(string sessionName, [FromBody] Overlay overlay)
public async Task Post(string mapName, [FromBody] Overlay overlay)
{
await _mediator.Send(new NewOverlayCommand(sessionName, overlay, UserId));
await _mediator.Send(new NewOverlayCommand(mapName, overlay, UserId));
}
[HttpPost("wall")]
public async Task Post(string sessionName, [FromBody] Wall wall)
public async Task Post(string mapName, [FromBody] Wall wall)
{
await _mediator.Send(new NewWallCommand(sessionName, wall, UserId));
await _mediator.Send(new NewWallCommand(mapName, wall, UserId));
}
[HttpPost("note")]
public async Task Post(string sessionName, [FromBody] Note note)
public async Task Post(string mapName, [FromBody] Note note)
{
await _mediator.Send(new NewNoteCommand(sessionName, note, UserId));
await _mediator.Send(new NewNoteCommand(mapName, note, UserId));
}
[HttpPost("room")]
public async Task Post(string sessionName, [FromBody] Room room)
public async Task Post(string mapName, [FromBody] Room room)
{
await _mediator.Send(new NewRoomCommand(sessionName, room, UserId));
await _mediator.Send(new NewRoomCommand(mapName, room, UserId));
}
[HttpPost("line")]
public async Task Post(string sessionName, [FromBody] Line line)
public async Task Post(string mapName, [FromBody] Line line)
{
await _mediator.Send(new NewLineCommand(sessionName, line, UserId));
}
[HttpDelete("tile")]
public async Task Delete(string sessionName, [FromBody] Tile tile)
{
await _mediator.Send(new DeleteTileCommand(sessionName, tile, UserId));
await _mediator.Send(new NewLineCommand(mapName, line, UserId));
}
[HttpDelete("overlay")]
public async Task Delete(string sessionName, [FromBody] Overlay overlay)
public async Task Delete(string mapName, [FromBody] Overlay overlay)
{
await _mediator.Send(new DeleteOverlayCommand(sessionName, overlay, UserId));
await _mediator.Send(new DeleteOverlayCommand(mapName, overlay, UserId));
}
[HttpDelete("wall")]
public async Task Delete(string sessionName, [FromBody] Wall wall)
public async Task Delete(string mapName, [FromBody] Wall wall)
{
await _mediator.Send(new DeleteWallCommand(sessionName, wall, UserId));
await _mediator.Send(new DeleteWallCommand(mapName, wall, UserId));
}
[HttpDelete("note")]
public async Task Delete(string sessionName, [FromBody] Note note)
public async Task Delete(string mapName, [FromBody] Note note)
{
await _mediator.Send(new DeleteNoteCommand(sessionName, note, UserId));
await _mediator.Send(new DeleteNoteCommand(mapName, note, UserId));
}
}
}

View file

@ -1,136 +0,0 @@
using System;
using System.Collections.Generic;
using Microsoft.AspNetCore.Mvc;
using AutoMapper;
using System.IdentityModel.Tokens.Jwt;
using Microsoft.Extensions.Options;
using System.Text;
using Microsoft.IdentityModel.Tokens;
using System.Security.Claims;
using Microsoft.AspNetCore.Authorization;
using Sledgemapper.Entities;
using Sledgemapper.Models.Users;
using Sledgemapper.Helpers;
using Sledgemapper.Api.Infrastructure.Services;
namespace Sledgemapper.Controllers
{
[Authorize]
[ApiController]
[Route("[controller]")]
public class UsersController : ControllerBase
{
private IUserService _userService;
private IMapper _mapper;
private readonly AppSettings _appSettings;
public UsersController(
IUserService userService,
IMapper mapper,
IOptions<AppSettings> appSettings)
{
_userService = userService;
_mapper = mapper;
_appSettings = appSettings.Value;
}
[AllowAnonymous]
[HttpPost("authenticate")]
public IActionResult Authenticate([FromBody]AuthenticateModel model)
{
var user = _userService.Authenticate(model.Username, model.Password);
if (user == null)
return BadRequest(new { message = "Username or password is incorrect" });
var tokenHandler = new JwtSecurityTokenHandler();
var key = Encoding.ASCII.GetBytes(_appSettings.Secret);
var tokenDescriptor = new SecurityTokenDescriptor
{
Subject = new ClaimsIdentity(new Claim[]
{
new Claim(ClaimTypes.Name, user.Id.ToString())
}),
Expires = DateTime.UtcNow.AddDays(7),
SigningCredentials = new SigningCredentials(new SymmetricSecurityKey(key), SecurityAlgorithms.HmacSha256Signature)
};
var token = tokenHandler.CreateToken(tokenDescriptor);
var tokenString = tokenHandler.WriteToken(token);
// return basic user info and authentication token
return Ok(new
{
Id = user.Id,
Username = user.Username,
FirstName = user.FirstName,
LastName = user.LastName,
Initials = user.Initials,
Token = tokenString
});
}
[AllowAnonymous]
[HttpPost("register")]
public IActionResult Register([FromBody]RegisterModel model)
{
// map model to entity
var user = _mapper.Map<User>(model);
try
{
// create user
_userService.Create(user, model.Password);
return Ok();
}
catch (AppException ex)
{
// return error message if there was an exception
return BadRequest(new { message = ex.Message });
}
}
[HttpGet]
public IActionResult GetAll()
{
var users = _userService.GetAll();
var model = _mapper.Map<IList<UserModel>>(users);
return Ok(model);
}
[HttpGet("{id}")]
public IActionResult GetById(int id)
{
var user = _userService.GetById(id);
var model = _mapper.Map<UserModel>(user);
return Ok(model);
}
[HttpPut("{id}")]
public IActionResult Update(int id, [FromBody]UpdateModel model)
{
// map model to entity and set id
var user = _mapper.Map<User>(model);
user.Id = id;
try
{
// update user
_userService.Update(user, model.Password);
return Ok();
}
catch (AppException ex)
{
// return error message if there was an exception
return BadRequest(new { message = ex.Message });
}
}
[HttpDelete("{id}")]
public IActionResult Delete(int id)
{
_userService.Delete(id);
return Ok();
}
}
}