Jelajahi Sumber

用户登录异常修复,

徐少年 1 tahun lalu
induk
melakukan
b97f7c6d3c

+ 35 - 0
Admin.NET/Admin.NET.Core/Entity/SysUserLdap.cs

@@ -30,6 +30,12 @@ public class SysUserLdap : EntityTenant
     [Required]
     public string Account { get; set; }
 
+    /// <summary>
+    /// 域用户名
+    /// </summary>
+    [SugarColumn(ColumnDescription = "域用户名", Length = 32)]
+    public string UserName { get; set; }
+
     /// <summary>
     /// 对应EmployeeId(用于数据导入对照)
     /// </summary>
@@ -41,4 +47,33 @@ public class SysUserLdap : EntityTenant
     /// </summary>
     [SugarColumn(ColumnDescription = "组织代码", Length = 64)]
     public string? DeptCode { get; set; }
+
+    /// <summary>
+    /// 最后设置密码时间
+    /// </summary>
+    [SugarColumn(ColumnDescription = "最后设置密码时间")]
+    public DateTime? PwdLastSetTime { get; set; }
+
+    /// <summary>
+    /// 邮箱
+    /// </summary>
+    [SugarColumn(ColumnDescription = "组织代码", Length = 64)]
+    public string? Mail { get; set; }
+
+    /// <summary>
+    /// 检查账户是否已过期
+    /// </summary>
+    [SugarColumn(ColumnDescription = "检查账户是否已过期")]
+    public bool AccountExpiresFlag { get; set; } = false;
+    /// <summary>
+    /// 密码设置是否永不过期
+    /// </summary>
+    [SugarColumn(ColumnDescription = "密码设置是否永不过期")]
+    public bool DontExpiresFlag { get; set; } = false;
+
+    /// <summary>
+    /// DN
+    /// </summary>
+    [SugarColumn(ColumnDescription = "DN", Length = 512)]
+    public string Dn { get; set; }
 }

+ 22 - 0
Admin.NET/Admin.NET.Core/Extension/ListExtensions.cs

@@ -23,4 +23,26 @@ public static class ListExtensions
             await action(value);
         }
     }
+
+    public static void ForEach<T>(this IEnumerable<T> enumerable, Action<T> consumer)
+    {
+        foreach (T item in enumerable)
+        {
+            consumer(item);
+        }
+    }
+
+    public static void AddRange<T>(this IList<T> list, IEnumerable<T> items)
+    {
+        if (list is List<T> list2)
+        {
+            list2.AddRange(items);
+            return;
+        }
+
+        foreach (T item in items)
+        {
+            list.Add(item);
+        }
+    }
 }

+ 25 - 17
Admin.NET/Admin.NET.Core/Service/Auth/SysAuthService.cs

@@ -106,19 +106,19 @@ public class SysAuthService : IDynamicApiController, ITransient
         // 是否开启域登录验证
         if (await _sysConfigService.GetConfigValue<bool>(ConfigConst.SysDomainLogin))
         {
-            var userLdap = await _sysUserLdap.GetFirstAsync(u => u.UserId == user.Id && u.TenantId == tenant.Id);
+            var userLdap = await _sysUserRep.ChangeRepository<SqlSugarRepository<SysUserLdap>>().GetFirstAsync(u => u.UserId == user.Id && u.TenantId == tenant.Id);
             if (userLdap == null)
             {
-                VerifyPassword(input, keyPasswordErrorTimes, passwordErrorTimes, user);
+                VerifyPassword(input.Password, keyPasswordErrorTimes, passwordErrorTimes, user);
             }
-            else if (!await _sysLdapService.AuthAccount(tenant.Id, userLdap.Account, input.Password))
+            else if (!await App.GetRequiredService<SysLdapService>().AuthAccount(tenant.Id, userLdap.Account, CryptogramUtil.Decrypt(input.Password)))
             {
                 _sysCacheService.Set(keyPasswordErrorTimes, ++passwordErrorTimes, TimeSpan.FromMinutes(30));
                 throw Oops.Oh(ErrorCodeEnum.D1000);
             }
         }
         else
-            VerifyPassword(input, keyPasswordErrorTimes, passwordErrorTimes, user);
+            VerifyPassword(input.Password, keyPasswordErrorTimes, passwordErrorTimes, user);
 
         // 登录成功则清空密码错误次数
         _sysCacheService.Remove(keyPasswordErrorTimes);
@@ -129,15 +129,15 @@ public class SysAuthService : IDynamicApiController, ITransient
     /// <summary>
     /// 验证用户密码
     /// </summary>
-    /// <param name="input"></param>
+    /// <param name="password"></param>
     /// <param name="keyPasswordErrorTimes"></param>
     /// <param name="passwordErrorTimes"></param>
     /// <param name="user"></param>
