aboutsummaryrefslogtreecommitdiff
path: root/Timeline
diff options
context:
space:
mode:
author杨宇千 <crupest@outlook.com>2019-08-01 22:32:40 +0800
committer杨宇千 <crupest@outlook.com>2019-08-01 22:32:40 +0800
commit9aeca6f6adf1a20d85e1fdbc8bdc8dfb35be28c1 (patch)
treeabbdb97d24c2e6d7c32433887643676637011720 /Timeline
parentee506e832e19e84cba2f9cf1c2b0172ca3e092b6 (diff)
downloadtimeline-9aeca6f6adf1a20d85e1fdbc8bdc8dfb35be28c1.tar.gz
timeline-9aeca6f6adf1a20d85e1fdbc8bdc8dfb35be28c1.tar.bz2
timeline-9aeca6f6adf1a20d85e1fdbc8bdc8dfb35be28c1.zip
Add token expire time.
Diffstat (limited to 'Timeline')
-rw-r--r--Timeline/Controllers/TokenController.cs24
-rw-r--r--Timeline/Entities/Http/Token.cs2
-rw-r--r--Timeline/Migrations/20190412144150_AddAdminUser.cs2
-rw-r--r--Timeline/Services/Clock.cs32
-rw-r--r--Timeline/Services/JwtService.cs8
-rw-r--r--Timeline/Services/UserService.cs7
-rw-r--r--Timeline/Startup.cs1
7 files changed, 65 insertions, 11 deletions
diff --git a/Timeline/Controllers/TokenController.cs b/Timeline/Controllers/TokenController.cs
index 66c97b59..f9dcfd76 100644
--- a/Timeline/Controllers/TokenController.cs
+++ b/Timeline/Controllers/TokenController.cs
@@ -1,6 +1,7 @@
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Logging;
+using System;
using System.Threading.Tasks;
using Timeline.Entities.Http;
using Timeline.Services;
@@ -23,6 +24,7 @@ namespace Timeline.Controllers
{
public const int Create_UserNotExist = -1001;
public const int Create_BadPassword = -1002;
+ public const int Create_BadExpireOffset = -1003;
public const int Verify_BadToken = -2001;
public const int Verify_UserNotExist = -2002;
@@ -32,28 +34,42 @@ namespace Timeline.Controllers
private readonly IUserService _userService;
private readonly ILogger<TokenController> _logger;
+ private readonly IClock _clock;
- public TokenController(IUserService userService, ILogger<TokenController> logger)
+ public TokenController(IUserService userService, ILogger<TokenController> logger, IClock clock)
{
_userService = userService;
_logger = logger;
+ _clock = clock;
}
[HttpPost("create")]
[AllowAnonymous]
public async Task<IActionResult> Create([FromBody] CreateTokenRequest request)
{
+ TimeSpan? expireOffset = null;
+ if (request.ExpireOffset != null)
+ {
+ if (request.ExpireOffset.Value <= 0.0)
+ {
+ var code = ErrorCodes.Create_BadExpireOffset;
+ _logger.LogInformation(LoggingEventIds.LogInFailed, "Attemp to login failed because expire time offset is bad. Code: {} Username: {} Password: {} Bad Expire Offset: {}.", code, request.Username, request.Password, request.ExpireOffset);
+ return BadRequest(new CommonResponse(code, "Expire time is not bigger than 0."));
+ }
+ expireOffset = TimeSpan.FromDays(request.ExpireOffset.Value);
+ }
+
try
{
- var result = await _userService.CreateToken(request.Username, request.Password);
- _logger.LogInformation(LoggingEventIds.LogInSucceeded, "Login succeeded. Username: {} .", request.Username);
+ var result = await _userService.CreateToken(request.Username, request.Password, expireOffset == null ? null : (DateTime?)(_clock.GetCurrentTime() + expireOffset.Value));
+ _logger.LogInformation(LoggingEventIds.LogInSucceeded, "Login succeeded. Username: {} Expire Time Offset: {} days.", request.Username, request.ExpireOffset);
return Ok(new CreateTokenResponse
{
Token = result.Token,
User = result.User
});
}
- catch(UserNotExistException e)
+ catch (UserNotExistException e)
{
var code = ErrorCodes.Create_UserNotExist;
_logger.LogInformation(LoggingEventIds.LogInFailed, e, "Attemp to login failed because user does not exist. Code: {} Username: {} Password: {} .", code, request.Username, request.Password);
diff --git a/Timeline/Entities/Http/Token.cs b/Timeline/Entities/Http/Token.cs
index aeb9fbf2..8a02ed2e 100644
--- a/Timeline/Entities/Http/Token.cs
+++ b/Timeline/Entities/Http/Token.cs
@@ -4,6 +4,8 @@
{
public string Username { get; set; }
public string Password { get; set; }
+ // in day
+ public double? ExpireOffset { get; set; }
}
public class CreateTokenResponse
diff --git a/Timeline/Migrations/20190412144150_AddAdminUser.cs b/Timeline/Migrations/20190412144150_AddAdminUser.cs
index 9fac05ff..1b3f14b7 100644
--- a/Timeline/Migrations/20190412144150_AddAdminUser.cs
+++ b/Timeline/Migrations/20190412144150_AddAdminUser.cs
@@ -8,7 +8,7 @@ namespace Timeline.Migrations
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.InsertData("user", new string[] { "name", "password", "roles" },
- new string[] { "crupest", new PasswordService(null).HashPassword("yang0101"), "user,admin" });
+ new string[] { "crupest", new PasswordService().HashPassword("yang0101"), "user,admin" });
}
protected override void Down(MigrationBuilder migrationBuilder)
diff --git a/Timeline/Services/Clock.cs b/Timeline/Services/Clock.cs
new file mode 100644
index 00000000..98451ad9
--- /dev/null
+++ b/Timeline/Services/Clock.cs
@@ -0,0 +1,32 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Threading.Tasks;
+
+namespace Timeline.Services
+{
+ /// <summary>
+ /// Convenient for unit test.
+ /// </summary>
+ public interface IClock
+ {
+ /// <summary>
+ /// Get current time.
+ /// </summary>
+ /// <returns>Current time.</returns>
+ DateTime GetCurrentTime();
+ }
+
+ public class Clock : IClock
+ {
+ public Clock()
+ {
+
+ }
+
+ public DateTime GetCurrentTime()
+ {
+ return DateTime.Now;
+ }
+ }
+}
diff --git a/Timeline/Services/JwtService.cs b/Timeline/Services/JwtService.cs
index f3416cce..52e892f6 100644
--- a/Timeline/Services/JwtService.cs
+++ b/Timeline/Services/JwtService.cs
@@ -94,10 +94,12 @@ namespace Timeline.Services
private readonly IOptionsMonitor<JwtConfig> _jwtConfig;
private readonly JwtSecurityTokenHandler _tokenHandler = new JwtSecurityTokenHandler();
+ private readonly IClock _clock;
- public JwtService(IOptionsMonitor<JwtConfig> jwtConfig)
+ public JwtService(IOptionsMonitor<JwtConfig> jwtConfig, IClock clock)
{
_jwtConfig = jwtConfig;
+ _clock = clock;
}
public string GenerateJwtToken(TokenInfo tokenInfo, DateTime? expires = null)
@@ -118,8 +120,8 @@ namespace Timeline.Services
Audience = config.Audience,
SigningCredentials = new SigningCredentials(
new SymmetricSecurityKey(Encoding.ASCII.GetBytes(config.SigningKey)), SecurityAlgorithms.HmacSha384),
- IssuedAt = DateTime.Now,
- Expires = expires.GetValueOrDefault(DateTime.Now.AddSeconds(config.DefaultExpireOffset))
+ IssuedAt = _clock.GetCurrentTime(),
+ Expires = expires.GetValueOrDefault(_clock.GetCurrentTime().AddSeconds(config.DefaultExpireOffset))
};
var token = _tokenHandler.CreateToken(tokenDescriptor);
diff --git a/Timeline/Services/UserService.cs b/Timeline/Services/UserService.cs
index 3164a645..328dbff0 100644
--- a/Timeline/Services/UserService.cs
+++ b/Timeline/Services/UserService.cs
@@ -58,11 +58,12 @@ namespace Timeline.Services
/// </summary>
/// <param name="username">The username of the user to anthenticate.</param>
/// <param name="password">The password of the user to anthenticate.</param>
+ /// <param name="expires">The expired time point. Null then use default. See <see cref="JwtService.GenerateJwtToken(TokenInfo, DateTime?)"/> for what is default.</param>
/// <returns>An <see cref="CreateTokenResult"/> containing the created token and user info.</returns>
/// <exception cref="ArgumentNullException">Thrown when <paramref name="username"/> or <paramref name="password"/> is null.</exception>
/// <exception cref="UserNotExistException">Thrown when the user with given username does not exist.</exception>
/// <exception cref="BadPasswordException">Thrown when password is wrong.</exception>
- Task<CreateTokenResult> CreateToken(string username, string password);
+ Task<CreateTokenResult> CreateToken(string username, string password, DateTime? expires = null);
/// <summary>
/// Verify the given token.
@@ -170,7 +171,7 @@ namespace Timeline.Services
_memoryCache.Remove(GenerateCacheKeyByUserId(id));
}
- public async Task<CreateTokenResult> CreateToken(string username, string password)
+ public async Task<CreateTokenResult> CreateToken(string username, string password, DateTime? expires)
{
if (username == null)
throw new ArgumentNullException(nameof(username));
@@ -198,7 +199,7 @@ namespace Timeline.Services
{
Id = user.Id,
Version = user.Version
- });
+ }, expires);
return new CreateTokenResult
{
Token = token,
diff --git a/Timeline/Startup.cs b/Timeline/Startup.cs
index a6965190..8f702da5 100644
--- a/Timeline/Startup.cs
+++ b/Timeline/Startup.cs
@@ -51,6 +51,7 @@ namespace Timeline
services.AddScoped<IUserService, UserService>();
services.AddScoped<IJwtService, JwtService>();
services.AddTransient<IPasswordService, PasswordService>();
+ services.AddTransient<IClock, Clock>();
var databaseConfig = Configuration.GetSection(nameof(DatabaseConfig)).Get<DatabaseConfig>();