延續之前兩個 AD 密碼相關的 API,接著寫了一個可以查詢 AD 使用者密碼即將到期的的 API,這篇就不再仔細寫出環境細節,包括 Models、appsettings.json、Program.cs 等,因為是延續之前的專案,如有需要可以參考前面的文章。
- 老森常譚 IT Help » 透過 ASP.NET Core 寫一個簡易的 AD 帳號密碼驗證 Web API
- 老森常譚 IT Help » 透過 ASP.NET Core 寫一個讓使用者可以修改自己 AD 密碼的 Web API
Services/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; } } } } |
Controllers/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
發佈留言