aboutsummaryrefslogtreecommitdiff
path: root/Timeline/Controllers
diff options
context:
space:
mode:
Diffstat (limited to 'Timeline/Controllers')
-rw-r--r--Timeline/Controllers/TokenController.cs80
-rw-r--r--Timeline/Controllers/UserController.cs130
-rw-r--r--Timeline/Controllers/UserTestController.cs11
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();
}