在C# Winform开发中,构建一个健壮的权限管理系统是企业级应用的核心需求。下面通过三个核心步骤,结合具体代码示例,详细介绍如何快速搭建一个基于角色的权限管理系统。
## 一、数据库设计与模型构建
权限系统的核心是合理的数据库设计,采用经典的RBAC(基于角色的访问控制)模型。
### 1.1 核心数据表设计
以下是权限系统的基本数据表结构:
```sql
-- 用户表
CREATE TABLE Users (
UserID INT PRIMARY KEY IDENTITY(1,1),
Username NVARCHAR(50) NOT NULL UNIQUE,
PasswordHash NVARCHAR(255) NOT NULL,
DisplayName NVARCHAR(100),
Email NVARCHAR(100),
IsActive BIT DEFAULT 1,
CreatedDate DATETIME DEFAULT GETDATE()
);
-- 角色表
CREATE TABLE Roles (
RoleID INT PRIMARY KEY IDENTITY(1,1),
RoleName NVARCHAR(50) NOT NULL UNIQUE,
Description NVARCHAR(255),
CreatedDate DATETIME DEFAULT GETDATE()
);
-- 权限表(菜单/功能)
CREATE TABLE Permissions (
PermissionID INT PRIMARY KEY IDENTITY(1,1),
PermissionName NVARCHAR(100) NOT NULL,
PermissionCode NVARCHAR(50) UNIQUE,
ParentID INT NULL,
MenuType INT DEFAULT 0, -- 0:菜单, 1:按钮
SortOrder INT DEFAULT 0,
Icon NVARCHAR(50),
Url NVARCHAR(255),
IsVisible BIT DEFAULT 1,
FOREIGN KEY (ParentID) REFERENCES Permissions(PermissionID)
);
-- 用户角色关联表
CREATE TABLE UserRoles (
UserID INT,
RoleID INT,
AssignedDate DATETIME DEFAULT GETDATE(),
PRIMARY KEY (UserID, RoleID),
FOREIGN KEY (UserID) REFERENCES Users(UserID),
FOREIGN KEY (RoleID) REFERENCES Roles(RoleID)
);
-- 角色权限关联表
CREATE TABLE RolePermissions (
RoleID INT,
PermissionID INT,
PRIMARY KEY (RoleID, PermissionID),
FOREIGN KEY (RoleID) REFERENCES Roles(RoleID),
FOREIGN KEY (PermissionID) REFERENCES Permissions(PermissionID)
);
```
### 1.2 C#实体类设计
```csharp
// 用户实体类 [ref_5]
[Serializable]
public class User
{
public int UserID { get; set; }
public string Username { get; set; }
public string PasswordHash { get; set; }
public string DisplayName { get; set; }
public string Email { get; set; }
public bool IsActive { get; set; }
public DateTime CreatedDate { get; set; }
// 角色集合
public List<Role> Roles { get; set; } = new List<Role>();
}
// 角色实体类 [ref_5]
[Serializable]
public class Role
{
public int RoleID { get; set; }
public string RoleName { get; set; }
public string Description { get; set; }
public DateTime CreatedDate { get; set; }
// 权限集合
public List<Permission> Permissions { get; set; } = new List<Permission>();
}
// 权限实体类 [ref_5]
[Serializable]
public class Permission
{
public int PermissionID { get; set; }
public string PermissionName { get; set; }
public string PermissionCode { get; set; }
public int? ParentID { get; set; }
public int MenuType { get; set; }
public int SortOrder { get; set; }
public string Icon { get; set; }
public string Url { get; set; }
public bool IsVisible { get; set; }
// 子菜单
public List<Permission> Children { get; set; } = new List<Permission>();
}
```
## 二、数据访问层与业务逻辑实现
### 2.1 数据库连接与基础操作类
```csharp
// 数据库助手类 [ref_1]
public class DbHelper
{
private static string connectionString = ConfigurationManager.ConnectionStrings["DefaultConnection"].ConnectionString;
// 执行查询返回DataTable
public static DataTable ExecuteQuery(string sql, params SqlParameter[] parameters)
{
using (SqlConnection conn = new SqlConnection(connectionString))
{
conn.Open();
using (SqlCommand cmd = new SqlCommand(sql, conn))
{
if (parameters != null)
cmd.Parameters.AddRange(parameters);
DataTable dt = new DataTable();
using (SqlDataAdapter adapter = new SqlDataAdapter(cmd))
{
adapter.Fill(dt);
}
return dt;
}
}
}
// 执行非查询操作
public static int ExecuteNonQuery(string sql, params SqlParameter[] parameters)
{
using (SqlConnection conn = new SqlConnection(connectionString))
{
conn.Open();
using (SqlCommand cmd = new SqlCommand(sql, conn))
{
if (parameters != null)
cmd.Parameters.AddRange(parameters);
return cmd.ExecuteNonQuery();
}
}
}
// 执行事务操作 [ref_1]
public static bool ExecuteTransaction(List<string> sqlList, List<SqlParameter[]> paramList)
{
using (SqlConnection conn = new SqlConnection(connectionString))
{
conn.Open();
using (SqlTransaction tran = conn.BeginTransaction())
{
try
{
for (int i = 0; i < sqlList.Count; i++)
{
using (SqlCommand cmd = new SqlCommand(sqlList[i], conn, tran))
{
if (paramList[i] != null)
cmd.Parameters.AddRange(paramList[i]);
cmd.ExecuteNonQuery();
}
}
tran.Commit();
return true;
}
catch (Exception ex)
{
tran.Rollback();
throw ex;
}
}
}
}
}
```
### 2.2 权限管理业务逻辑
```csharp
// 权限管理服务类 [ref_5]
public class PermissionService
{
// 获取用户的所有权限
public List<Permission> GetUserPermissions(int userId)
{
List<Permission> permissions = new List<Permission>();
string sql = @"
SELECT DISTINCT p.*
FROM Permissions p
INNER JOIN RolePermissions rp ON p.PermissionID = rp.PermissionID
INNER JOIN UserRoles ur ON rp.RoleID = ur.RoleID
WHERE ur.UserID = @UserID AND p.IsVisible = 1
ORDER BY p.SortOrder";
SqlParameter param = new SqlParameter("@UserID", userId);
DataTable dt = DbHelper.ExecuteQuery(sql, param);
foreach (DataRow row in dt.Rows)
{
permissions.Add(new Permission
{
PermissionID = Convert.ToInt32(row["PermissionID"]),
PermissionName = row["PermissionName"].ToString(),
PermissionCode = row["PermissionCode"].ToString(),
ParentID = row["ParentID"] == DBNull.Value ? (int?)null : Convert.ToInt32(row["ParentID"]),
MenuType = Convert.ToInt32(row["MenuType"]),
SortOrder = Convert.ToInt32(row["SortOrder"]),
Icon = row["Icon"].ToString(),
Url = row["Url"].ToString(),
IsVisible = Convert.ToBoolean(row["IsVisible"])
});
}
// 构建树形结构
return BuildPermissionTree(permissions);
}
// 构建权限树 [ref_1]
private List<Permission> BuildPermissionTree(List<Permission> permissions)
{
var permissionDict = permissions.ToDictionary(p => p.PermissionID);
var rootPermissions = new List<Permission>();
foreach (var permission in permissions)
{
if (permission.ParentID == null || permission.ParentID == 0)
{
rootPermissions.Add(permission);
}
else if (permissionDict.ContainsKey(permission.ParentID.Value))
{
permissionDict[permission.ParentID.Value].Children.Add(permission);
}
}
return rootPermissions;
}
// 检查用户是否有特定权限 [ref_6]
public bool HasPermission(int userId, string permissionCode)
{
string sql = @"
SELECT COUNT(1)
FROM Permissions p
INNER JOIN RolePermissions rp ON p.PermissionID = rp.PermissionID
INNER JOIN UserRoles ur ON rp.RoleID = ur.RoleID
WHERE ur.UserID = @UserID AND p.PermissionCode = @PermissionCode";
SqlParameter[] parameters = {
new SqlParameter("@UserID", userId),
new SqlParameter("@PermissionCode", permissionCode)
};
object result = DbHelper.ExecuteScalar(sql, parameters);
return Convert.ToInt32(result) > 0;
}
// 分配角色权限 [ref_1]
public bool AssignRolePermissions(int roleId, List<int> permissionIds)
{
List<string> sqlList = new List<string>();
List<SqlParameter[]> paramList = new List<SqlParameter[]>();
// 先删除原有权限
sqlList.Add("DELETE FROM RolePermissions WHERE RoleID = @RoleID");
paramList.Add(new SqlParameter[] { new SqlParameter("@RoleID", roleId) });
// 添加新权限
foreach (int permissionId in permissionIds)
{
sqlList.Add("INSERT INTO RolePermissions (RoleID, PermissionID) VALUES (@RoleID, @PermissionID)");
paramList.Add(new SqlParameter[] {
new SqlParameter("@RoleID", roleId),
new SqlParameter("@PermissionID", permissionId)
});
}
return DbHelper.ExecuteTransaction(sqlList, paramList);
}
}
```
## 三、Winform界面实现与动态菜单生成
### 3.1 主窗体与动态菜单生成
```csharp
// 主窗体类 [ref_1]
public partial class MainForm : Form
{
private int currentUserId;
private PermissionService permissionService;
public MainForm(int userId)
{
InitializeComponent();
currentUserId = userId;
permissionService = new PermissionService();
// 加载动态菜单
LoadDynamicMenu();
// 设置窗体标题
this.Text = $"权限管理系统 - 当前用户: {GetCurrentUserName()}";
}
// 动态加载菜单 [ref_1]
private void LoadDynamicMenu()
{
// 清空原有菜单
mainMenuStrip.Items.Clear();
// 获取当前用户的权限
List<Permission> userPermissions = permissionService.GetUserPermissions(currentUserId);
// 构建菜单树
BuildMenuFromPermissions(mainMenuStrip.Items, userPermissions);
}
// 递归构建菜单 [ref_5]
private void BuildMenuFromPermissions(ToolStripItemCollection parentItems, List<Permission> permissions)
{
foreach (Permission permission in permissions.OrderBy(p => p.SortOrder))
{
if (permission.MenuType == 0) // 菜单项
{
ToolStripMenuItem menuItem = new ToolStripMenuItem();
menuItem.Text = permission.PermissionName;
menuItem.Tag = permission.PermissionCode;
if (!string.IsNullOrEmpty(permission.Icon))
{
// 加载图标(示例)
menuItem.Image = Image.FromFile($"Icons/{permission.Icon}.png");
}
// 如果有子菜单,递归构建
if (permission.Children != null && permission.Children.Count > 0)
{
BuildMenuFromPermissions(menuItem.DropDownItems, permission.Children);
}
else
{
// 绑定菜单点击事件
menuItem.Click += MenuItem_Click;
}
parentItems.Add(menuItem);
}
else if (permission.MenuType == 1) // 工具栏按钮
{
ToolStripButton button = new ToolStripButton();
button.Text = permission.PermissionName;
button.Tag = permission.PermissionCode;
button.Click += ToolbarButton_Click;
if (!string.IsNullOrEmpty(permission.Icon))
{
button.Image = Image.FromFile($"Icons/{permission.Icon}.png");
}
// 添加到工具栏
mainToolStrip.Items.Add(button);
}
}
}
// 菜单点击事件处理
private void MenuItem_Click(object sender, EventArgs e)
{
ToolStripMenuItem menuItem = sender as ToolStripMenuItem;
if (menuItem != null)
{
string permissionCode = menuItem.Tag?.ToString();
OpenFormByPermission(permissionCode);
}
}
// 根据权限打开对应窗体
private void OpenFormByPermission(string permissionCode)
{
switch (permissionCode)
{
case "USER_MANAGE":
UserManageForm userForm = new UserManageForm();
userForm.MdiParent = this;
userForm.Show();
break;
case "ROLE_MANAGE":
RoleManageForm roleForm = new RoleManageForm();
roleForm.MdiParent = this;
roleForm.Show();
break;
case "PERMISSION_MANAGE":
PermissionManageForm permForm = new PermissionManageForm();
permForm.MdiParent = this;
permForm.Show();
break;
// 添加更多窗体...
}
}
// 获取当前用户名
private string GetCurrentUserName()
{
string sql = "SELECT DisplayName FROM Users WHERE UserID = @UserID";
SqlParameter param = new SqlParameter("@UserID", currentUserId);
DataTable dt = DbHelper.ExecuteQuery(sql, param);
if (dt.Rows.Count > 0)
return dt.Rows[0]["DisplayName"].ToString();
return "未知用户";
}
}
```
### 3.2 用户管理界面实现
```csharp
// 用户管理窗体 [ref_5]
public partial class UserManageForm : Form
{
private DataGridView dgvUsers;
private Button btnAdd;
private Button btnEdit;
private Button btnDelete;
private Button btnAssignRole;
public UserManageForm()
{
InitializeComponent();
LoadUsers();
}
private void InitializeComponent()
{
this.Text = "用户管理";
this.Size = new Size(800, 600);
// 创建DataGridView
dgvUsers = new DataGridView();
dgvUsers.Dock = DockStyle.Fill;
dgvUsers.AutoSizeColumnsMode = DataGridViewAutoSizeColumnsMode.Fill;
dgvUsers.SelectionMode = DataGridViewSelectionMode.FullRowSelect;
dgvUsers.ReadOnly = true;
// 添加列
dgvUsers.Columns.Add("UserID", "用户ID");
dgvUsers.Columns.Add("Username", "用户名");
dgvUsers.Columns.Add("DisplayName", "显示名称");
dgvUsers.Columns.Add("Email", "邮箱");
dgvUsers.Columns.Add("IsActive", "是否激活");
dgvUsers.Columns.Add("CreatedDate", "创建时间");
// 创建按钮面板
Panel buttonPanel = new Panel();
buttonPanel.Dock = DockStyle.Bottom;
buttonPanel.Height = 50;
btnAdd = new Button { Text = "新增", Location = new Point(20, 10), Size = new Size(80, 30) };
btnEdit = new Button { Text = "编辑", Location = new Point(120, 10), Size = new Size(80, 30) };
btnDelete = new Button { Text = "删除", Location = new Point(220, 10), Size = new Size(80, 30) };
btnAssignRole = new Button { Text = "分配角色", Location = new Point(320, 10), Size = new Size(80, 30) };
// 绑定事件
btnAdd.Click += BtnAdd_Click;
btnEdit.Click += BtnEdit_Click;
btnDelete.Click += BtnDelete_Click;
btnAssignRole.Click += BtnAssignRole_Click;
buttonPanel.Controls.AddRange(new Control[] { btnAdd, btnEdit, btnDelete, btnAssignRole });
// 添加到窗体
this.Controls.Add(dgvUsers);
this.Controls.Add(buttonPanel);
}
// 加载用户数据 [ref_6]
private void LoadUsers()
{
string sql = "SELECT * FROM Users ORDER BY CreatedDate DESC";
DataTable dt = DbHelper.ExecuteQuery(sql);
dgvUsers.Rows.Clear();
foreach (DataRow row in dt.Rows)
{
dgvUsers.Rows.Add(
row["UserID"],
row["Username"],
row["DisplayName"],
row["Email"],
Convert.ToBoolean(row["IsActive"]) ? "是" : "否",
Convert.ToDateTime(row["CreatedDate"]).ToString("yyyy-MM-dd HH:mm:ss")
);
}
}
// 新增用户
private void BtnAdd_Click(object sender, EventArgs e)
{
UserEditForm editForm = new UserEditForm();
if (editForm.ShowDialog() == DialogResult.OK)
{
LoadUsers(); // 刷新列表
}
}
// 编辑用户
private void BtnEdit_Click(object sender, EventArgs e)
{
if (dgvUsers.SelectedRows.Count > 0)
{
int userId = Convert.ToInt32(dgvUsers.SelectedRows[0].Cells["UserID"].Value);
UserEditForm editForm = new UserEditForm(userId);
if (editForm.ShowDialog() == DialogResult.OK)
{
LoadUsers();
}
}
else
{
MessageBox.Show("请选择要编辑的用户", "提示", MessageBoxButtons.OK, MessageBoxIcon.Warning);
}
}
// 删除用户
private void BtnDelete_Click(object sender, EventArgs e)
{
if (dgvUsers.SelectedRows.Count > 0)
{
int userId = Convert.ToInt32(dgvUsers.SelectedRows[0].Cells["UserID"].Value);
string username = dgvUsers.SelectedRows[0].Cells["Username"].Value.ToString();
if (MessageBox.Show($"确定要删除用户 '{username}' 吗?", "确认删除",
MessageBoxButtons.YesNo, MessageBoxIcon.Question) == DialogResult.Yes)
{
string sql = "DELETE FROM Users WHERE UserID =