using Application.Domain.Entities; using Application.Models; using Infrastructure.Data; using Infrastructure.Extensions; using Infrastructure.Security; using Microsoft.AspNetCore.Mvc; using Microsoft.Extensions.Configuration; using System; using System.Linq; using System.Net.Mime; using System.Security.Claims; namespace UserCenter.Controllers { [ApiVersion("1.0")] [Route("api/[controller]/[action]")] [Route("api/v{version:apiVersion}/[controller]/[action]")] [ApiController] [Produces(MediaTypeNames.Application.Json)] public class TokenController : ControllerBase { private readonly IConfiguration _cfg; private readonly IRepository _userRepo; private readonly IEncryptionService _encryptionService; public TokenController(IConfiguration cfg, IRepository userRepo, IEncryptionService encryptionService) { this._cfg = cfg; this._userRepo = userRepo; this._encryptionService = encryptionService; } [HttpPost] public ActionResult GetToken([FromBody]LoginModel model) { var success = false; try { var user = this._userRepo.Table().FirstOrDefault(o => o.UserName == model.UserName); if (user == null) { ModelState.AddModelError("", "用户名或密码错误"); } else { var maxAccessFailedCount = this._cfg.GetValue("MaxFailedAccessAttemptsBeforeLockout"); var lockoutEndMinutes = this._cfg.GetValue("DefaultAccountLockoutMinutes"); if (user.LockoutEnabled)//对已启用登录锁定的用户,如果当前登录时间超出锁定时间,先解除锁定状态 { if (user.LockoutEnd.HasValue && DateTime.UtcNow > user.LockoutEnd) { user.LockoutEnd = null; user.AccessFailedCount = 0; this._userRepo.SaveChanges(); } } if (user.LockoutEnabled)//对启用登录锁定的用户进行验证 { if (user.LockoutEnd.HasValue == false) { if (user.PasswordHash == this._encryptionService.CreatePasswordHash(model.Password, user.SecurityStamp)) { user.LockoutEnd = null; user.AccessFailedCount = 0; success = true; } else { user.AccessFailedCount += 1; if (user.AccessFailedCount >= maxAccessFailedCount) { user.LockoutEnd = DateTime.UtcNow.AddMinutes(lockoutEndMinutes); ModelState.AddModelError(nameof(model.UserName), $"用户被锁定,请于{user.LockoutEnd.Value.ToLocalTime().ToString("HH:mm")}后重试"); } else { ModelState.AddModelError(nameof(model.UserName), $"密码错误,再错误{maxAccessFailedCount - user.AccessFailedCount}次后将锁定用户{lockoutEndMinutes}分钟"); } } this._userRepo.SaveChanges(); } } else//对未启用登录锁定的用户进行验证 { if (user.PasswordHash == this._encryptionService.CreatePasswordHash(model.Password, user.SecurityStamp)) { success = true; } else { ModelState.AddModelError("", "用户名或密码错误"); } } } if (success) { return Ok(new { AccessToken = Request.HttpContext.GetToken(model.UserName, _cfg, DateTime.Now.AddHours(_cfg.GetValue("AccessTokenHours", 0.5))), RefreshToken = Request.HttpContext.GetToken(model.UserName, _cfg, DateTime.Now.AddHours(_cfg.GetValue("AccessTokenHours", 720))), }); } else { return Unauthorized(ModelState); } } catch (Exception ex) { ex.PrintStack(); return Problem(ex.Message); } } [HttpPost] public ActionResult RefreshToken([FromBody]string refreshToken) { try { var token = Request.HttpContext.ReadToken(refreshToken); if (DateTime.UtcNow > token.ValidTo) { ModelState.AddModelError("", "已过期"); return Unauthorized(ModelState); } var userName = token.Claims.FirstOrDefault(o => o.Type == ClaimTypes.Name).Value; return Ok(new { AccessToken = Request.HttpContext.GetToken(userName, _cfg, DateTime.Now.AddHours(_cfg.GetValue("AccessTokenHours", 0.5))), RefreshToken = Request.HttpContext.GetToken(userName, _cfg, DateTime.Now.AddHours(_cfg.GetValue("AccessTokenHours", 720))), }); } catch (Exception ex) { ex.PrintStack(); return Problem(ex.Message); } } } }