diff options
author | 杨宇千 <crupest@outlook.com> | 2019-08-01 22:32:40 +0800 |
---|---|---|
committer | 杨宇千 <crupest@outlook.com> | 2019-08-01 22:32:40 +0800 |
commit | 9aeca6f6adf1a20d85e1fdbc8bdc8dfb35be28c1 (patch) | |
tree | abbdb97d24c2e6d7c32433887643676637011720 /Timeline | |
parent | ee506e832e19e84cba2f9cf1c2b0172ca3e092b6 (diff) | |
download | timeline-9aeca6f6adf1a20d85e1fdbc8bdc8dfb35be28c1.tar.gz timeline-9aeca6f6adf1a20d85e1fdbc8bdc8dfb35be28c1.tar.bz2 timeline-9aeca6f6adf1a20d85e1fdbc8bdc8dfb35be28c1.zip |
Add token expire time.
Diffstat (limited to 'Timeline')
-rw-r--r-- | Timeline/Controllers/TokenController.cs | 24 | ||||
-rw-r--r-- | Timeline/Entities/Http/Token.cs | 2 | ||||
-rw-r--r-- | Timeline/Migrations/20190412144150_AddAdminUser.cs | 2 | ||||
-rw-r--r-- | Timeline/Services/Clock.cs | 32 | ||||
-rw-r--r-- | Timeline/Services/JwtService.cs | 8 | ||||
-rw-r--r-- | Timeline/Services/UserService.cs | 7 | ||||
-rw-r--r-- | Timeline/Startup.cs | 1 |
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>(); |