diff options
author | 杨宇千 <crupest@outlook.com> | 2019-07-23 16:47:53 +0800 |
---|---|---|
committer | 杨宇千 <crupest@outlook.com> | 2019-07-23 16:47:53 +0800 |
commit | d088a03986713a71e274fc16144ca42b7f020e3f (patch) | |
tree | 2740cfa1964024d080d1b842b20e918a3e8d8981 | |
parent | 35300c1b1ce6377393d4c9353416daae23b6d17c (diff) | |
download | timeline-d088a03986713a71e274fc16144ca42b7f020e3f.tar.gz timeline-d088a03986713a71e274fc16144ca42b7f020e3f.tar.bz2 timeline-d088a03986713a71e274fc16144ca42b7f020e3f.zip |
WIP: Develop UserService. Remove unused components.
-rw-r--r-- | Timeline/Configs/JwtConfig.cs | 4 | ||||
-rw-r--r-- | Timeline/Entities/PutResult.cs | 17 | ||||
-rw-r--r-- | Timeline/Entities/UserUtility.cs | 1 | ||||
-rw-r--r-- | Timeline/Formatters/StringInputFormatter.cs | 29 | ||||
-rw-r--r-- | Timeline/Services/JwtService.cs | 3 | ||||
-rw-r--r-- | Timeline/Services/QCloudCosService.cs | 1 | ||||
-rw-r--r-- | Timeline/Services/UserService.cs | 204 | ||||
-rw-r--r-- | Timeline/Startup.cs | 12 |
8 files changed, 72 insertions, 199 deletions
diff --git a/Timeline/Configs/JwtConfig.cs b/Timeline/Configs/JwtConfig.cs index 1b395650..4d5ef97f 100644 --- a/Timeline/Configs/JwtConfig.cs +++ b/Timeline/Configs/JwtConfig.cs @@ -8,8 +8,8 @@ namespace Timeline.Configs /// <summary> /// Set the default value of expire offset of jwt token. - /// Unit is second. Default is 3600 seconds, aka 1 hour. + /// Unit is second. Default is 3600 * 24 seconds, aka 1 day. /// </summary> - public long DefaultExpireOffset { get; set; } = 3600; + public long DefaultExpireOffset { get; set; } = 3600 * 24; } } diff --git a/Timeline/Entities/PutResult.cs b/Timeline/Entities/PutResult.cs new file mode 100644 index 00000000..4ed48572 --- /dev/null +++ b/Timeline/Entities/PutResult.cs @@ -0,0 +1,17 @@ +namespace Timeline.Entities +{ + /// <summary> + /// Represents the result of a "put" operation. + /// </summary> + public enum PutResult + { + /// <summary> + /// Indicates the item did not exist and now is created. + /// </summary> + Created, + /// <summary> + /// Indicates the item exists already and is modified. + /// </summary> + Modified + } +} diff --git a/Timeline/Entities/UserUtility.cs b/Timeline/Entities/UserUtility.cs index 1de7ac7d..c8e82fba 100644 --- a/Timeline/Entities/UserUtility.cs +++ b/Timeline/Entities/UserUtility.cs @@ -1,6 +1,5 @@ using System; using System.Linq; -using Timeline.Entities; using Timeline.Models; using Timeline.Services; diff --git a/Timeline/Formatters/StringInputFormatter.cs b/Timeline/Formatters/StringInputFormatter.cs deleted file mode 100644 index ca9216d7..00000000 --- a/Timeline/Formatters/StringInputFormatter.cs +++ /dev/null @@ -1,29 +0,0 @@ -using Microsoft.AspNetCore.Mvc.Formatters; -using Microsoft.Net.Http.Headers; -using System.IO; -using System.Text; -using System.Threading.Tasks; - -namespace Timeline.Formatters -{ - public class StringInputFormatter : TextInputFormatter - { - public StringInputFormatter() - { - SupportedMediaTypes.Add(MediaTypeHeaderValue.Parse("text/plain")); - - SupportedEncodings.Add(Encoding.UTF8); - SupportedEncodings.Add(Encoding.Unicode); - } - - public override Task<InputFormatterResult> ReadRequestBodyAsync(InputFormatterContext context, Encoding effectiveEncoding) - { - var request = context.HttpContext.Request; - using (var reader = new StreamReader(request.Body, effectiveEncoding)) - { - var stringContent = reader.ReadToEnd(); - return InputFormatterResult.SuccessAsync(stringContent); - } - } - } -} diff --git a/Timeline/Services/JwtService.cs b/Timeline/Services/JwtService.cs index b070ad62..f721971b 100644 --- a/Timeline/Services/JwtService.cs +++ b/Timeline/Services/JwtService.cs @@ -1,5 +1,4 @@ -using Microsoft.Extensions.Logging; -using Microsoft.Extensions.Options; +using Microsoft.Extensions.Options; using Microsoft.IdentityModel.Tokens; using System; using System.IdentityModel.Tokens.Jwt; diff --git a/Timeline/Services/QCloudCosService.cs b/Timeline/Services/QCloudCosService.cs index b37631e5..748173c4 100644 --- a/Timeline/Services/QCloudCosService.cs +++ b/Timeline/Services/QCloudCosService.cs @@ -6,7 +6,6 @@ using System.Diagnostics; using System.Linq; using System.Net; using System.Net.Http; -using System.Net.Http.Headers; using System.Security.Cryptography; using System.Text; using System.Text.RegularExpressions; diff --git a/Timeline/Services/UserService.cs b/Timeline/Services/UserService.cs index 49c9747d..ec8e5091 100644 --- a/Timeline/Services/UserService.cs +++ b/Timeline/Services/UserService.cs @@ -50,70 +50,6 @@ namespace Timeline.Services System.Runtime.Serialization.StreamingContext context) : base(info, context) { } } - public enum PutUserResult - { - /// <summary> - /// A new user is created. - /// </summary> - Created, - /// <summary> - /// A existing user is modified. - /// </summary> - Modified - } - - public enum PatchUserResult - { - /// <summary> - /// Succeed to modify user. - /// </summary> - Success, - /// <summary> - /// A user of given username does not exist. - /// </summary> - NotExists - } - - public enum DeleteUserResult - { - /// <summary> - /// A existing user is deleted. - /// </summary> - Deleted, - /// <summary> - /// A user of given username does not exist. - /// </summary> - NotExists - } - - public enum ChangePasswordResult - { - /// <summary> - /// Success to change password. - /// </summary> - Success, - /// <summary> - /// The user does not exists. - /// </summary> - NotExists, - /// <summary> - /// Old password is wrong. - /// </summary> - BadOldPassword - } - - public enum PutAvatarResult - { - /// <summary> - /// Success to upload avatar. - /// </summary> - Success, - /// <summary> - /// The user does not exists. - /// </summary> - UserNotExists - } - public interface IUserService { /// <summary> @@ -160,31 +96,29 @@ namespace Timeline.Services /// </summary> /// <param name="username">Username of user.</param> /// <param name="password">Password of user.</param> - /// <param name="roles">Array of roles of user.</param> - /// <returns>Return <see cref="PutUserResult.Created"/> if a new user is created. - /// Return <see cref="PutUserResult.Modified"/> if a existing user is modified.</returns> - Task<PutUserResult> PutUser(string username, string password, bool isAdmin); + /// <param name="isAdmin">Whether the user is administrator.</param> + /// <returns>Return <see cref="PutResult.Created"/> if a new user is created. + /// Return <see cref="PutResult.Modified"/> if a existing user is modified.</returns> + /// <exception cref="ArgumentNullException">Thrown when <paramref name="username"/> or <paramref name="password"/> is null.</exception> + Task<PutResult> PutUser(string username, string password, bool isAdmin); /// <summary> - /// Partially modify a use of given username. + /// Partially modify a user of given username. /// </summary> - /// <param name="username">Username of the user to modify.</param> - /// <param name="password">New password. If not modify, then null.</param> - /// <param name="roles">New roles. If not modify, then null.</param> - /// <returns>Return <see cref="PatchUserResult.Success"/> if modification succeeds. - /// Return <see cref="PatchUserResult.NotExists"/> if the user of given username doesn't exist.</returns> - Task<PatchUserResult> PatchUser(string username, string password, bool? isAdmin); + /// <param name="username">Username of the user to modify. Can't be null.</param> + /// <param name="password">New password. Null if not modify.</param> + /// <param name="isAdmin">Whether the user is administrator. Null if not modify.</param> + /// <exception cref="ArgumentNullException">Thrown if <paramref name="username"/> is null.</exception> + /// <exception cref="UserNotExistException">Thrown if the user with given username does not exist.</exception> + Task PatchUser(string username, string password, bool? isAdmin); /// <summary> /// Delete a user of given username. - /// Return <see cref="DeleteUserResult.Deleted"/> if the user is deleted. - /// Return <see cref="DeleteUserResult.NotExists"/> if the user of given username - /// does not exist. /// </summary> - /// <param name="username">Username of thet user to delete.</param> - /// <returns><see cref="DeleteUserResult.Deleted"/> if the user is deleted. - /// <see cref="DeleteUserResult.NotExists"/> if the user doesn't exist.</returns> - Task<DeleteUserResult> DeleteUser(string username); + /// <param name="username">Username of thet user to delete. Can't be null.</param> + /// <exception cref="ArgumentNullException">Thrown if <paramref name="username"/> is null.</exception> + /// <exception cref="UserNotExistException">Thrown if the user with given username does not exist.</exception> + Task DeleteUser(string username); /// <summary> /// Try to change a user's password with old password. @@ -192,27 +126,10 @@ namespace Timeline.Services /// <param name="username">The name of user to change password of.</param> /// <param name="oldPassword">The user's old password.</param> /// <param name="newPassword">The user's new password.</param> - /// <returns><see cref="ChangePasswordResult.Success"/> if success. - /// <see cref="ChangePasswordResult.NotExists"/> if user does not exist. - /// <see cref="ChangePasswordResult.BadOldPassword"/> if old password is wrong.</returns> - Task<ChangePasswordResult> ChangePassword(string username, string oldPassword, string newPassword); - - /// <summary> - /// Get the true avatar url of a user. - /// </summary> - /// <param name="username">The name of user.</param> - /// <returns>The url if user exists. Null if user does not exist.</returns> - Task<string> GetAvatarUrl(string username); - - /// <summary> - /// Put a avatar of a user. - /// </summary> - /// <param name="username">The name of user.</param> - /// <param name="data">The data of avatar image.</param> - /// <param name="mimeType">The mime type of the image.</param> - /// <returns>Return <see cref="PutAvatarResult.Success"/> if success. - /// Return <see cref="PutAvatarResult.UserNotExists"/> if user does not exist.</returns> - Task<PutAvatarResult> PutAvatar(string username, byte[] data, string mimeType); + /// <exception cref="ArgumentNullException">Thrown if <paramref name="username"/> or <paramref name="oldPassword"/> or <paramref name="newPassword"/> is null.</exception> + /// <exception cref="UserNotExistException">Thrown if the user with given username does not exist.</exception> + /// <exception cref="BadPasswordException">Thrown if the old password is wrong.</exception> + Task ChangePassword(string username, string oldPassword, string newPassword); } internal class UserCache @@ -348,8 +265,13 @@ namespace Timeline.Services .ToArrayAsync(); } - public async Task<PutUserResult> PutUser(string username, string password, bool isAdmin) + public async Task<PutResult> PutUser(string username, string password, bool isAdmin) { + if (username == null) + throw new ArgumentNullException(nameof(username)); + if (password == null) + throw new ArgumentNullException(nameof(password)); + var user = await _databaseContext.Users.Where(u => u.Name == username).SingleOrDefaultAsync(); if (user == null) @@ -362,7 +284,7 @@ namespace Timeline.Services Version = 0 }); await _databaseContext.SaveChangesAsync(); - return PutUserResult.Created; + return PutResult.Created; } user.EncryptedPassword = _passwordService.HashPassword(password); @@ -373,15 +295,17 @@ namespace Timeline.Services //clear cache RemoveCache(user.Id); - return PutUserResult.Modified; + return PutResult.Modified; } - public async Task<PatchUserResult> PatchUser(string username, string password, bool? isAdmin) + public async Task PatchUser(string username, string password, bool? isAdmin) { - var user = await _databaseContext.Users.Where(u => u.Name == username).SingleOrDefaultAsync(); + if (username == null) + throw new ArgumentNullException(nameof(username)); + var user = await _databaseContext.Users.Where(u => u.Name == username).SingleOrDefaultAsync(); if (user == null) - return PatchUserResult.NotExists; + throw new UserNotExistException(); bool modified = false; @@ -399,78 +323,50 @@ namespace Timeline.Services if (modified) { + user.Version += 1; await _databaseContext.SaveChangesAsync(); //clear cache RemoveCache(user.Id); } - - return PatchUserResult.Success; } - public async Task<DeleteUserResult> DeleteUser(string username) + public async Task DeleteUser(string username) { - var user = await _databaseContext.Users.Where(u => u.Name == username).SingleOrDefaultAsync(); + if (username == null) + throw new ArgumentNullException(nameof(username)); + var user = await _databaseContext.Users.Where(u => u.Name == username).SingleOrDefaultAsync(); if (user == null) - { - return DeleteUserResult.NotExists; - } + throw new UserNotExistException(); _databaseContext.Users.Remove(user); await _databaseContext.SaveChangesAsync(); //clear cache RemoveCache(user.Id); - - return DeleteUserResult.Deleted; } - public async Task<ChangePasswordResult> ChangePassword(string username, string oldPassword, string newPassword) + public async Task ChangePassword(string username, string oldPassword, string newPassword) { + if (username == null) + throw new ArgumentNullException(nameof(username)); + if (oldPassword == null) + throw new ArgumentNullException(nameof(oldPassword)); + if (newPassword == null) + throw new ArgumentNullException(nameof(newPassword)); + var user = await _databaseContext.Users.Where(u => u.Name == username).SingleOrDefaultAsync(); if (user == null) - return ChangePasswordResult.NotExists; + throw new UserNotExistException(); var verifyResult = _passwordService.VerifyPassword(user.EncryptedPassword, oldPassword); if (!verifyResult) - return ChangePasswordResult.BadOldPassword; + throw new BadPasswordException(); user.EncryptedPassword = _passwordService.HashPassword(newPassword); + user.Version += 1; await _databaseContext.SaveChangesAsync(); //clear cache RemoveCache(user.Id); - - return ChangePasswordResult.Success; - } - - public async Task<string> GetAvatarUrl(string username) - { - if (username == null) - throw new ArgumentNullException(nameof(username)); - - if ((await GetUser(username)) == null) - return null; - - var exists = await _cosService.IsObjectExists("avatar", username); - if (exists) - return _cosService.GenerateObjectGetUrl("avatar", username); - else - return _cosService.GenerateObjectGetUrl("avatar", "__default"); - } - - public async Task<PutAvatarResult> PutAvatar(string username, byte[] data, string mimeType) - { - if (username == null) - throw new ArgumentNullException(nameof(username)); - if (data == null) - throw new ArgumentNullException(nameof(data)); - if (mimeType == null) - throw new ArgumentNullException(nameof(mimeType)); - - if ((await GetUser(username)) == null) - return PutAvatarResult.UserNotExists; - - await _cosService.PutObject("avatar", username, data, mimeType); - return PutAvatarResult.Success; } } } diff --git a/Timeline/Startup.cs b/Timeline/Startup.cs index 374b918a..a6965190 100644 --- a/Timeline/Startup.cs +++ b/Timeline/Startup.cs @@ -1,4 +1,3 @@ -using Microsoft.AspNetCore.Authentication.JwtBearer; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.HttpOverrides; @@ -9,7 +8,6 @@ using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Timeline.Authenticate; using Timeline.Configs; -using Timeline.Formatters; using Timeline.Models; using Timeline.Services; @@ -31,10 +29,7 @@ namespace Timeline // This method gets called by the runtime. Use this method to add services to the container. public void ConfigureServices(IServiceCollection services) { - services.AddMvc(options => - { - options.InputFormatters.Add(new StringInputFormatter()); - }).SetCompatibilityVersion(CompatibilityVersion.Version_2_2); + services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2); services.AddCors(options => { @@ -50,7 +45,7 @@ namespace Timeline services.Configure<JwtConfig>(Configuration.GetSection(nameof(JwtConfig))); var jwtConfig = Configuration.GetSection(nameof(JwtConfig)).Get<JwtConfig>(); - services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme) + services.AddAuthentication(AuthConstants.Scheme) .AddScheme<AuthOptions, AuthHandler>(AuthConstants.Scheme, AuthConstants.DisplayName, o => { }); services.AddScoped<IUserService, UserService>(); @@ -73,9 +68,6 @@ namespace Timeline services.AddHttpClient(); - services.Configure<QCloudCosConfig>(Configuration.GetSection(nameof(QCloudCosConfig))); - services.AddSingleton<IQCloudCosService, QCloudCosService>(); - services.AddMemoryCache(); } |