You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

基于角色的窗体权限配置:VB.NET+Dapper+Access实现问询

VB.NET 大规模窗体的角色权限控制简洁实现方案

核心思路

采用数据库集中配置权限+基类窗体封装逻辑的方式,避免在每个窗体重复编写权限判断代码,适配大量窗体的场景。Owner角色默认拥有全权限,Admin角色的权限通过数据库配置灵活控制。


一、数据库表结构(补充/调整)

如果现有表缺少权限配置,需新增以下两张表:

Roles(角色表)

字段名类型说明
RoleIdint(主键)角色ID
RoleNamevarchar(50)角色名称

FormPermissions(窗体权限配置表)

字段名类型说明
PermissionIdint(主键)权限ID
RoleIdint(外键)关联Roles表RoleId
FormNamevarchar(100)窗体名称(对应窗体Name属性)
ControlNamevarchar(100)控件名称(空值表示控制窗体访问权限)
IsAllowedbit是否允许(1=允许,0=禁止)

示例数据

PermissionIdRoleIdFormNameControlNameIsAllowed
12FrmMainbtnUpdate0
22Form2Button10
32Form21

二、代码实现

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

方案优势

  1. 集中维护:所有权限配置在数据库,新增/修改权限无需修改代码
  2. 代码复用:基类封装所有权限逻辑,业务窗体只需继承即可
  3. 性能优化:权限数据仅初始化一次,缓存复用
  4. 扩展性强:新增窗体/控件只需在数据库添加配置,无需改动业务代码

内容的提问来源于stack exchange,提问作者roy

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.12 21:00:00