aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author杨宇千 <crupest@outlook.com>2019-07-23 16:47:53 +0800
committer杨宇千 <crupest@outlook.com>2019-07-23 16:47:53 +0800
commitd088a03986713a71e274fc16144ca42b7f020e3f (patch)
tree2740cfa1964024d080d1b842b20e918a3e8d8981
parent35300c1b1ce6377393d4c9353416daae23b6d17c (diff)
downloadtimeline-d088a03986713a71e274fc16144ca42b7f020e3f.tar.gz
timeline-d088a03986713a71e274fc16144ca42b7f020e3f.tar.bz2
timeline-d088a03986713a71e274fc16144ca42b7f020e3f.zip
WIP: Develop UserService. Remove unused components.
-rw-r--r--Timeline/Configs/JwtConfig.cs4
-rw-r--r--Timeline/Entities/PutResult.cs17
-rw-r--r--Timeline/Entities/UserUtility.cs1
-rw-r--r--Timeline/Formatters/StringInputFormatter.cs29
-rw-r--r--Timeline/Services/JwtService.cs3
-rw-r--r--Timeline/Services/QCloudCosService.cs1
-rw-r--r--Timeline/Services/UserService.cs204
-rw-r--r--Timeline/Startup.cs12
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();
}