基于角色的窗体权限配置:VB.NET+Dapper+Access实现问询
VB.NET 大规模窗体的角色权限控制简洁实现方案
核心思路
采用数据库集中配置权限+基类窗体封装逻辑的方式,避免在每个窗体重复编写权限判断代码,适配大量窗体的场景。Owner角色默认拥有全权限,Admin角色的权限通过数据库配置灵活控制。
一、数据库表结构(补充/调整)
如果现有表缺少权限配置,需新增以下两张表:
Roles(角色表)
| 字段名 | 类型 | 说明 |
|---|---|---|
| RoleId | int(主键) | 角色ID |
| RoleName | varchar(50) | 角色名称 |
FormPermissions(窗体权限配置表)
| 字段名 | 类型 | 说明 |
|---|---|---|
| PermissionId | int(主键) | 权限ID |
| RoleId | int(外键) | 关联Roles表RoleId |
| FormName | varchar(100) | 窗体名称(对应窗体Name属性) |
| ControlName | varchar(100) | 控件名称(空值表示控制窗体访问权限) |
| IsAllowed | bit | 是否允许(1=允许,0=禁止) |
示例数据
| PermissionId | RoleId | FormName | ControlName | IsAllowed |
|---|---|---|---|---|
| 1 | 2 | FrmMain | btnUpdate | 0 |
| 2 | 2 | Form2 | Button1 | 0 |
| 3 | 2 | Form2 | 1 |
二、代码实现
1. 全局用户信息类
存储当前登录用户的角色信息,供全项目调用:
Public Class CurrentUser Public Shared Property RoleName As String ' 登录验证后赋值 End Class
2. 权限管理静态类
负责加载缓存权限配置、提供权限判断方法:
Imports System.Data.SqlClient Imports System.Collections.Generic Public Class PermissionManager ' 缓存权限数据,避免重复查询数据库 Private Shared _permissionCache As Dictionary(Of String, Dictionary(Of String, Boolean)) = Nothing ' 初始化权限缓存 Public Shared Sub InitPermissions() _permissionCache = New Dictionary(Of String, Dictionary(Of String, Boolean))() Dim connStr As String = "你的数据库连接字符串" Using conn As New SqlConnection(connStr) conn.Open() Dim cmd As New SqlCommand("SELECT r.RoleName, fp.FormName, fp.ControlName, fp.IsAllowed FROM Roles r JOIN FormPermissions fp ON r.RoleId = fp.RoleId", conn) Dim reader As SqlDataReader = cmd.ExecuteReader() While reader.Read() Dim roleName As String = reader("RoleName").ToString() Dim fullKey As String = If(String.IsNullOrEmpty(reader("ControlName").ToString()), reader("FormName").ToString(), $"{reader("FormName")}.{reader("ControlName")}") Dim isAllowed As Boolean = Convert.ToBoolean(reader("IsAllowed")) If Not _permissionCache.ContainsKey(roleName) Then _permissionCache.Add(roleName, New Dictionary(Of String, Boolean))() End If _permissionCache(roleName)(fullKey) = isAllowed End While End Using End Sub ' 判断权限:Owner默认全允许 Public Shared Function HasPermission(roleName As String, formName As String, controlName As String) As Boolean If roleName.Equals("Owner", StringComparison.OrdinalIgnoreCase) Then Return True End If If _permissionCache Is Nothing Then InitPermissions() End If Dim checkKey As String = If(String.IsNullOrEmpty(controlName), formName, $"{formName}.{controlName}") Return _permissionCache.ContainsKey(roleName) AndAlso _permissionCache(roleName).ContainsKey(checkKey) AndAlso _permissionCache(roleName)(checkKey) End Function End Class
3. 基类窗体(所有业务窗体继承此类)
封装权限检查逻辑,自动处理控件权限:
Public Class BaseForm Inherits Form Protected Overrides Sub OnLoad(e As EventArgs) MyBase.OnLoad(e) ' 自动绑定按钮的权限检查事件 BindControlPermissionCheck() End Sub ' 为所有按钮绑定权限检查点击事件 Private Sub BindControlPermissionCheck() For Each ctrl As Control In Me.Controls If TypeOf ctrl Is Button Then AddHandler ctrl.Click, AddressOf CheckPermissionBeforeExecute End If Next End Sub ' 点击前检查权限,无权限则弹出提示并拦截原逻辑 Private Sub CheckPermissionBeforeExecute(sender As Object, e As EventArgs) Dim btn As Button = DirectCast(sender, Button) If Not PermissionManager.HasPermission(CurrentUser.RoleName, Me.Name, btn.Name) Then MessageBox.Show("无权限执行此操作!", "权限提示", MessageBoxButtons.OK, MessageBoxIcon.Warning) DirectCast(e, MouseEventArgs).Handled = True End If End Sub End Class
4. 业务窗体改造
所有需要权限控制的窗体继承BaseForm即可:
FrmMain示例
Public Class FrmMain Inherits BaseForm ' 打开Form2的按钮逻辑(需检查窗体访问权限) Private Sub btnOpenForm2_Click(sender As Object, e As EventArgs) Handles btnOpenForm2.Click If PermissionManager.HasPermission(CurrentUser.RoleName, "Form2", "") Then Dim frm2 As New Form2() frm2.Show() Else MessageBox.Show("无权限打开此窗体!") End If End Sub ' 更新按钮原逻辑(仅有权限时执行) Private Sub btnUpdate_Click(sender As Object, e As EventArgs) Handles btnUpdate.Click ' 你的更新业务代码 MessageBox.Show("执行更新操作") End Sub End Class
Form2示例
Public Class Form2 Inherits BaseForm ' Button1原逻辑(仅有权限时执行) Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click ' 你的业务代码 MessageBox.Show("执行Button1操作") End Sub End Class
5. 登录代码改造
登录验证通过后初始化权限缓存:
Private Sub btnLogin_Click(sender As Object, e As EventArgs) Handles btnLogin.Click ' 自行实现用户名密码验证逻辑,获取用户角色 Dim roleName As String = GetUserRole(txtUsername.Text, txtPassword.Text) If roleName IsNot Nothing Then CurrentUser.RoleName = roleName PermissionManager.InitPermissions() ' 初始化权限缓存 Dim mainFrm As New FrmMain() mainFrm.Show() Me.Close() Else MessageBox.Show("登录失败") End If End Sub ' 示例:从数据库获取用户角色 Private Function GetUserRole(username As String, password As String) As String Dim connStr As String = "你的数据库连接字符串" Using conn As New SqlConnection(connStr) conn.Open() Dim cmd As New SqlCommand("SELECT r.RoleName FROM Users u JOIN Roles r ON u.RoleId = r.RoleId WHERE u.Username = @username AND u.Password = @password", conn) cmd.Parameters.AddWithValue("@username", username) cmd.Parameters.AddWithValue("@password", password) Return cmd.ExecuteScalar()?.ToString() End Using End Function
方案优势
- 集中维护:所有权限配置在数据库,新增/修改权限无需修改代码
- 代码复用:基类封装所有权限逻辑,业务窗体只需继承即可
- 性能优化:权限数据仅初始化一次,缓存复用
- 扩展性强:新增窗体/控件只需在数据库添加配置,无需改动业务代码
内容的提问来源于stack exchange,提问作者roy
相关产品推荐
相关产品推荐

