diff options
author | 杨宇千 <crupest@outlook.com> | 2019-07-23 18:01:04 +0800 |
---|---|---|
committer | 杨宇千 <crupest@outlook.com> | 2019-07-23 18:01:04 +0800 |
commit | e34873c8cec905cd38c754d8968e848c9d0db5c2 (patch) | |
tree | a63911cb371b8ca01370e9c0d2aceb1811d00a8e /Timeline | |
parent | 1e5ac670386614b2d88da0af198a6b3df004f1dd (diff) | |
download | timeline-e34873c8cec905cd38c754d8968e848c9d0db5c2.tar.gz timeline-e34873c8cec905cd38c754d8968e848c9d0db5c2.tar.bz2 timeline-e34873c8cec905cd38c754d8968e848c9d0db5c2.zip |
WIP: Change UserController.
Diffstat (limited to 'Timeline')
-rw-r--r-- | Timeline/Authenticate/Attribute.cs | 21 | ||||
-rw-r--r-- | Timeline/Controllers/TokenController.cs | 30 | ||||
-rw-r--r-- | Timeline/Controllers/UserController.cs | 130 | ||||
-rw-r--r-- | Timeline/Entities/Http/Common.cs | 24 | ||||
-rw-r--r-- | Timeline/Entities/Http/User.cs | 40 | ||||
-rw-r--r-- | Timeline/Entities/UserUtility.cs | 4 | ||||
-rw-r--r-- | Timeline/Models/DatabaseContext.cs | 6 |
7 files changed, 124 insertions, 131 deletions
diff --git a/Timeline/Authenticate/Attribute.cs b/Timeline/Authenticate/Attribute.cs new file mode 100644 index 00000000..50b2681d --- /dev/null +++ b/Timeline/Authenticate/Attribute.cs @@ -0,0 +1,21 @@ +using Microsoft.AspNetCore.Authorization; +using Timeline.Models; + +namespace Timeline.Authenticate +{ + public class AdminAuthorizeAttribute : AuthorizeAttribute + { + public AdminAuthorizeAttribute() + { + Roles = UserRoles.Admin; + } + } + + public class UserAuthorizeAttribute : AuthorizeAttribute + { + public UserAuthorizeAttribute() + { + Roles = UserRoles.User; + } + } +} diff --git a/Timeline/Controllers/TokenController.cs b/Timeline/Controllers/TokenController.cs index 3a364ffe..023bd53f 100644 --- a/Timeline/Controllers/TokenController.cs +++ b/Timeline/Controllers/TokenController.cs @@ -21,12 +21,12 @@ namespace Timeline.Controllers private static class ErrorCodes { - public const int Create_UserNotExist = 1001; - public const int Create_BadPassword = 1002; + 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; + public const int Verify_BadToken = -2001; + public const int Verify_UserNotExist = -2002; + public const int Verify_BadVersion = -2003; } private readonly IUserService _userService; @@ -55,14 +55,14 @@ namespace Timeline.Controllers catch(UserNotExistException e) { var code = ErrorCodes.Create_UserNotExist; - _logger.LogInformation(LoggingEventIds.LogInFailed, e, "Attemp to login failed. Code: {} Username: {} Password: {} .", code, request.Username, request.Password); - return BadRequest(new CommonErrorResponse(code, "Bad username or password.")); + _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) { var code = ErrorCodes.Create_BadPassword; - _logger.LogInformation(LoggingEventIds.LogInFailed, e, "Attemp to login failed. Code: {} Username: {} Password: {} .", code, request.Username, request.Password); - return BadRequest(new CommonErrorResponse(code, "Bad username or password.")); + _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.")); } } @@ -82,20 +82,20 @@ namespace Timeline.Controllers catch (JwtTokenVerifyException e) { var code = ErrorCodes.Verify_BadToken; - _logger.LogInformation(LoggingEventIds.VerifyFailed, e, "Attemp to verify a bad token. Code: {} Token: {}.", code, request.Token); - return BadRequest(new CommonErrorResponse(code, "A token of bad format.")); + _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. Code: {} Token: {}.", code, request.Token); - return BadRequest(new CommonErrorResponse(code, "The user does not exist. Administrator might have deleted this user.")); + _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. Code: {} Token: {}.", code, request.Token); - return BadRequest(new CommonErrorResponse(code, "The token is expired. Try recreate a token.")); + _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/Entities/Http/Common.cs b/Timeline/Entities/Http/Common.cs index 7708927a..3a45a0ae 100644 --- a/Timeline/Entities/Http/Common.cs +++ b/Timeline/Entities/Http/Common.cs @@ -1,13 +1,13 @@ namespace Timeline.Entities.Http { - public class CommonErrorResponse + public class CommonResponse { - public CommonErrorResponse() + public CommonResponse() { } - public CommonErrorResponse(int code, string message) + public CommonResponse(int code, string message) { Code = code; Message = message; @@ -16,4 +16,22 @@ public int Code { get; set; } public string Message { get; set; } } + + public static class CommonPutResponse + { + public const int CreatedCode = 0; + public const int ModifiedCode = 1; + + public static CommonResponse Created { get; } = new CommonResponse(CreatedCode, "A new item is created."); + public static CommonResponse Modified { get; } = new CommonResponse(ModifiedCode, "An existent item is modified."); + } + + public static class CommonDeleteResponse + { + public const int DeletedCode = 0; + public const int NotExistsCode = 1; + + public static CommonResponse Deleted { get; } = new CommonResponse(DeletedCode, "An existent item is deleted."); + public static CommonResponse NotExists { get; } = new CommonResponse(NotExistsCode, "The item does not exist."); + } } diff --git a/Timeline/Entities/Http/User.cs b/Timeline/Entities/Http/User.cs index f5d233cd..91423c7b 100644 --- a/Timeline/Entities/Http/User.cs +++ b/Timeline/Entities/Http/User.cs @@ -12,49 +12,9 @@ public bool? IsAdmin { get; set; } } - public static class UserPutResponse - { - public const int CreatedCode = 0; - public const int ModifiedCode = 1; - - public static CommonErrorResponse Created { get; } = new CommonErrorResponse(CreatedCode, "A new user is created."); - public static CommonErrorResponse Modified { get; } = new CommonErrorResponse(ModifiedCode, "A existing user is modified."); - } - - public static class UserDeleteResponse - { - public const int DeletedCode = 0; - public const int NotExistsCode = 1; - - public static CommonErrorResponse Deleted { get; } = new CommonErrorResponse(DeletedCode, "A existing user is deleted."); - public static CommonErrorResponse NotExists { get; } = new CommonErrorResponse(NotExistsCode, "User with given name does not exists."); - } - public class ChangePasswordRequest { public string OldPassword { get; set; } public string NewPassword { get; set; } } - - public static class ChangePasswordResponse - { - public const int SuccessCode = 0; - public const int BadOldPasswordCode = 1; - public const int NotExistsCode = 2; - - public static CommonErrorResponse Success { get; } = new CommonErrorResponse(SuccessCode, "Success to change password."); - public static CommonErrorResponse BadOldPassword { get; } = new CommonErrorResponse(BadOldPasswordCode, "Old password is wrong."); - public static CommonErrorResponse NotExists { get; } = new CommonErrorResponse(NotExistsCode, "Username does not exists, please update token."); - } - - public static class PutAvatarResponse - { - public const int SuccessCode = 0; - public const int ForbiddenCode = 1; - public const int NotExistsCode = 2; - - public static CommonErrorResponse Success { get; } = new CommonErrorResponse(SuccessCode, "Success to upload avatar."); - public static CommonErrorResponse Forbidden { get; } = new CommonErrorResponse(ForbiddenCode, "You are not allowed to upload the user's avatar."); - public static CommonErrorResponse NotExists { get; } = new CommonErrorResponse(NotExistsCode, "The username does not exists. If you are a user, try update your token."); - } } diff --git a/Timeline/Entities/UserUtility.cs b/Timeline/Entities/UserUtility.cs index c8e82fba..cbbd391c 100644 --- a/Timeline/Entities/UserUtility.cs +++ b/Timeline/Entities/UserUtility.cs @@ -7,8 +7,8 @@ namespace Timeline.Entities { public static class UserUtility { - public const string UserRole = "user"; - public const string AdminRole = "admin"; + public const string UserRole = UserRoles.User; + public const string AdminRole = UserRoles.Admin; public static string[] UserRoleArray { get; } = new string[] { UserRole }; public static string[] AdminRoleArray { get; } = new string[] { UserRole, AdminRole }; diff --git a/Timeline/Models/DatabaseContext.cs b/Timeline/Models/DatabaseContext.cs index 87c0fd17..afd5a333 100644 --- a/Timeline/Models/DatabaseContext.cs +++ b/Timeline/Models/DatabaseContext.cs @@ -4,6 +4,12 @@ using System.ComponentModel.DataAnnotations.Schema; namespace Timeline.Models { + public static class UserRoles + { + public const string Admin = "admin"; + public const string User = "user"; + } + [Table("user")] public class User { |