aboutsummaryrefslogtreecommitdiff
path: root/BackEnd/Timeline
diff options
context:
space:
mode:
authorcrupest <crupest@outlook.com>2021-04-24 22:01:27 +0800
committercrupest <crupest@outlook.com>2021-04-24 22:01:27 +0800
commit7c37a5885437aaf97b9986b7cc2941b5e4316003 (patch)
treec3b9b733e269b4f187f24a12dc08e1f1c88bd7a6 /BackEnd/Timeline
parent6877db6a535e57fd1d7e01c966a6451dc6f186f0 (diff)
downloadtimeline-7c37a5885437aaf97b9986b7cc2941b5e4316003.tar.gz
timeline-7c37a5885437aaf97b9986b7cc2941b5e4316003.tar.bz2
timeline-7c37a5885437aaf97b9986b7cc2941b5e4316003.zip
refactor: Move token services.
Diffstat (limited to 'BackEnd/Timeline')
-rw-r--r--BackEnd/Timeline/Auth/MyAuthenticationHandler.cs1
-rw-r--r--BackEnd/Timeline/Configs/JwtConfiguration.cs14
-rw-r--r--BackEnd/Timeline/Configs/JwtOptions.cs8
-rw-r--r--BackEnd/Timeline/Configs/TokenOptions.cs11
-rw-r--r--BackEnd/Timeline/Controllers/TokenController.cs1
-rw-r--r--BackEnd/Timeline/Services/Token/JwtUserTokenBadFormatException.cs (renamed from BackEnd/Timeline/Services/JwtUserTokenBadFormatException.cs)3
-rw-r--r--BackEnd/Timeline/Services/Token/TokenServiceColletionExtensions.cs18
-rw-r--r--BackEnd/Timeline/Services/Token/UserTokenException.cs (renamed from BackEnd/Timeline/Services/UserTokenException.cs)2
-rw-r--r--BackEnd/Timeline/Services/Token/UserTokenHandler.cs (renamed from BackEnd/Timeline/Services/UserTokenHandler.cs)21
-rw-r--r--BackEnd/Timeline/Services/Token/UserTokenManager.cs (renamed from BackEnd/Timeline/Services/UserTokenManager.cs)25
-rw-r--r--BackEnd/Timeline/Startup.cs6
-rw-r--r--BackEnd/Timeline/appsettings.json4
12 files changed, 72 insertions, 42 deletions
diff --git a/BackEnd/Timeline/Auth/MyAuthenticationHandler.cs b/BackEnd/Timeline/Auth/MyAuthenticationHandler.cs
index f3d18a0e..fe27814a 100644
--- a/BackEnd/Timeline/Auth/MyAuthenticationHandler.cs
+++ b/BackEnd/Timeline/Auth/MyAuthenticationHandler.cs
@@ -14,6 +14,7 @@ using System.Threading.Tasks;
using Timeline.Models;
using Timeline.Models.Http;
using Timeline.Services;
+using Timeline.Services.Token;
namespace Timeline.Auth
{
diff --git a/BackEnd/Timeline/Configs/JwtConfiguration.cs b/BackEnd/Timeline/Configs/JwtConfiguration.cs
deleted file mode 100644
index af8052de..00000000
--- a/BackEnd/Timeline/Configs/JwtConfiguration.cs
+++ /dev/null
@@ -1,14 +0,0 @@
-namespace Timeline.Configs
-{
- public class JwtConfiguration
- {
- public string Issuer { get; set; } = default!;
- public string Audience { get; set; } = default!;
-
- /// <summary>
- /// Set the default value of expire offset of jwt token.
- /// Unit is second. Default is 3600 * 24 seconds, aka 1 day.
- /// </summary>
- public long DefaultExpireOffset { get; set; } = 3600 * 24;
- }
-}
diff --git a/BackEnd/Timeline/Configs/JwtOptions.cs b/BackEnd/Timeline/Configs/JwtOptions.cs
new file mode 100644
index 00000000..c400b8a6
--- /dev/null
+++ b/BackEnd/Timeline/Configs/JwtOptions.cs
@@ -0,0 +1,8 @@
+namespace Timeline.Configs
+{
+ public class JwtOptions
+ {
+ public string Issuer { get; set; } = default!;
+ public string Audience { get; set; } = default!;
+ }
+}
diff --git a/BackEnd/Timeline/Configs/TokenOptions.cs b/BackEnd/Timeline/Configs/TokenOptions.cs
new file mode 100644
index 00000000..e7d4d9e7
--- /dev/null
+++ b/BackEnd/Timeline/Configs/TokenOptions.cs
@@ -0,0 +1,11 @@
+namespace Timeline.Configs
+{
+ public class TokenOptions
+ {
+ /// <summary>
+ /// Set the default value of expire offset of jwt token.
+ /// Unit is second. Default is 3600 * 24 seconds, aka 1 day.
+ /// </summary>
+ public long DefaultExpireSeconds { get; set; } = 3600 * 24;
+ }
+}
diff --git a/BackEnd/Timeline/Controllers/TokenController.cs b/BackEnd/Timeline/Controllers/TokenController.cs
index 3ff8acf5..7df3891c 100644
--- a/BackEnd/Timeline/Controllers/TokenController.cs
+++ b/BackEnd/Timeline/Controllers/TokenController.cs
@@ -10,6 +10,7 @@ using Timeline.Models.Http;
using Timeline.Models.Mapper;
using Timeline.Services;
using Timeline.Services.Exceptions;
+using Timeline.Services.Token;
using static Timeline.Resources.Controllers.TokenController;
namespace Timeline.Controllers
diff --git a/BackEnd/Timeline/Services/JwtUserTokenBadFormatException.cs b/BackEnd/Timeline/Services/Token/JwtUserTokenBadFormatException.cs
index c528c3e3..4d7300a1 100644
--- a/BackEnd/Timeline/Services/JwtUserTokenBadFormatException.cs
+++ b/BackEnd/Timeline/Services/Token/JwtUserTokenBadFormatException.cs
@@ -2,7 +2,7 @@
using System.Globalization;
using static Timeline.Resources.Services.Exception;
-namespace Timeline.Services
+namespace Timeline.Services.Token
{
[Serializable]
public class JwtUserTokenBadFormatException : UserTokenBadFormatException
@@ -13,6 +13,7 @@ namespace Timeline.Services
IdClaimBadFormat,
NoVersionClaim,
VersionClaimBadFormat,
+ NoExp,
Other
}
diff --git a/BackEnd/Timeline/Services/Token/TokenServiceColletionExtensions.cs b/BackEnd/Timeline/Services/Token/TokenServiceColletionExtensions.cs
new file mode 100644
index 00000000..d3219ec4
--- /dev/null
+++ b/BackEnd/Timeline/Services/Token/TokenServiceColletionExtensions.cs
@@ -0,0 +1,18 @@
+using Microsoft.Extensions.Configuration;
+using Microsoft.Extensions.DependencyInjection;
+using Timeline.Configs;
+
+namespace Timeline.Services.Token
+{
+ public static class TokenServiceColletionExtensions
+ {
+ public static IServiceCollection AddTokenService(this IServiceCollection services, IConfiguration configuration)
+ {
+ services.Configure<TokenOptions>(configuration.GetSection("Token"));
+ services.Configure<JwtOptions>(configuration.GetSection("Jwt"));
+ services.AddScoped<IUserTokenHandler, JwtUserTokenHandler>();
+ services.AddScoped<IUserTokenManager, UserTokenManager>();
+ return services;
+ }
+ }
+}
diff --git a/BackEnd/Timeline/Services/UserTokenException.cs b/BackEnd/Timeline/Services/Token/UserTokenException.cs
index 398da41f..d666ba10 100644
--- a/BackEnd/Timeline/Services/UserTokenException.cs
+++ b/BackEnd/Timeline/Services/Token/UserTokenException.cs
@@ -1,6 +1,6 @@
using System;
-namespace Timeline.Services
+namespace Timeline.Services.Token
{
[Serializable]
diff --git a/BackEnd/Timeline/Services/UserTokenHandler.cs b/BackEnd/Timeline/Services/Token/UserTokenHandler.cs
index c24a8d47..2eaea57e 100644
--- a/BackEnd/Timeline/Services/UserTokenHandler.cs
+++ b/BackEnd/Timeline/Services/Token/UserTokenHandler.cs
@@ -8,13 +8,13 @@ using System.Security.Claims;
using Timeline.Configs;
using Timeline.Entities;
-namespace Timeline.Services
+namespace Timeline.Services.Token
{
public class UserTokenInfo
{
public long Id { get; set; }
public long Version { get; set; }
- public DateTime? ExpireAt { get; set; }
+ public DateTime ExpireAt { get; set; }
}
public interface IUserTokenHandler
@@ -28,7 +28,7 @@ namespace Timeline.Services
string GenerateToken(UserTokenInfo tokenInfo);
/// <summary>
- /// Verify a token and get the saved info.
+ /// Verify a token and get the saved info. Do not validate lifetime!!!
/// </summary>
/// <param name="token">The token to verify.</param>
/// <returns>The saved info in token.</returns>
@@ -44,13 +44,13 @@ namespace Timeline.Services
{
private const string VersionClaimType = "timeline_version";
- private readonly IOptionsMonitor<JwtConfiguration> _jwtConfig;
+ private readonly IOptionsMonitor<JwtOptions> _jwtConfig;
private readonly IClock _clock;
private readonly JwtSecurityTokenHandler _tokenHandler = new JwtSecurityTokenHandler();
private SymmetricSecurityKey _tokenSecurityKey;
- public JwtUserTokenHandler(IOptionsMonitor<JwtConfiguration> jwtConfig, IClock clock, DatabaseContext database)
+ public JwtUserTokenHandler(IOptionsMonitor<JwtOptions> jwtConfig, IClock clock, DatabaseContext database)
{
_jwtConfig = jwtConfig;
_clock = clock;
@@ -83,7 +83,7 @@ namespace Timeline.Services
Audience = config.Audience,
SigningCredentials = new SigningCredentials(_tokenSecurityKey, SecurityAlgorithms.HmacSha384),
IssuedAt = _clock.GetCurrentTime(),
- Expires = tokenInfo.ExpireAt.GetValueOrDefault(_clock.GetCurrentTime().AddSeconds(config.DefaultExpireOffset)),
+ Expires = tokenInfo.ExpireAt,
NotBefore = _clock.GetCurrentTime() // I must explicitly set this or it will use the current time by default and mock is not work in which case test will not pass.
};
@@ -127,17 +127,14 @@ namespace Timeline.Services
var decodedToken = (JwtSecurityToken)t;
var exp = decodedToken.Payload.Exp;
- DateTime? expireAt = null;
- if (exp.HasValue)
- {
- expireAt = EpochTime.DateTime(exp.Value);
- }
+ if (exp is null)
+ throw new JwtUserTokenBadFormatException(token, JwtUserTokenBadFormatException.ErrorKind.NoExp);
return new UserTokenInfo
{
Id = id,
Version = version,
- ExpireAt = expireAt
+ ExpireAt = EpochTime.DateTime(exp.Value)
};
}
catch (Exception e) when (e is SecurityTokenException || e is ArgumentException)
diff --git a/BackEnd/Timeline/Services/UserTokenManager.cs b/BackEnd/Timeline/Services/Token/UserTokenManager.cs
index 898e4d6d..00bc2cf7 100644
--- a/BackEnd/Timeline/Services/UserTokenManager.cs
+++ b/BackEnd/Timeline/Services/Token/UserTokenManager.cs
@@ -1,11 +1,13 @@
using Microsoft.Extensions.Logging;
+using Microsoft.Extensions.Options;
using System;
using System.Threading.Tasks;
+using Timeline.Configs;
using Timeline.Entities;
using Timeline.Helpers;
using Timeline.Services.Exceptions;
-namespace Timeline.Services
+namespace Timeline.Services.Token
{
public class UserTokenCreateResult
{
@@ -44,14 +46,16 @@ namespace Timeline.Services
public class UserTokenManager : IUserTokenManager
{
private readonly ILogger<UserTokenManager> _logger;
+ private readonly IOptionsMonitor<TokenOptions> _tokenOptionsMonitor;
private readonly IUserService _userService;
private readonly IUserCredentialService _userCredentialService;
private readonly IUserTokenHandler _userTokenService;
private readonly IClock _clock;
- public UserTokenManager(ILogger<UserTokenManager> logger, IUserService userService, IUserCredentialService userCredentialService, IUserTokenHandler userTokenService, IClock clock)
+ public UserTokenManager(ILogger<UserTokenManager> logger, IOptionsMonitor<TokenOptions> tokenOptionsMonitor, IUserService userService, IUserCredentialService userCredentialService, IUserTokenHandler userTokenService, IClock clock)
{
_logger = logger;
+ _tokenOptionsMonitor = tokenOptionsMonitor;
_userService = userService;
_userCredentialService = userCredentialService;
_userTokenService = userTokenService;
@@ -69,7 +73,13 @@ namespace Timeline.Services
var userId = await _userCredentialService.VerifyCredential(username, password);
var user = await _userService.GetUser(userId);
- var token = _userTokenService.GenerateToken(new UserTokenInfo { Id = user.Id, Version = user.Version, ExpireAt = expireAt });
+
+ var token = _userTokenService.GenerateToken(new UserTokenInfo
+ {
+ Id = user.Id,
+ Version = user.Version,
+ ExpireAt = expireAt ?? _clock.GetCurrentTime() + TimeSpan.FromSeconds(_tokenOptionsMonitor.CurrentValue.DefaultExpireSeconds)
+ });
return new UserTokenCreateResult { Token = token, User = user };
}
@@ -82,12 +92,9 @@ namespace Timeline.Services
var tokenInfo = _userTokenService.VerifyToken(token);
- if (tokenInfo.ExpireAt.HasValue)
- {
- var currentTime = _clock.GetCurrentTime();
- if (tokenInfo.ExpireAt < currentTime)
- throw new UserTokenTimeExpiredException(token, tokenInfo.ExpireAt.Value, currentTime);
- }
+ var currentTime = _clock.GetCurrentTime();
+ if (tokenInfo.ExpireAt < currentTime)
+ throw new UserTokenTimeExpiredException(token, tokenInfo.ExpireAt, currentTime);
try
{
diff --git a/BackEnd/Timeline/Startup.cs b/BackEnd/Timeline/Startup.cs
index c2134a94..d4fffb51 100644
--- a/BackEnd/Timeline/Startup.cs
+++ b/BackEnd/Timeline/Startup.cs
@@ -22,6 +22,7 @@ using Timeline.Models.Mapper;
using Timeline.Routes;
using Timeline.Services;
using Timeline.Services.DatabaseManagement;
+using Timeline.Services.Token;
using Timeline.Swagger;
namespace Timeline
@@ -78,7 +79,6 @@ namespace Timeline
options.InvalidModelStateResponseFactory = InvalidModelResponseFactory.Factory;
});
- services.Configure<JwtConfiguration>(Configuration.GetSection("Jwt"));
services.AddAuthentication(AuthenticationConstants.Scheme)
.AddScheme<MyAuthenticationOptions, MyAuthenticationHandler>(AuthenticationConstants.Scheme, AuthenticationConstants.DisplayName, o => { });
services.AddAuthorization();
@@ -111,11 +111,11 @@ namespace Timeline
services.AddScoped<IUserService, UserService>();
services.AddScoped<IUserCredentialService, UserCredentialService>();
services.AddScoped<IUserDeleteService, UserDeleteService>();
- services.AddScoped<IUserTokenHandler, JwtUserTokenHandler>();
- services.AddScoped<IUserTokenManager, UserTokenManager>();
services.AddScoped<IUserPermissionService, UserPermissionService>();
services.AddUserAvatarService();
+ services.AddTokenService(Configuration);
+
services.AddScoped<IBasicTimelineService, BasicTimelineService>();
services.AddScoped<ITimelineService, TimelineService>();
services.AddScoped<ITimelinePostService, TimelinePostService>();
diff --git a/BackEnd/Timeline/appsettings.json b/BackEnd/Timeline/appsettings.json
index 804ca43a..5098b4ae 100644
--- a/BackEnd/Timeline/appsettings.json
+++ b/BackEnd/Timeline/appsettings.json
@@ -5,7 +5,7 @@
}
},
"Jwt": {
- "Issuer": "api.crupest.xyz",
- "Audience": "api.crupest.xyz"
+ "Issuer": "timeline.crupest.life",
+ "Audience": "timeline.crupest.life"
}
}