Hi,大家好!
今天我們來講一下如何獲取Windows賬號,實現單點登錄。
在構建企業級 Access 應用程序(C/S 架構)時,開發者往往面臨一個兩難選擇:是自己設計一套“用户表+密碼字段”的登錄系統,還是直接利用現有的企業基礎設施?
答案顯而易見。在域環境(Active Directory)下,利用 SSO(單點登錄) 是標準且最佳的實踐。
01什麼是SSO
SSO (Single Sign-On),即單點登錄。它的核心定義是:在多個應用系統中,用户只需要登錄一次,就可以訪問所有相互信任的應用系統。
在我們的 Access 開發場景中,指 Windows 集成認證 (Integrated Windows Authentication, IWA)。
舉個栗子簡單的理解一下:
- 傳統模式:你去公司大樓(Windows),保安查了一次證件。進辦公室(Access系統)時,前台又要你背一遍身份證號和密碼。
-
SSO 模式:你刷卡進了公司大樓(Windows 登錄成功),你的工牌(Token)就是你的通行證。當你走進辦公室(打開 Access)時,系統只看你的工牌,確認是“自己人”,直接放行。
02為什麼要用SSO
很多開發者覺得:“我自己寫個密碼判斷 If txtPassword = "123456" 很簡單啊,為什麼要搞這麼複雜?”這是一個典型的誤區。
引入 SSO 不僅僅是為了“少輸一次密碼”,是為了解決企業開發中的幾個問題: - 安全性Access 並不是一個專業的安全工具。存儲風險:如果你在 Access 表中存儲密碼(即使是 MD5 加密),一旦 .accdb 文件被拷貝,有無數種工具可以暴力破解。
- 運維成本:終結“忘記密碼”的工單IT 部門的就不會再有軟件系統“重置密碼“的工單。只要用户能登錄 Windows,他就能登錄 Access。你不需要維護一套獨立的密碼庫,也不需要處理密碼找回請求。
-
權限生命週期管理當員工離職時,IT 部門會禁用其 Windows 域賬號。如果 Access 有獨立的賬户體系,管理員忘記在 Access 裏禁用該員工,SSO 的優勢:域賬號一封禁,所有依賴 SSO 的系統(包括你的 Access)瞬間全部拒絕訪問。
03核心代碼
新建標準模塊 mod_Auth,代碼如下:
Option Compare Database
Option Explicit
' ---------------------------------------------------------
' API 聲明:兼容 VBA7 (x64) 及舊版本 (x86)
' ---------------------------------------------------------
#If VBA7 Then
Private Declare PtrSafe Function GetUserName Lib "advapi32.dll" Alias "GetUserNameA" _
(ByVal lpBuffer As String, nSize As Long) As Long
#Else
Private Declare Function GetUserName Lib "advapi32.dll" Alias "GetUserNameA" _
(ByVal lpBuffer As String, nSize As Long) As Long
#End If
' ---------------------------------------------------------
' 函數:GetSystemUser
' 描述:通過 API 獲取當前 Windows 登錄賬户名
' 原理:讀取當前線程的安全令牌,而非環境變量
' ---------------------------------------------------------
Public Function GetSystemUser() As String
Dim strBuffer As String
Dim lngSize As Long
Dim lngResult As Long
' 初始化緩衝區:API 需要預先分配內存空間
' 255 字符通常足以容納 Windows 用户名
strBuffer = String(255, vbNullChar)
lngSize = Len(strBuffer)
' 調用 API
' lpBuffer: 接收用户名的緩衝區
' nSize: 傳入緩衝區長度,返回實際用户名長度
lngResult = GetUserName(strBuffer, lngSize)
If lngResult <> 0 Then
' API 返回成功 (非0)
' 注意:lngSize 返回的是包含 Null 結尾的長度,需要 -1
GetSystemUser = Left$(strBuffer, lngSize - 1)
Else
' API 調用失敗 (通常極少發生,除非系統底層異常)
GetSystemUser = "Unknown"
' 實際生產中建議在此處記錄 Err.LastDllError
End If
End Function
04架構設計
獲取用户名只是第一步,完整的權限控制需要數據庫層面的配合。建議採用 RBAC (基於角色的訪問控制) 模型。這裏我們簡單的來描述一下。
- 數據庫 Schema 設計在後端數據庫(或本地表)創建 sys_Users 表:User_ID (PK, AutoNumber)Win_Account (String, Indexed, Unique) - 存儲 Windows 登錄名Role_Code (String) - 例如: 'ADMIN', 'VIEWER'Is_Active (Boolean) - 軟刪除標記
-
啓動掛載邏輯利用 Access 的啓動窗體(Splash Screen)作為控制器。在啓動窗體 frm_Splash 的 Form_Load 事件中:
Private Sub Form_Load() On Error GoTo ErrorHandler Dim strCurrentUser As String Dim strRole As String ' 1. 獲取系統標識 (SSO 核心步驟) strCurrentUser = GetSystemUser() ' 2. 數據庫鑑權 (Authorization) ' 認證(Authentication)由 Windows 完成,Access 只負責授權(Authorization) strRole = Nz(DLookup("Role_Code", "sys_Users", _ "Win_Account='" & strCurrentUser & "' AND Is_Active=True"), "") ' 3. 邏輯分發 If Len(strRole) = 0 Then LogAccessAttempt strCurrentUser, "FAILED" ' 記錄審計日誌 MsgBox "Access Denied: User [" & strCurrentUser & "] not authorized.", vbCritical Application.Quit acQuitSaveNone Else ' 初始化全局會話變量 TempVars.Add "Current_User", strCurrentUser TempVars.Add "Current_Role", strRole LogAccessAttempt strCurrentUser, "SUCCESS" ' 根據角色跳轉 DoCmd.OpenForm "frm_MainDashboard" End If Exit Sub ErrorHandler: MsgBox "System Error: " & Err.Description, vbCritical Application.Quit End Sub05總結
通過引入 SSO,我們將 Access 的身份驗證委託給了最值得信任的操作系統。這不僅讓代碼更簡潔(無需編寫複雜的密碼哈希、加鹽邏輯),更讓整個系統的安全架構提升到了企業級標準。
**喜歡這篇文章嗎?歡迎點贊、在看、轉發,讓更多 Access 愛好者看到!