-    private void VerifyPassword(LoginInput input, string keyPasswordErrorTimes, int passwordErrorTimes, SysUser user)
+    private void VerifyPassword(string password, string keyPasswordErrorTimes, int passwordErrorTimes, SysUser user)
     {
         if (CryptogramUtil.CryptoType == CryptogramEnum.MD5.ToString())
         {
-            if (!user.Password.Equals(MD5Encryption.Encrypt(input.Password)))
+            if (!user.Password.Equals(MD5Encryption.Encrypt(password)))
             {
                 _sysCacheService.Set(keyPasswordErrorTimes, ++passwordErrorTimes, TimeSpan.FromMinutes(30));
                 throw Oops.Oh(ErrorCodeEnum.D1000);
@@ -145,7 +145,10 @@ public class SysAuthService : IDynamicApiController, ITransient
         }
         else
         {
-            if (!CryptogramUtil.Decrypt(user.Password).Equals(input.Password))
+            // 国密SM2解密(前端密码传输SM2加密后的)
+            password = CryptogramUtil.SM2Decrypt(password);
+
+            if (!CryptogramUtil.Decrypt(user.Password).Equals(password))
             {
                 _sysCacheService.Set(keyPasswordErrorTimes, ++passwordErrorTimes, TimeSpan.FromMinutes(30));
                 throw Oops.Oh(ErrorCodeEnum.D1000);
@@ -165,20 +168,25 @@ public class SysAuthService : IDynamicApiController, ITransient
         var user = await _sysUserRep.GetFirstAsync(u => u.Id == _userManager.UserId);
         _ = user ?? throw Oops.Oh(ErrorCodeEnum.D0009);
 
-        // 国密SM2解密(前端密码传输SM2加密后的)
-        password = CryptogramUtil.SM2Decrypt(password);
+        var keyPasswordErrorTimes = $"{CacheConst.KeyPasswordErrorTimes}{user.Account}";
+        var passwordErrorTimes = _sysCacheService.Get<int>(keyPasswordErrorTimes);
 
-        // 密码是否正确
-        if (CryptogramUtil.CryptoType == CryptogramEnum.MD5.ToString())
+        // 是否开启域登录验证
+        if (await _sysConfigService.GetConfigValue<bool>(ConfigConst.SysDomainLogin))
         {
-            if (!user.Password.Equals(MD5Encryption.Encrypt(password)))
+            var userLdap = await _sysUserRep.ChangeRepository<SqlSugarRepository<SysUserLdap>>().GetFirstAsync(u => u.UserId == user.Id && u.TenantId == user.TenantId);
+            if (userLdap == null)
+            {
+                VerifyPassword(password, keyPasswordErrorTimes, passwordErrorTimes, user);
+            }
+            else if (!await App.GetRequiredService<SysLdapService>().AuthAccount(user.TenantId.Value, userLdap.Account, CryptogramUtil.Decrypt(password)))
+            {
+                _sysCacheService.Set(keyPasswordErrorTimes, ++passwordErrorTimes, TimeSpan.FromMinutes(30));
                 throw Oops.Oh(ErrorCodeEnum.D1000);
+            }
         }
         else
-        {
-            if (!CryptogramUtil.Decrypt(user.Password).Equals(password))
-                throw Oops.Oh(ErrorCodeEnum.D1000);
-        }
+            VerifyPassword(password, keyPasswordErrorTimes, passwordErrorTimes, user);
 
         return true;
     }

+ 48 - 10
Admin.NET/Admin.NET.Core/Service/Auth/SysLdapService.cs

@@ -119,13 +119,14 @@ public class SysLdapService : IDynamicApiController, ITransient
         try
         {
             ldapConn.Connect(sysLdap.Host, sysLdap.Port);
-            ldapConn.Bind(sysLdap.Version, sysLdap.BindDn, sysLdap.BindPass);
-            var ldapSearchResults = ldapConn.Search(sysLdap.BaseDn, LdapConnection.ScopeSub, sysLdap.AuthFilter.Replace("$s", account), null, false);
+            string bindPass = CryptogramUtil.Decrypt(sysLdap.BindPass);
+            ldapConn.Bind(sysLdap.Version, sysLdap.BindDn, bindPass);
+            var ldapSearchResults = ldapConn.Search(sysLdap.BaseDn, LdapConnection.ScopeSub, sysLdap.AuthFilter.Replace("%s", account), null, false);
             string dn = string.Empty;
             while (ldapSearchResults.HasMore())
             {
                 var ldapEntry = ldapSearchResults.Next();
-                var sAMAccountName = ldapEntry.GetAttribute(sysLdap.AuthFilter)?.StringValue;
+                var sAMAccountName = ldapEntry.GetAttribute(sysLdap.BindAttrAccount)?.StringValue;
                 if (!string.IsNullOrEmpty(sAMAccountName))
                 {
                     dn = ldapEntry.Dn;
@@ -154,15 +155,39 @@ public class SysLdapService : IDynamicApiController, ITransient
         return true;
     }
 
+    /// <summary>
+    /// 同步域用户 🔖
+    /// </summary>
+    /// <param name="tenantId"></param>
+    /// <returns></returns>
+    [DisplayName("同步域用户")]
+    [NonAction]
+    public async Task<List<SysUserLdap>> SyncUserTenant(long tenantId)
+    {
+        var sysLdap = await _sysLdapRep.GetFirstAsync(c => c.TenantId == tenantId && c.IsDelete == false && c.Status == StatusEnum.Enable) ?? throw Oops.Oh(ErrorCodeEnum.D1002);
+        return await SyncUser(sysLdap);
+    }
+
     /// <summary>
     /// 同步域用户 🔖
     /// </summary>
     /// <param name="input"></param>
     /// <returns></returns>
     [DisplayName("同步域用户")]
-    public async Task SyncUser(SyncSysLdapInput input)
+    public async Task<List<SysUserLdap>> SyncUser(SyncSysLdapInput input)
     {
-        var sysLdap = await _sysLdapRep.GetFirstAsync(u => u.Id == input.Id) ?? throw Oops.Oh(ErrorCodeEnum.D1002);
+        var sysLdap = await _sysLdapRep.GetByIdAsync(input.Id) ?? throw Oops.Oh(ErrorCodeEnum.D1002);
+        return await SyncUser(sysLdap);
+    }
+
+    /// <summary>
+    /// 同步域用户 🔖
+    /// </summary>
+    /// <param name="sysLdap"></param>
+    /// <returns></returns>
+    private async Task<List<SysUserLdap>> SyncUser(SysLdap sysLdap)
+    {
+        if (sysLdap == null) throw Oops.Oh(ErrorCodeEnum.D1002);
         var ldapConn = new LdapConnection();
         try
         {
@@ -192,15 +217,16 @@ public class SysLdapService : IDynamicApiController, ITransient
                 else
                 {
                     var sysUserLdap = CreateSysUserLdap(attrs, sysLdap.BindAttrAccount, sysLdap.BindAttrEmployeeId, deptCode);
-                    if (string.IsNullOrEmpty(sysUserLdap.EmployeeId)) continue;
+                    sysUserLdap.Dn = ldapEntry.Dn;
                     userLdapList.Add(sysUserLdap);
                 }
             }
 
             if (userLdapList.Count == 0)
-                return;
+                return null;
 
             await App.GetRequiredService<SysUserLdapService>().InsertUserLdaps(sysLdap.TenantId!.Value, userLdapList);
+            return userLdapList;
         }
         catch (LdapException e)
         {
@@ -239,12 +265,23 @@ public class SysLdapService : IDynamicApiController, ITransient
     /// <returns></returns>
     private static SysUserLdap CreateSysUserLdap(LdapAttributeSet attrs, string bindAttrAccount, string bindAttrEmployeeId, string deptCode)
     {
-        return new SysUserLdap
+        var userLdap = new SysUserLdap
         {
             Account = !attrs.ContainsKey(bindAttrAccount) ? null : attrs.GetAttribute(bindAttrAccount)?.StringValue,
             EmployeeId = !attrs.ContainsKey(bindAttrEmployeeId) ? null : attrs.GetAttribute(bindAttrEmployeeId)?.StringValue,
             DeptCode = deptCode
         };
+        userLdap.UserName = !attrs.ContainsKey("name") ? null : attrs.GetAttribute("name")?.StringValue;
+        userLdap.Mail = !attrs.ContainsKey("mail") ? null : attrs.GetAttribute("mail")?.StringValue;
+        var pwdLastSet = !attrs.ContainsKey("pwdLastSet") ? null : attrs.GetAttribute("pwdLastSet")?.StringValue;
+        if (!pwdLastSet.Equals("0"))
+            userLdap.PwdLastSetTime = DateTime.FromFileTime(Convert.ToInt64(pwdLastSet));
+        var userAccountControl = !attrs.ContainsKey("userAccountControl") ? null : attrs.GetAttribute("userAccountControl")?.StringValue;
+        if ((Convert.ToInt32(userAccountControl) & 0x2) == 0x2) // 检查账户是否已过期(通过检查userAccountControl属性的特定位)  
+            userLdap.AccountExpiresFlag = true;
+        if ((Convert.ToInt32(userAccountControl) & 0x10000) == 0x10000) // 检查账户密码设置是否永不过期
+            userLdap.DontExpiresFlag = true;
+        return userLdap;
     }
 
     /// <summary>
@@ -279,7 +316,7 @@ public class SysLdapService : IDynamicApiController, ITransient
             else
             {
                 var sysUserLdap = CreateSysUserLdap(attrs, sysLdap.BindAttrAccount, sysLdap.BindAttrEmployeeId, deptCode);
-
+                sysUserLdap.Dn = ldapEntry.Dn;
                 if (string.IsNullOrEmpty(sysUserLdap.EmployeeId)) continue;
                 userLdapList.Add(sysUserLdap);
             }
@@ -299,7 +336,8 @@ public class SysLdapService : IDynamicApiController, ITransient
         try
         {
             ldapConn.Connect(sysLdap.Host, sysLdap.Port);
-            ldapConn.Bind(sysLdap.Version, sysLdap.BindDn, sysLdap.BindPass);
+            string bindPass = CryptogramUtil.Decrypt(sysLdap.BindPass);
+            ldapConn.Bind(sysLdap.Version, sysLdap.BindDn, bindPass);
             var ldapSearchResults = ldapConn.Search(sysLdap.BaseDn, LdapConnection.ScopeOne, "(objectClass=*)", null, false);
             var orgList = new List<SysOrg>();
             while (ldapSearchResults.HasMore())

+ 16 - 5
Admin.NET/Admin.NET.Core/Service/Config/SysConfigService.cs

@@ -83,7 +83,7 @@ public class SysConfigService : IDynamicApiController, ITransient
         var config = input.Adapt<SysConfig>();
         await _sysConfigRep.AsUpdateable(config).IgnoreColumns(true).ExecuteCommandAsync();
 
-        _sysCacheService.Remove($"{CacheConst.KeyConfig}{config.Code}");
+        Remove(config);
     }
 
     /// <summary>
@@ -101,7 +101,7 @@ public class SysConfigService : IDynamicApiController, ITransient
 
         await _sysConfigRep.DeleteAsync(config);
 
-        _sysCacheService.Remove($"{CacheConst.KeyConfig}{config.Code}");
+        Remove(config);
     }
 
     /// <summary>
@@ -121,7 +121,7 @@ public class SysConfigService : IDynamicApiController, ITransient
 
             await _sysConfigRep.DeleteAsync(config);
 
-            _sysCacheService.Remove($"{CacheConst.KeyConfig}{config.Code}");
+            Remove(config);
         }
     }
 
@@ -172,7 +172,7 @@ public class SysConfigService : IDynamicApiController, ITransient
         config.Value = value;
         await _sysConfigRep.AsUpdateable(config).ExecuteCommandAsync();
 
-        _sysCacheService.Remove($"{CacheConst.KeyConfig}{config.Code}");
+        Remove(config);
     }
 
     /// <summary>
@@ -223,8 +223,11 @@ public class SysConfigService : IDynamicApiController, ITransient
     {
         foreach (var Config in input)
         {
+            var info = await _sysConfigRep.GetFirstAsync(c => c.Code == Config.Code);
+            if (info == null)
+                continue;
             await _sysConfigRep.AsUpdateable().SetColumns(u => u.Value == Config.Value).Where(u => u.Code == Config.Code).ExecuteCommandAsync();
-            _sysCacheService.Remove($"{CacheConst.KeyConfig}{Config.Code}");
+            Remove(info);
         }
     }
 
@@ -315,4 +318,12 @@ public class SysConfigService : IDynamicApiController, ITransient
         await UpdateConfigValue(ConfigConst.SysSecondVer, (input.SysSecondVer ?? false).ToString());
         await UpdateConfigValue(ConfigConst.SysCaptcha, (input.SysCaptcha ?? true).ToString());
     }
+
+    private void Remove(SysConfig config)
+    {
+        _sysCacheService.Remove($"{CacheConst.KeyConfig}Value:{config.Code}");
+        _sysCacheService.Remove($"{CacheConst.KeyConfig}Remark:{config.Code}");
+        _sysCacheService.Remove($"{CacheConst.KeyConfig}{config.GroupCode}:GroupWithCache");
+        _sysCacheService.Remove($"{CacheConst.KeyConfig}{config.GroupCode}:{config.Value}");
+    }
 }

+ 2 - 1
Admin.NET/Admin.NET.Core/Service/User/SysUserLdapService.cs

@@ -31,8 +31,9 @@ public class SysUserLdapService : ITransient
         await _sysUserLdapRep.InsertRangeAsync(sysUserLdaps);
 
         await _sysUserLdapRep.AsUpdateable()
-            .InnerJoin<SysUser>((l, u) => l.EmployeeId == u.Account && u.Status == StatusEnum.Enable && u.IsDelete == false && l.IsDelete == false)
+            .InnerJoin<SysUser>((l, u) => l.EmployeeId == u.Account)
             .SetColumns((l, u) => new SysUserLdap { UserId = u.Id })
+            .Where((l, u) => l.TenantId == tenantId && u.Status == StatusEnum.Enable && u.IsDelete == false && l.IsDelete == false)
             .ExecuteCommandAsync();
     }