db and auth refactoring
This commit is contained in:
parent
0e1c16ab91
commit
aa472f9e29
45 changed files with 2182 additions and 697 deletions
184
Sledgemapper.Api/Controllers/AuthManagementController.cs
Normal file
184
Sledgemapper.Api/Controllers/AuthManagementController.cs
Normal 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"
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
39
Sledgemapper.Api/Controllers/CampaignController.cs
Normal file
39
Sledgemapper.Api/Controllers/CampaignController.cs
Normal 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;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -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));
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue