aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author杨宇千 <crupest@outlook.com>2019-07-23 18:01:04 +0800
committer杨宇千 <crupest@outlook.com>2019-07-23 18:01:04 +0800
commitc84faf2b8f5a55ae170e92ead6516e573a318e65 (patch)
treea63911cb371b8ca01370e9c0d2aceb1811d00a8e
parent79d4c444ace7cb10fbd638936c2e47a6314d2758 (diff)
downloadtimeline-c84faf2b8f5a55ae170e92ead6516e573a318e65.tar.gz
timeline-c84faf2b8f5a55ae170e92ead6516e573a318e65.tar.bz2
timeline-c84faf2b8f5a55ae170e92ead6516e573a318e65.zip
WIP: Change UserController.
-rw-r--r--Timeline/Authenticate/Attribute.cs21
-rw-r--r--Timeline/Controllers/TokenController.cs30
-rw-r--r--Timeline/Controllers/UserController.cs130
-rw-r--r--Timeline/Entities/Http/Common.cs24
-rw-r--r--Timeline/Entities/Http/User.cs40
-rw-r--r--Timeline/Entities/UserUtility.cs4
-rw-r--r--Timeline/Models/DatabaseContext.cs6
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
{