IdentityAppService.cs 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108
  1. using System.Security.Claims;
  2. using Hotline.Identity.Accounts;
  3. using Hotline.Settings;
  4. using Hotline.Share.Dtos.Identity;
  5. using Hotline.Share.Enums.Identity;
  6. using Hotline.Users;
  7. using IdentityModel;
  8. using Microsoft.AspNetCore.Identity;
  9. using Microsoft.Extensions.Options;
  10. using XF.Domain.Authentications;
  11. using XF.Domain.Dependency;
  12. using XF.Domain.Exceptions;
  13. using XF.Domain.Options;
  14. using XF.Domain.Repository;
  15. namespace Hotline.Application.Identity;
  16. public class IdentityAppService : IIdentityAppService, IScopeDependency
  17. {
  18. private readonly IAccountRepository _accountRepository;
  19. private readonly IAccountDomainService _accountDomainService;
  20. private readonly IRepository<User> _userRepository;
  21. private readonly IJwtSecurity _jwtSecurity;
  22. private readonly IOptionsSnapshot<IdentityConfiguration> _identityOptionsAccessor;
  23. public IdentityAppService(
  24. IAccountRepository accountRepository,
  25. IAccountDomainService accountDomainService,
  26. IRepository<User> userRepository,
  27. IJwtSecurity jwtSecurity,
  28. IOptionsSnapshot<IdentityConfiguration> identityOptionsAccessor)
  29. {
  30. _accountRepository = accountRepository;
  31. _accountDomainService = accountDomainService;
  32. _userRepository = userRepository;
  33. _jwtSecurity = jwtSecurity;
  34. _identityOptionsAccessor = identityOptionsAccessor;
  35. }
  36. public async Task<string> LoginAsync(LoginDto dto, CancellationToken cancellationToken)
  37. {
  38. var account = await _accountRepository.GetExtAsync(
  39. d => d.UserName == dto.Username,
  40. d => d.Includes(x => x.Roles));
  41. if (account == null)
  42. throw UserFriendlyException.SameMessage("用户名或密码错误!");
  43. if (account.Status != EAccountStatus.Normal)
  44. throw UserFriendlyException.SameMessage("用户名或密码错误!");
  45. if (account.LockoutEnabled && account.LockoutEnd >= DateTime.Now)
  46. throw UserFriendlyException.SameMessage("账号被锁定!");
  47. var verifyResult = _accountDomainService.VerifyPassword(account, dto.Password);
  48. if (verifyResult == PasswordVerificationResult.Failed)
  49. {
  50. var lockoutOptions = _identityOptionsAccessor.Value.Lockout;
  51. account.AccessFailedCount += 1;
  52. if (account.LockoutEnabled && account.AccessFailedCount >= lockoutOptions.MaxFailedAccessAttempts)
  53. account.LockoutEnd = DateTime.Now.Add(lockoutOptions.DefaultLockoutTimeSpan);
  54. await _accountRepository.UpdateAsync(account, cancellationToken);
  55. throw UserFriendlyException.SameMessage("账号名或密码错误!");
  56. }
  57. if (account.LockoutEnd.HasValue || account.AccessFailedCount > 0)
  58. {
  59. account.LockoutEnd = null;
  60. account.AccessFailedCount = 0;
  61. await _accountRepository.UpdateAsync(account, cancellationToken);
  62. }
  63. var user = await _userRepository.Queryable()
  64. .Includes(d => d.Organization)
  65. .FirstAsync(d => d.Id == account.Id);
  66. if (user == null)
  67. throw UserFriendlyException.SameMessage("未查询到用户数据");
  68. var jwtOptions = _identityOptionsAccessor.Value.Jwt;
  69. var claims = new List<Claim>
  70. {
  71. //new(JwtClaimTypes.Id, account.Id),
  72. new(JwtClaimTypes.Subject, account.Id),
  73. new(JwtClaimTypes.PhoneNumber, account.PhoneNo ?? string.Empty),
  74. new(AppClaimTypes.UserDisplayName, account.Name),
  75. new(JwtClaimTypes.Scope, jwtOptions.Scope),
  76. new(AppClaimTypes.UserPasswordChanged, account.PasswordChanged.ToString()),
  77. new(AppClaimTypes.StaffNo, user.StaffNo ?? string.Empty),
  78. };
  79. if (!string.IsNullOrEmpty(user.OrgId) && user.Organization is not null)
  80. {
  81. claims.AddRange(
  82. new List<Claim>
  83. {
  84. new(AppClaimTypes.DepartmentId, user.OrgId ?? string.Empty),
  85. new(AppClaimTypes.DepartmentIsCenter, user.Organization?.IsCenter.ToString()),
  86. new(AppClaimTypes.DepartmentName, user.Organization?.Name ?? string.Empty),
  87. new(AppClaimTypes.DepartmentAreaCode, user.Organization?.AreaCode ?? string.Empty),
  88. new(AppClaimTypes.DepartmentAreaName, user.Organization?.AreaName ?? string.Empty),
  89. new(AppClaimTypes.DepartmentLevel, user.Organization?.Level.ToString() ?? string.Empty),
  90. new(AppClaimTypes.AreaId, user.OrgId?.GetHigherOrgCode() ?? string.Empty),
  91. }
  92. );
  93. }
  94. claims.AddRange(account.Roles.Select(d => new Claim(JwtClaimTypes.Role, d.Name)));
  95. var token = _jwtSecurity.EncodeJwtToken(claims);
  96. return token;
  97. }
  98. }