diff options
Diffstat (limited to 'Timeline/Controllers')
-rw-r--r-- | Timeline/Controllers/TokenController.cs | 80 | ||||
-rw-r--r-- | Timeline/Controllers/UserController.cs | 130 | ||||
-rw-r--r-- | Timeline/Controllers/UserTestController.cs | 11 |
3 files changed, 119 insertions, 102 deletions
diff --git a/Timeline/Controllers/TokenController.cs b/Timeline/Controllers/TokenController.cs index 0be5fb2f..023bd53f 100644 --- a/Timeline/Controllers/TokenController.cs +++ b/Timeline/Controllers/TokenController.cs @@ -12,8 +12,21 @@ namespace Timeline.Controllers { private static class LoggingEventIds { - public const int LogInSucceeded = 4000; - public const int LogInFailed = 4001; + public const int LogInSucceeded = 1000; + public const int LogInFailed = 1001; + + public const int VerifySucceeded = 2000; + public const int VerifyFailed = 2001; + } + + private static class ErrorCodes + { + public const int Create_UserNotExist = -1001; + public const int Create_BadPassword = -1002; + + public const int Verify_BadToken = -2001; + public const int Verify_UserNotExist = -2002; + public const int Verify_BadVersion = -2003; } private readonly IUserService _userService; @@ -27,48 +40,63 @@ namespace Timeline.Controllers [HttpPost("create")] [AllowAnonymous] - public async Task<ActionResult<CreateTokenResponse>> Create([FromBody] CreateTokenRequest request) + public async Task<IActionResult> Create([FromBody] CreateTokenRequest request) { - var result = await _userService.CreateToken(request.Username, request.Password); - - if (result == null) + try { - _logger.LogInformation(LoggingEventIds.LogInFailed, "Attemp to login with username: {} and password: {} failed.", request.Username, request.Password); + var result = await _userService.CreateToken(request.Username, request.Password); + _logger.LogInformation(LoggingEventIds.LogInSucceeded, "Login succeeded. Username: {} .", request.Username); return Ok(new CreateTokenResponse { - Success = false + Token = result.Token, + User = result.User }); } - - _logger.LogInformation(LoggingEventIds.LogInSucceeded, "Login with username: {} succeeded.", request.Username); - - return Ok(new CreateTokenResponse + catch(UserNotExistException e) + { + var code = ErrorCodes.Create_UserNotExist; + _logger.LogInformation(LoggingEventIds.LogInFailed, e, "Attemp to login failed because user does not exist. Code: {} Username: {} Password: {} .", code, request.Username, request.Password); + return BadRequest(new CommonResponse(code, "Bad username or password.")); + } + catch (BadPasswordException e) { - Success = true, - Token = result.Token, - UserInfo = result.UserInfo - }); + var code = ErrorCodes.Create_BadPassword; + _logger.LogInformation(LoggingEventIds.LogInFailed, e, "Attemp to login failed because password is wrong. Code: {} Username: {} Password: {} .", code, request.Username, request.Password); + return BadRequest(new CommonResponse(code, "Bad username or password.")); + } } [HttpPost("verify")] [AllowAnonymous] - public async Task<ActionResult<VerifyTokenResponse>> Verify([FromBody] VerifyTokenRequest request) + public async Task<IActionResult> Verify([FromBody] VerifyTokenRequest request) { - var result = await _userService.VerifyToken(request.Token); - - if (result == null) + try { + var result = await _userService.VerifyToken(request.Token); + _logger.LogInformation(LoggingEventIds.VerifySucceeded, "Verify token succeeded. Username: {} Token: {} .", result.Username, request.Token); return Ok(new VerifyTokenResponse { - IsValid = false, + User = result }); } - - return Ok(new VerifyTokenResponse + catch (JwtTokenVerifyException e) { - IsValid = true, - UserInfo = result - }); + var code = ErrorCodes.Verify_BadToken; + _logger.LogInformation(LoggingEventIds.VerifyFailed, e, "Attemp to verify a bad token because of bad format. Code: {} Token: {}.", code, request.Token); + return BadRequest(new CommonResponse(code, "A token of bad format.")); + } + catch (UserNotExistException e) + { + var code = ErrorCodes.Verify_UserNotExist; + _logger.LogInformation(LoggingEventIds.VerifyFailed, e, "Attemp to verify a bad token because user does not exist. Code: {} Token: {}.", code, request.Token); + return BadRequest(new CommonResponse(code, "The user does not exist. Administrator might have deleted this user.")); + } + catch (BadTokenVersionException e) + { + var code = ErrorCodes.Verify_BadToken; + _logger.LogInformation(LoggingEventIds.VerifyFailed, e, "Attemp to verify a bad token because version is old. Code: {} Token: {}.", code, request.Token); + return BadRequest(new CommonResponse(code, "The token is expired. Try recreate a token.")); + } } } } diff --git a/Timeline/Controllers/UserController.cs b/Timeline/Controllers/UserController.cs index 6f708e8a..413999ce 100644 --- a/Timeline/Controllers/UserController.cs +++ b/Timeline/Controllers/UserController.cs @@ -1,9 +1,9 @@ using Microsoft.AspNetCore.Authorization; -using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc; +using Microsoft.Extensions.Logging; using System; -using System.IO; using System.Threading.Tasks; +using Timeline.Authenticate; using Timeline.Entities; using Timeline.Entities.Http; using Timeline.Services; @@ -12,125 +12,113 @@ namespace Timeline.Controllers { public class UserController : Controller { + private static class ErrorCodes + { + public const int Get_NotExists = -1001; + + public const int Put_NoPassword = -2001; + + public const int Patch_NotExists = -3001; + + public const int ChangePassword_BadOldPassword = -4001; + } + + private readonly ILogger<UserController> _logger; private readonly IUserService _userService; - public UserController(IUserService userService) + public UserController(ILogger<UserController> logger, IUserService userService) { + _logger = logger; _userService = userService; } - [HttpGet("users"), Authorize(Roles = "admin")] + [HttpGet("users"), AdminAuthorize] public async Task<ActionResult<UserInfo[]>> List() { return Ok(await _userService.ListUsers()); } - [HttpGet("user/{username}"), Authorize] + [HttpGet("user/{username}"), AdminAuthorize] public async Task<IActionResult> Get([FromRoute] string username) { var user = await _userService.GetUser(username); if (user == null) { - return NotFound(); + _logger.LogInformation("Attempt to get a non-existent user. Username: {} .", username); + return NotFound(new CommonResponse(ErrorCodes.Get_NotExists, "The user does not exist.")); } return Ok(user); } - [HttpPut("user/{username}"), Authorize(Roles = "admin")] + [HttpPut("user/{username}"), AdminAuthorize] public async Task<IActionResult> Put([FromBody] UserPutRequest request, [FromRoute] string username) { + if (request.Password == null) + { + _logger.LogInformation("Attempt to put a user without a password. Username: {} .", username); + return BadRequest(); + } + var result = await _userService.PutUser(username, request.Password, request.IsAdmin); switch (result) { - case PutUserResult.Created: - return CreatedAtAction("Get", new { username }, UserPutResponse.Created); - case PutUserResult.Modified: - return Ok(UserPutResponse.Modified); + case PutResult.Created: + _logger.LogInformation("Created a user. Username: {} .", username); + return CreatedAtAction("Get", new { username }, CommonPutResponse.Created); + case PutResult.Modified: + _logger.LogInformation("Modified a user. Username: {} .", username); + return Ok(CommonPutResponse.Modified); default: throw new Exception("Unreachable code."); } } - [HttpPatch("user/{username}"), Authorize(Roles = "admin")] + [HttpPatch("user/{username}"), AdminAuthorize] public async Task<IActionResult> Patch([FromBody] UserPatchRequest request, [FromRoute] string username) { - var result = await _userService.PatchUser(username, request.Password, request.IsAdmin); - switch (result) + try { - case PatchUserResult.Success: - return Ok(); - case PatchUserResult.NotExists: - return NotFound(); - default: - throw new Exception("Unreachable code."); + await _userService.PatchUser(username, request.Password, request.IsAdmin); + return Ok(); } - } - - [HttpDelete("user/{username}"), Authorize(Roles = "admin")] - public async Task<IActionResult> Delete([FromRoute] string username) - { - var result = await _userService.DeleteUser(username); - switch (result) + catch (UserNotExistException e) { - case DeleteUserResult.Deleted: - return Ok(UserDeleteResponse.Deleted); - case DeleteUserResult.NotExists: - return Ok(UserDeleteResponse.NotExists); - default: - throw new Exception("Uncreachable code."); + _logger.LogInformation(e, "Attempt to patch a non-existent user. Username: {} .", username); + return BadRequest(new CommonResponse(ErrorCodes.Patch_NotExists, "The user does not exist.")); } } - [HttpGet("user/{username}/avatar"), Authorize] - public async Task<IActionResult> GetAvatar([FromRoute] string username) - { - var url = await _userService.GetAvatarUrl(username); - if (url == null) - return NotFound(); - return Redirect(url); - } - - [HttpPut("user/{username}/avatar"), Authorize] - [Consumes("image/png", "image/gif", "image/jpeg", "image/svg+xml")] - public async Task<IActionResult> PutAvatar([FromRoute] string username, [FromHeader(Name="Content-Type")] string contentType) + [HttpDelete("user/{username}"), AdminAuthorize] + public async Task<IActionResult> Delete([FromRoute] string username) { - bool isAdmin = User.IsInRole("admin"); - if (!isAdmin) + try { - if (username != User.Identity.Name) - return StatusCode(StatusCodes.Status403Forbidden, PutAvatarResponse.Forbidden); + await _userService.DeleteUser(username); + _logger.LogInformation("A user is deleted. Username: {} .", username); + return Ok(CommonDeleteResponse.Deleted); } - - var stream = new MemoryStream(); - await Request.Body.CopyToAsync(stream); - var result = await _userService.PutAvatar(username, stream.ToArray(), contentType); - switch (result) + catch (UserNotExistException e) { - case PutAvatarResult.Success: - return Ok(PutAvatarResponse.Success); - case PutAvatarResult.UserNotExists: - return BadRequest(PutAvatarResponse.NotExists); - default: - throw new Exception("Unknown put avatar result."); + _logger.LogInformation(e, "Attempt to delete a non-existent user. Username: {} .", username); + return Ok(CommonDeleteResponse.NotExists); } } - [HttpPost("userop/changepassword"), Authorize] public async Task<IActionResult> ChangePassword([FromBody] ChangePasswordRequest request) { - var result = await _userService.ChangePassword(User.Identity.Name, request.OldPassword, request.NewPassword); - switch (result) + try { - case ChangePasswordResult.Success: - return Ok(ChangePasswordResponse.Success); - case ChangePasswordResult.BadOldPassword: - return Ok(ChangePasswordResponse.BadOldPassword); - case ChangePasswordResult.NotExists: - return Ok(ChangePasswordResponse.NotExists); - default: - throw new Exception("Uncreachable code."); + await _userService.ChangePassword(User.Identity.Name, request.OldPassword, request.NewPassword); + _logger.LogInformation("A user changed password. Username: {} .", User.Identity.Name); + return Ok(); + } + catch (BadPasswordException e) + { + _logger.LogInformation(e, "A user attempt to change password but old password is wrong. Username: {} .", User.Identity.Name); + return BadRequest(new CommonResponse(ErrorCodes.ChangePassword_BadOldPassword, "Old password is wrong.")); } + // User can't be non-existent or the token is bad. } } } diff --git a/Timeline/Controllers/UserTestController.cs b/Timeline/Controllers/UserTestController.cs index f1edb0d5..21686b81 100644 --- a/Timeline/Controllers/UserTestController.cs +++ b/Timeline/Controllers/UserTestController.cs @@ -1,5 +1,6 @@ using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; +using Timeline.Authenticate; namespace Timeline.Controllers { @@ -8,21 +9,21 @@ namespace Timeline.Controllers { [HttpGet("[action]")] [Authorize] - public ActionResult NeedAuthorize() + public ActionResult Authorize() { return Ok(); } [HttpGet("[action]")] - [Authorize(Roles = "user,admin")] - public ActionResult BothUserAndAdmin() + [UserAuthorize] + public new ActionResult User() { return Ok(); } [HttpGet("[action]")] - [Authorize(Roles = "admin")] - public ActionResult OnlyAdmin() + [AdminAuthorize] + public ActionResult Admin() { return Ok(); } |