延续之前两个AD密码相关的API,接着写了一个可以查询 AD 用户密码即将到期的的 API,这篇就不再仔细写出环境细节,包括 Models、应用程序设置.json、Program.cs等,因为是延续之前的项目,如有需要可以参考前面的文章。
- 老森常谭 IT Help » 透过 ASP.NET Core 写一个简易的 AD 帐号密码验证 Web API
- 老森常谭 IT Help » 透过 ASP.NET Core 写一个让使用者可以修改自己 AD 密码的 Web API
服务/PasswordManagementService.cs
using AD.Models; using Microsoft.Extensions.Options; using System.DirectoryServices; using System.DirectoryServices.Protocols; using System.Net; using System.Text; using System.DirectoryServices.AccountManagement; using System.Runtime.Versioning; namespace AD.Services { public class PasswordManagementService(IOptions<LdapSettings> ldapSettings) { private readonly string _ldapServer = ldapSettings.Value.Server; private readonly string _domain = ldapSettings.Value.Domain; private readonly string _baseDn = ldapSettings.Value.BaseDn; // 查詢網域密碼政策 [SupportedOSPlatform("windows")] // 宣告以下方法僅適用於 Windows,避免 DirectorySearcher 等 class 被提示要留意跨平臺問題。 public TimeSpan GetMaxPasswordAge() { try { // 使用 DirectorySearcher 查詢網域《群組原則》的「密碼最長使用期限」。 using DirectorySearcher searcher = new(new DirectoryEntry($"LDAP://{_baseDn}")) { Filter = "(objectClass=domain)" }; searcher.PropertiesToLoad.Add("maxPwdAge"); // 密碼最長使用期限 SearchResult? result = searcher.FindOne(); if (result != null && result.Properties.Contains("maxPwdAge")) { long maxPwdAgeTicks = (long)result.Properties["maxPwdAge"][0]; // 「密碼最長使用期限」原始數值, return TimeSpan.FromTicks(maxPwdAgeTicks); // 轉成 TimeSpan 物件。(TimeSpan 物件在時間處理較為方便) } return TimeSpan.Zero; // 找不到資料時,回傳 0 } catch (Exception ex) { Console.WriteLine($"查詢網域密碼政策時,發生錯誤: {ex.Message}"); return TimeSpan.Zero; } } // 查詢密碼即將到期的使用者 [SupportedOSPlatform("windows")] // 宣告以下方法僅適用於 Windows,避免 GetMaxPasswordAge() 等方法被提示要留意跨平臺問題。 public List<String> GetUsersWithExpiringPasswords(int daysUntilExpiry) { List<String> expiringUsers = []; // 「密碼即將到期的使用者」清單。 try { TimeSpan MaxPasswordAge = GetMaxPasswordAge(); // 取得「密碼最長使用期限」。 if (MaxPasswordAge == TimeSpan.Zero) // 未設定「密碼最長使用期限」。 return expiringUsers; DateTime today = DateTime.Now; DateTime thresholdDate = today.AddDays(daysUntilExpiry); // XX 天 (daysUntilExpiry) 後的「到期日期」。 // 使用 DirectorySearcher 查詢網域《群組原則》的「密碼最長使用期限」。 using DirectorySearcher searcher = new(new DirectoryEntry($"LDAP://{_baseDn}")) { Filter = "(&(objectCategory=person)(objectClass=user)(pwdLastSet=*)(mail=*))" // 篩選有「上次密碼設定時間」、「Mail」的「使用者」。 }; searcher.PropertiesToLoad.Add("sAMAccountName"); // AD 帳號 searcher.PropertiesToLoad.Add("pwdLastSet"); // 上次密碼設定時間 searcher.PropertiesToLoad.Add("displayName"); // 顯示名稱 searcher.PropertiesToLoad.Add("mail"); // 電子郵件 foreach (SearchResult result in searcher.FindAll()) { long pwdLastSetTicks = (long)result.Properties["pwdLastSet"][0]; // 使用者帳戶的「上次密碼設定時間」。 DateTime pwdLastSet = DateTime.FromFileTime(pwdLastSetTicks); // 轉成 DateTime 格式。(具體的日期) DateTime passwordExpiryDate = pwdLastSet + MaxPasswordAge; // 使用者帳戶的「密碼到期日」。 if (passwordExpiryDate <= thresholdDate) // 已經到期或未來 XX 天內會到期的帳戶 { string userSAMAccountName = result.Properties["sAMAccountName"][0].ToString() ?? string.Empty; // AD 帳號 string userPasswordExpiryDate = passwordExpiryDate.ToString("yyyy/MM/dd") ?? string.Empty; // 上次密碼設定時間 string userDisplayName = result.Properties["displayName"][0].ToString() ?? string.Empty; // 顯示名稱 string userMail = result.Properties["mail"][0].ToString() ?? string.Empty; // 電子郵件 string expiringUsersInfo = $"{userSAMAccountName};{userPasswordExpiryDate};{userDisplayName};{userMail}"; expiringUsers.Add(expiringUsersInfo); } } return expiringUsers; // 若沒結果,回傳空的清單。 } catch (Exception ex) { Console.WriteLine($"查詢密碼即將到期的使用者時,發生錯誤: {ex.Message}"); return expiringUsers; } } } }
控制器/PasswordManagementController.cs
using AD.Models; using AD.Services; using Microsoft.AspNetCore.Mvc; using System.Runtime.Versioning; namespace AD.Controllers { [Route("password")] [ApiController] public class PasswordManagementController(PasswordManagementService passwordManagement) : ControllerBase { // 取得密碼即將到期的使用者 [HttpGet("get-expiry-users/{days}")] [SupportedOSPlatform("windows")] // 宣告以下用到的方法僅適用於 Windows,避免 GetUsersWithExpiringPasswords 方法被提示要留意跨平臺問題。 public IActionResult GetExpiringUsers(int days) { try { var users = passwordManagement.GetUsersWithExpiringPasswords(days); return Ok(new { expiringUsers = users }); // 回傳一個包含 ExpiringUsers 屬性,其值為 users 的 JSON 格式。 } catch (Exception ex) { return StatusCode(500, new { Message = "發生錯誤", Error = ex.Message }); } } } }
《Swagger 测试结果》
《相关连结》
- 老森常谭 IT Help » 透过 ASP.NET Core 写一个简易的 AD 帐号密码验证 Web API
- 老森常谭 IT Help » 透过 ASP.NET Core 写一个让使用者可以修改自己 AD 密码的 Web API