using Application.Domain.Entities; using Application.Models; using Infrastructure.Application.Services.Settings; using Infrastructure.Data; using Infrastructure.Extensions; using Infrastructure.Security; using Microsoft.AspNetCore.Mvc; using Microsoft.Extensions.Configuration; using System; using System.ComponentModel.DataAnnotations; using System.Linq; using System.Security.Claims; namespace UserCenter.Controllers { [ApiVersion("1.0")] [Route("api/v{version:apiVersion}/[controller]/[action]")] [ApiController] public class TokenController : ControllerBase { private readonly ISettingService _settingService; private readonly IConfiguration _cfg; private readonly IRepository _userRepo; private readonly IEncryptionService _encryptionService; public TokenController(IConfiguration cfg, ISettingService settingService, IRepository userRepo, IEncryptionService encryptionService) { this._settingService = settingService; this._cfg = cfg; this._userRepo = userRepo; this._encryptionService = encryptionService; } [HttpPost] public ActionResult GetToken([FromBody]LoginModel model) { try { var user = this._userRepo.Table().FirstOrDefault(o => o.UserName == model.UserName); if (user == null) { return BadRequest(ModelState.AddModelError("用户名或密码错误")); } else { var maxAccessFailedCount = Convert.ToInt32(this._settingService.GetSetting("MaxFailedAccessAttemptsBeforeLockout").Value); var lockoutEndMinutes = Convert.ToInt32(this._settingService.GetSetting("DefaultAccountLockoutMinutes").Value); 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; } else { user.AccessFailedCount += 1; if (user.AccessFailedCount >= maxAccessFailedCount) { user.LockoutEnd = DateTime.UtcNow.AddMinutes(lockoutEndMinutes); return BadRequest(ModelState.AddModelError(o => model.UserName, $"用户被锁定,请于{user.LockoutEnd.Value.ToLocalTime():HH:mm}后重试", 1)); } else { return BadRequest(ModelState.AddModelError(o => model.UserName, $"密码错误,再错误{maxAccessFailedCount - user.AccessFailedCount}次后将锁定用户{lockoutEndMinutes}分钟", 2)); } } this._userRepo.SaveChanges(); } } else//对未启用登录锁定的用户进行验证 { if (user.PasswordHash != this._encryptionService.CreatePasswordHash(model.Password, user.SecurityStamp)) { return BadRequest(ModelState.AddModelError("用户名或密码错误")); } } } return Ok(this.CreateToken(user.UserName)); } catch (Exception ex) { ex.PrintStack(); return Problem(ex.Message); } } private object CreateToken(String userName) { return new { AccessToken = Request.HttpContext.GetToken(userName, _cfg, DateTime.Now.AddMinutes(Convert.ToDouble(_settingService.GetSetting("AccessTokenTimeout").Value))), RefreshToken = Request.HttpContext.GetToken(userName, _cfg, DateTime.Now.AddMinutes(Convert.ToDouble(_settingService.GetSetting("RefreshTokenTimeout").Value))), }; } [HttpPost] public ActionResult RefreshToken([FromBody][Required(ErrorMessage = nameof(RequiredAttribute))]string refreshToken) { try { var token = Request.HttpContext.ReadToken(refreshToken); if (DateTime.UtcNow > token.ValidTo) { return Unauthorized(ModelState.AddModelError("已过期")); } 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("AccessTokenTimeout", 0.5))), RefreshToken = Request.HttpContext.GetToken(userName, _cfg, DateTime.Now.AddHours(_cfg.GetValue("RefreshTokenTimeout", 720))), }); } catch (Exception ex) { ex.PrintStack(); return Problem(ex.Message); } } } }