99精品久久精品一区二区-亚洲熟妇无码?v在线播放-日本国产精品无码字幕在线观看-久久久亚洲永夜AV-亚洲一级无码一区二区一-免费国产成高清人在线视频-中文字幕乱码免费观看-国产毛片精品妇女久久久

ARTICLE DETAIL

資訊詳情

深耕商務(wù)建站與企業(yè)官網(wǎng)運(yùn)營(yíng)的一線實(shí)戰(zhàn)洞察。

C# WinForm權(quán)限管理系統(tǒng)實(shí)踐:基于RBAC模型從數(shù)據(jù)庫(kù)設(shè)計(jì)到按鈕級(jí)權(quán)限控制

C# WinForm權(quán)限管理系統(tǒng)實(shí)踐:基于RBAC模型從數(shù)據(jù)庫(kù)設(shè)計(jì)到按鈕級(jí)權(quán)限控制 簡(jiǎn)介一套基于C# WinForm框架開(kāi)發(fā)的權(quán)限管理系統(tǒng)完整源碼包面向需要完成課程設(shè)計(jì)或快速搭建后臺(tái)管理權(quán)限模塊的開(kāi)發(fā)者。系統(tǒng)覆蓋用戶管理、組管理、用戶授權(quán)、菜單管理及菜單授權(quán)等核心功能后臺(tái)默認(rèn)管理員賬號(hào)密碼均為admin開(kāi)發(fā)環(huán)境為Visual Studio數(shù)據(jù)庫(kù)采用SQL Server 2008連接字符串可在app.config中修改。資源共101個(gè)文件以cs源碼、resx/resources界面資源、config配置文件、sln/csproj工程文件為主另含mdf/ldf數(shù)據(jù)庫(kù)文件、exe可執(zhí)行程序及ico圖標(biāo)等壓縮包僅1.63MB目錄結(jié)構(gòu)緊湊便于本地調(diào)試與二次開(kāi)發(fā)。已有497人學(xué)習(xí)下載適合希望快速理解權(quán)限控制流程、完成課設(shè)演示或擴(kuò)展功能的中初級(jí)C#開(kāi)發(fā)者。1. 基于C#的winform框架的權(quán)限管理系統(tǒng)附完整源碼數(shù)據(jù)庫(kù)到底解決什么問(wèn)題上一家公司里權(quán)限還躺在一張有十七個(gè)Sheet的Excel里每次新員工入職要挨個(gè)問(wèn)“你該看哪些菜單”問(wèn)完還要截圖畫(huà)紅線發(fā)給相關(guān)人員核對(duì)。后來(lái)我拿到一套基于C#的winform框架的權(quán)限管理系統(tǒng)附完整源碼數(shù)據(jù)庫(kù)時(shí)第一反應(yīng)不是打開(kāi)界面而是先看表和目錄——只要用戶、角色、菜單、按鈕權(quán)限落到數(shù)據(jù)庫(kù)里新增一個(gè)權(quán)限點(diǎn)就不再需要發(fā)郵件了。這套方案最適合三類(lèi)人中小團(tuán)隊(duì)做內(nèi)部管理系統(tǒng)、給上位機(jī)配一套帶登錄的后臺(tái)、以及想學(xué)C/S架構(gòu)但不想從零寫(xiě)權(quán)限邏輯的開(kāi)發(fā)者。它能解決的核心問(wèn)題只有一個(gè)把散落在窗體事件里的判斷邏輯收斂成一套可配置、可審計(jì)、可復(fù)用的RBAC模型。2. 權(quán)限管理系統(tǒng)的骨架數(shù)據(jù)表設(shè)計(jì)、分層架構(gòu)與源碼包目錄還原拿到壓縮包之后先別急著F5運(yùn)行先花二十分鐘把結(jié)構(gòu)看懂。常見(jiàn)的做法是三層結(jié)構(gòu)加一個(gè)實(shí)體層UI層放窗體BLL層寫(xiě)業(yè)務(wù)校驗(yàn)DAL層做數(shù)據(jù)訪問(wèn)Model層放實(shí)體類(lèi)Common層放加密和權(quán)限判斷等公共方法。這套劃分在中小項(xiàng)目里是性?xún)r(jià)比最高的選型——比單純把代碼堆在Form后面要好維護(hù)又比引入大型框架輕得多。2.1 權(quán)限模型的選型RBAC為什么適合WinForm場(chǎng)景WinForm程序的特點(diǎn)是界面事件密集按鈕點(diǎn)擊、窗體加載、DataGridView行雙擊都能觸發(fā)業(yè)務(wù)操作如果每個(gè)事件里都寫(xiě)if (currentUser.Role admin)后面改權(quán)限就得翻遍整個(gè)解決方案。RBAC模型把用戶和權(quán)限解耦用戶掛在角色下角色綁定權(quán)限點(diǎn)窗體只問(wèn)“當(dāng)前用戶有沒(méi)有某個(gè)權(quán)限標(biāo)識(shí)”不關(guān)心用戶是誰(shuí)、屬于哪個(gè)角色。這樣新增一個(gè)實(shí)習(xí)生賬號(hào)只需要給他掛“訪客”角色而不用改任何代碼。代碼包里如果用了類(lèi)似HasPermission(order:delete)的統(tǒng)一判斷說(shuō)明作者走的就是RBAC路線。不選ABAC基于屬性的訪問(wèn)控制的原因也很簡(jiǎn)單——桌面程序的數(shù)據(jù)量級(jí)和變化頻率都用不上那么復(fù)雜的策略引擎RBAC的平面模型足夠覆蓋90%的內(nèi)部系統(tǒng)需求。后續(xù)如果要做數(shù)據(jù)范圍控制在RBAC上擴(kuò)展一個(gè)數(shù)據(jù)范圍字段就行不需要推翻重來(lái)。2.2 核心數(shù)據(jù)表六張表的字段設(shè)計(jì)與外鍵關(guān)系我打開(kāi)數(shù)據(jù)庫(kù)腳本第一件事就是看表數(shù)量權(quán)限系統(tǒng)最少要有六張表用戶表、角色表、菜單表、按鈕表或者權(quán)限點(diǎn)表、用戶角色關(guān)聯(lián)表、角色權(quán)限關(guān)聯(lián)表。下面是精簡(jiǎn)后的建表腳本去掉了審計(jì)字段和索引保留了核心結(jié)構(gòu)CREATE TABLE Sys_User ( UserId INT IDENTITY(1,1) PRIMARY KEY, UserName NVARCHAR(50) NOT NULL, PasswordHash NVARCHAR(200) NOT NULL, RealName NVARCHAR(50) NULL, DeptId INT NULL, IsEnabled BIT DEFAULT 1, CreateTime DATETIME DEFAULT GETDATE() ); CREATE TABLE Sys_Role ( RoleId INT IDENTITY(1,1) PRIMARY KEY, RoleName NVARCHAR(50) NOT NULL, DataScope TINYINT DEFAULT 1, -- 1全部 2本部門(mén) 3僅本人 Description NVARCHAR(200) NULL ); CREATE TABLE Sys_Menu ( MenuId INT IDENTITY(1,1) PRIMARY KEY, ParentId INT DEFAULT 0, MenuName NVARCHAR(50) NOT NULL, MenuKey NVARCHAR(100) NOT NULL, -- 權(quán)限標(biāo)識(shí)如 order:list FormName NVARCHAR(100) NULL, -- 要打開(kāi)的窗體類(lèi)名 SortOrder INT DEFAULT 0 ); CREATE TABLE Sys_Button ( ButtonId INT IDENTITY(1,1) PRIMARY KEY, MenuId INT NOT NULL, BtnText NVARCHAR(50) NOT NULL, BtnKey NVARCHAR(100) NOT NULL, -- 權(quán)限標(biāo)識(shí)如 order:delete SortOrder INT DEFAULT 0 ); CREATE TABLE Sys_UserRole ( UserRoleId INT IDENTITY(1,1) PRIMARY KEY, UserId INT NOT NULL, RoleId INT NOT NULL ); CREATE TABLE Sys_RoleButton ( RoleButtonId INT IDENTITY(1,1) PRIMARY KEY, RoleId INT NOT NULL, ButtonId INT NOT NULL );這段腳本有四個(gè)地方值得關(guān)注。第一MenuKey和BtnKey用冒號(hào)分隔的層級(jí)命名規(guī)則是“模塊:操作”這比存中文名稱(chēng)要穩(wěn)因?yàn)榻缑嫖陌缚梢噪S便改但權(quán)限標(biāo)識(shí)一旦改了所有權(quán)限判斷的地方都要跟著改。第二Sys_UserRole和Sys_RoleButton是純關(guān)聯(lián)表不需要業(yè)務(wù)字段加IDENTITY主鍵是為了方便按行做日志審計(jì)。第三DataScope字段放在角色表而不是用戶表因?yàn)閿?shù)據(jù)范圍通常按角色統(tǒng)一控制比如銷(xiāo)售部經(jīng)理看全部門(mén)訂單銷(xiāo)售員只看自己的。第四所有表都留了CreateTime這樣的基礎(chǔ)審計(jì)列WinForm程序沒(méi)有中間件幫你記錄操作日志表自己不帶時(shí)間字段后面根本沒(méi)法排查問(wèn)題。2.3 從源碼包還原項(xiàng)目結(jié)構(gòu)目錄命名與主窗體啟動(dòng)流程解壓后常見(jiàn)的項(xiàng)目結(jié)構(gòu)是這樣一個(gè)單頁(yè)簽解決方案頂層是解決方案文件下面按層建文件夾UI層里是登錄窗體、主窗體、各個(gè)業(yè)務(wù)窗體Common層里有權(quán)限判斷幫助類(lèi)和MD5加密類(lèi)??吹絇rogram.cs里寫(xiě)著類(lèi)似下面這樣啟動(dòng)邏輯的基本可以確定是標(biāo)準(zhǔn)WinForm啟動(dòng)流程static class Program { [STAThread] static void Main() { Application.EnableVisualStyles(); Application.SetCompatibleTextRenderingDefault(false); LoginForm login new LoginForm(); if (login.ShowDialog() DialogResult.OK) { Application.Run(new MainForm()); } else { Application.Exit(); } } }這段代碼的邏輯是程序啟動(dòng)先彈登錄窗體登錄成功后才創(chuàng)建主窗體否則直接退出進(jìn)程。注意Application.Run(new MainForm())這個(gè)寫(xiě)法——主窗體不是在啟動(dòng)時(shí)無(wú)腦創(chuàng)建的而是依賴(lài)登錄窗體的返回值。很多新手會(huì)把登錄窗體放在主窗體里new出來(lái)關(guān)掉登錄窗體其實(shí)只隱藏了主窗體還活著這是需要避免的寫(xiě)法。STAThread特性必須保留WinForm的消息循環(huán)依賴(lài)單線程單元模型去掉會(huì)導(dǎo)致剪貼板和拖拽功能異常特別是后面要集成第三方SDK時(shí)必踩。3. 把項(xiàng)目跑通數(shù)據(jù)庫(kù)還原、連接串修改與登錄鏈路調(diào)試很多人卡在第一步不是因?yàn)榇a復(fù)雜而是數(shù)據(jù)庫(kù)沒(méi)起來(lái)。壓縮包里如果帶了.bak文件那是SQL Server的備份文件如果帶的是.sql腳本那是建表和初始數(shù)據(jù)腳本。兩種恢復(fù)方式不一樣先分清你拿到的是哪種。3.1 先還原數(shù)據(jù)庫(kù)再跑程序備份文件與腳本的差異.bak文件需要用SQL Server Management Studio的“還原數(shù)據(jù)庫(kù)”功能或者直接跑一條RESTORE命令。腳本文件則簡(jiǎn)單得多直接在SSMS里打開(kāi)執(zhí)行或者用命令行工具導(dǎo)入。MySQL用戶如果是拿到mysqldump導(dǎo)出的.sql文件命令行導(dǎo)入方式如下mysql -u root -p -e CREATE DATABASE PermissionDB DEFAULT CHARACTER SET utf8mb4; mysql -u root -p PermissionDB dump.sql第一行先創(chuàng)建數(shù)據(jù)庫(kù)第二行把表結(jié)構(gòu)和初始數(shù)據(jù)導(dǎo)入進(jìn)去。注意utf8mb4不能寫(xiě)成utf8否則用戶表里存了生僻字或表情符號(hào)會(huì)直接報(bào)錯(cuò)。導(dǎo)入完成后在數(shù)據(jù)庫(kù)里查一下Sys_User表有沒(méi)有數(shù)據(jù)以及Sys_RoleButton和Sys_Menu有沒(méi)有關(guān)聯(lián)記錄這兩個(gè)表如果全是空的說(shuō)明腳本里沒(méi)帶初始權(quán)限數(shù)據(jù)登錄進(jìn)去也看不見(jiàn)菜單。3.2 連接串修改App.config里的三個(gè)必調(diào)參數(shù)WinForm項(xiàng)目的連接字符串通常放在App.config里我見(jiàn)到過(guò)有人把連接串硬編碼在DAL類(lèi)里結(jié)果換一臺(tái)電腦部署就要重新編譯這是反面教材。正確做法是寫(xiě)在connectionStrings節(jié)點(diǎn)下configuration connectionStrings add namePermissionDb connectionStringServer.;DatabasePermissionDB;User Idsa;Passwordyour_password;PoolingTrue;Max Pool Size100;Connect Timeout15; providerNameSystem.Data.SqlClient / /connectionStrings appSettings add keySalt valuea1b2c3d4 / /appSettings /configurationServer.表示本機(jī)的默認(rèn)SQL Server實(shí)例改成遠(yuǎn)程機(jī)器就填I(lǐng)P地址加實(shí)例名比如192.168.1.10\\SQLEXPRESS。PoolingTrue和Max Pool Size100是給多用戶并發(fā)場(chǎng)景準(zhǔn)備的——WinForm程序雖然不像Web那樣有高并發(fā)但幾十個(gè)客戶端同時(shí)連著同一個(gè)數(shù)據(jù)庫(kù)不開(kāi)連接池就會(huì)頻繁創(chuàng)建連接表現(xiàn)為“偶爾卡一下”。Connect Timeout15是連接超時(shí)秒數(shù)默認(rèn)15秒太長(zhǎng)實(shí)際調(diào)8到10秒夠用。Salt放在appSettings里是密碼加密的加鹽值這個(gè)值一旦啟用了就不要在線上改改了所有已存用戶的密碼全部失效。3.3 登錄鏈路MD5加鹽、登錄態(tài)保持與主窗體傳參登錄窗體的核心邏輯只有三步取輸入框里的值調(diào)BLL層驗(yàn)證成功則把用戶信息放進(jìn)一個(gè)靜態(tài)上下文類(lèi)關(guān)閉登錄窗體。下面的代碼是常見(jiàn)做法private void btnLogin_Click(object sender, EventArgs e) { string userName txtUserName.Text.Trim(); string password txtPassword.Text; if (userName.Length 0 || password.Length 0) { MessageBox.Show(用戶名和密碼不能為空); return; } string salt ConfigurationManager.AppSettings[Salt]; string pwdHash Md5Helper.ComputeHash(password salt); UserModel user new UserBll().Login(userName, pwdHash); if (user null) { MessageBox.Show(用戶名或密碼錯(cuò)誤); return; } UserContext.Current user; this.DialogResult DialogResult.OK; }這段代碼有三個(gè)關(guān)鍵點(diǎn)。第一密碼做了加鹽哈希Md5Helper.ComputeHash(password salt)是把用戶輸入的原密碼拼接固定鹽值再做MD5而不是直接加密原始密碼——直接MD5查彩虹表等于脫褲子放屁。第二UserBll().Login()只返回第一個(gè)匹配的用戶如果數(shù)據(jù)庫(kù)里有重復(fù)用戶名這里會(huì)出問(wèn)題所以Sys_User.UserName建表時(shí)就應(yīng)該加唯一索引。第三登錄成功后把用戶對(duì)象放進(jìn)UserContext.Current這個(gè)靜態(tài)屬性后續(xù)所有窗體通過(guò)UserContext.Current.UserId拿當(dāng)前用戶而不是到處傳參。靜態(tài)類(lèi)在這里是合理的因?yàn)橐粋€(gè)WinForm進(jìn)程里同時(shí)只有一個(gè)登錄用戶不會(huì)有多線程并發(fā)寫(xiě)的問(wèn)題。UserContext里一般還會(huì)順手存一份角色I(xiàn)D列表后面做按鈕權(quán)限判斷用得上省得每查一次權(quán)限就訪問(wèn)一次數(shù)據(jù)庫(kù)。4. 把權(quán)限做細(xì)菜單動(dòng)態(tài)加載、按鈕級(jí)權(quán)限與數(shù)據(jù)范圍過(guò)濾登錄跑通只是第一步。權(quán)限系統(tǒng)最見(jiàn)功夫的是三個(gè)細(xì)節(jié)菜單隨角色動(dòng)態(tài)生成、按鈕能被控制顯隱或禁用、同一份數(shù)據(jù)不同角色看到不同的行。這三件事做扎實(shí)了這套系統(tǒng)才真正稱(chēng)得上“權(quán)限管理系統(tǒng)”。4.1 菜單動(dòng)態(tài)加載用數(shù)據(jù)驅(qū)動(dòng)UI而不是UI驅(qū)動(dòng)數(shù)據(jù)很多WinForm項(xiàng)目的菜單是在設(shè)計(jì)器里一個(gè)個(gè)拖出來(lái)寫(xiě)死的新增一個(gè)窗體要改主窗體代碼、改菜單順序、改圖標(biāo)這跟權(quán)限系統(tǒng)的理念完全相悖。正確做法是登錄后從數(shù)據(jù)庫(kù)查當(dāng)前角色的可見(jiàn)菜單然后遞歸生成菜單項(xiàng)。方式比較靈活——有人用ToolStripMenuItem動(dòng)態(tài)創(chuàng)建有人用TreeView控件。常見(jiàn)的思路是按ParentId分組然后遞歸綁定public void LoadMenus(ToolStripMenuItem rootMenu) { DataTable dt new MenuBll().GetMenusByRole(UserContext.Current.RoleIds); if (dt.Rows.Count 0) return; // 添加根菜單 DataRow[] roots dt.Select(ParentId 0); foreach (DataRow r in roots) { ToolStripMenuItem item new ToolStripMenuItem(r[MenuName].ToString()); item.Tag r[MenuKey].ToString(); rootMenu.DropDownItems.Add(item); AddChildMenus(item, int.Parse(r[MenuId].ToString()), dt); } } private void AddChildMenus(ToolStripMenuItem parent, int parentId, DataTable dt) { DataRow[] children dt.Select(ParentId parentId); foreach (DataRow r in children) { ToolStripMenuItem item new ToolStripMenuItem(r[MenuName].ToString()); item.Tag r[FormName].ToString(); item.Click MenuItem_Click; parent.DropDownItems.Add(item); AddChildMenus(item, int.Parse(r[MenuId].ToString()), dt); } } private void MenuItem_Click(object sender, EventArgs e) { ToolStripMenuItem item sender as ToolStripMenuItem; if (item.Tag null || item.Tag.ToString() ) return; // 通過(guò)反射創(chuàng)建窗體和打開(kāi)子窗體 Type t Type.GetType(MyApp.UI. item.Tag.ToString()); if (t ! null) { Form f (Form)Activator.CreateInstance(t); f.MdiParent this; f.Show(); } }DATA可讀性來(lái)自于dt.Select(ParentId ...)這個(gè)篩選——它假設(shè)數(shù)據(jù)庫(kù)里已經(jīng)按SortOrder排序好了父子關(guān)系通過(guò)ParentId指向MenuId構(gòu)成樹(shù)。我把Item.Tag存了兩個(gè)東西根菜單存MenuKey權(quán)限標(biāo)識(shí)子菜單存FormName窗體類(lèi)名通過(guò)反射動(dòng)態(tài)創(chuàng)建窗體實(shí)例。這樣每新增一個(gè)業(yè)務(wù)窗體只需要在數(shù)據(jù)庫(kù)菜單表里插一行記錄并寫(xiě)個(gè)窗體類(lèi)代碼里完全不需要新增菜單項(xiàng)。注意子菜單的Tag存的是窗體類(lèi)名這個(gè)類(lèi)必須在UI層的命名空間下反射的Type.GetType()才能按字符串找到類(lèi)型不然會(huì)在運(yùn)行時(shí)報(bào)找不到類(lèi)型。4.2 按鈕級(jí)權(quán)限用Tag標(biāo)記加遞歸掃描實(shí)現(xiàn)WinForm沒(méi)有Web那種現(xiàn)成的按鈕授權(quán)機(jī)制要在窗體的按鈕上做權(quán)限控制就得自己掃。我是按下面這個(gè)思路做的給每個(gè)需要權(quán)限控制的按鈕Tag屬性設(shè)成權(quán)限點(diǎn)標(biāo)識(shí)窗體加載時(shí)調(diào)用一個(gè)擴(kuò)展方法遞歸掃描所有控件按Tag查權(quán)限沒(méi)有權(quán)限的直接Visible false或者禁用。代碼如下public static class PermissionExtensions { public static void ApplyButtonPermission(this Control root) { foreach (Control c in root.Controls) { if (c is Button c.Tag ! null) { string permKey c.Tag.ToString(); if (permKey.StartsWith(perm:)) { string key permKey.Substring(5); if (!UserContext.HasPermission(key)) { c.Visible false; } } } // 遞歸處理子容器Panel、GroupBox、TabPage 都是容器 if (c.HasChildren) { ApplyButtonPermission(c); } } } }這段代碼的靈魂在遞歸處理子容器。WinForm里Panel、GroupBox、TabControl的子頁(yè)都是容器控件按鈕嵌在容器里時(shí)直接遍歷頂層Controls是掃不到的必須遞歸深入每一層。我見(jiàn)過(guò)有人在每個(gè)窗體里寫(xiě)一遍按鈕遍歷邏輯代碼重復(fù)不說(shuō)漏掉Tab頁(yè)里的按鈕是常有的事。UserContext.HasPermission(key)內(nèi)部是拿當(dāng)前用戶的權(quán)限集合做Contains判斷這里集合建議在登錄后一次性加載進(jìn)內(nèi)存不要每次都查數(shù)據(jù)庫(kù)否則按鈕多的窗體打開(kāi)會(huì)明顯卡頓。這里還有一個(gè)容易被忽略的坑如果按鈕橫跨多個(gè)Tab頁(yè)TabControl里只有當(dāng)前激活的Tab頁(yè)控件會(huì)被創(chuàng)建未激活頁(yè)里的按鈕遍歷不到要在窗體Shown事件時(shí)調(diào)一次并在SelectedTabChanged時(shí)再調(diào)一次。4.3 數(shù)據(jù)范圍權(quán)限同一個(gè)查詢(xún)方法不同角色看到不同行菜單和按鈕控制的是“能不能點(diǎn)”數(shù)據(jù)范圍控制的是“能看哪些行”。比如訂單查詢(xún)老板要看全公司經(jīng)理看本部門(mén)員工看自己。實(shí)現(xiàn)方式通常是把數(shù)據(jù)范圍判斷下推到SQL層而不是查出結(jié)果再在內(nèi)存里過(guò)濾——內(nèi)過(guò)濾又慢又不安全繞開(kāi)界面直接調(diào)BLL層一樣能拿到全量數(shù)據(jù)。我在SQL里加了一個(gè)DataScope參數(shù)存儲(chǔ)過(guò)程或查詢(xún)語(yǔ)句里根據(jù)角色設(shè)置做條件拼接SELECT o.OrderId, o.OrderNo, o.Amount, o.CreateBy, d.DeptName FROM Orders o INNER JOIN Sys_User u ON o.CreateBy u.UserId INNER JOIN Sys_Dept d ON u.DeptId d.DeptId WHERE (DataScope 1) -- 全部 OR (DataScope 2 AND u.DeptId DeptId) -- 本部門(mén) OR (DataScope 3 AND o.CreateBy UserId) -- 僅本人數(shù)據(jù)范圍值放在角色表里用戶登錄時(shí)拿到的是他自己的所有角色的最小范圍或最大范圍這取決于業(yè)務(wù)規(guī)則——有的系統(tǒng)按最嚴(yán)的來(lái)有的按最寬的來(lái)。最常見(jiàn)的做法是取最小范圍也就是對(duì)用戶最安全的那個(gè)。這里要注意一點(diǎn)如果同一用戶的多個(gè)角色分別配置了“全部”和“僅本人”到底按哪個(gè)生效需要在產(chǎn)品層面定好規(guī)則否則就會(huì)出現(xiàn)“為什么我改了用戶的角色他看到的數(shù)據(jù)反而更多了”的困惑。參數(shù)化的WHERE條件避免了拼接SQL注入的問(wèn)題但DataScope變量本身也要走參數(shù)不能直接用常量拼接進(jìn)SQL。4.4 用委托和事件解耦權(quán)限變更角色改權(quán)限后不用重啟程序權(quán)限改了不生效是WinForm系統(tǒng)最尷尬的場(chǎng)景——管理員在權(quán)限管理窗體里給某個(gè)角色勾選了一個(gè)新按鈕權(quán)限正在使用這個(gè)角色的用戶必須重啟程序才能看到變化。這是因?yàn)榈卿洉r(shí)權(quán)限集合已經(jīng)被靜態(tài)變量緩存住了。一個(gè)成熟的方案是用C#委托和事件做權(quán)限變更通知權(quán)限發(fā)生修改時(shí)觸發(fā)全局事件正在運(yùn)行的所有窗體訂閱這個(gè)事件并重新拉取權(quán)限列表。public static class PermissionBus { public static event EventHandlerPermissionChangedEventArgs PermissionsChanged; public static void RaisePermissionChanged(int roleId) { PermissionsChanged?.Invoke(null, new PermissionChangedEventArgs(roleId)); } } // 在某個(gè)業(yè)務(wù)窗體中訂閱 protected override void OnLoad(EventArgs e) { base.OnLoad(e); PermissionBus.PermissionsChanged (s, args) { if (args.RoleId UserContext.Current.RoleId) { UserContext.RefreshPermissions(); this.ApplyButtonPermission(); // 重新掃描按鈕權(quán)限 LoadOrderList(); // 刷新當(dāng)前可見(jiàn)的列表數(shù)據(jù) } this.BeginInvoke(new Action(() { // 更新界面上的按鈕和菜單狀態(tài) })); }; }事件里回調(diào)的代碼要特別注意線程問(wèn)題如果事件是從權(quán)限管理窗體的線程里觸發(fā)的直接更新其他窗體的控件會(huì)拋“跨線程訪問(wèn)控件”異常所以這里用BeginInvoke把更新動(dòng)作切回UI線程執(zhí)行。如果窗體已經(jīng)關(guān)閉事件里還會(huì)訪問(wèn)已釋放的控件需要在Dispose時(shí)取消訂閱。這里只展示了事件訂閱和權(quán)限刷新兩個(gè)核心動(dòng)作真正實(shí)現(xiàn)時(shí)還要在權(quán)限管理窗體的“保存角色權(quán)限”按鈕里調(diào)用PermissionBus.RaisePermissionChanged(roleId)通知全局。這樣權(quán)限更新后正在使用的用戶不需要重啟當(dāng)前打開(kāi)的產(chǎn)品在下次操作前就會(huì)刷新按鈕狀態(tài)體驗(yàn)上更接近Web系統(tǒng)。5. 從這套系統(tǒng)里踩到的5個(gè)坑及排查手法前面講的都是設(shè)計(jì)層面實(shí)際運(yùn)行里還有一堆玄學(xué)問(wèn)題。以下五條都是我親手踩過(guò)的按“現(xiàn)象→原因→解決”展開(kāi)每條都能對(duì)應(yīng)一個(gè)真實(shí)的翻車(chē)現(xiàn)場(chǎng)。5.1 登錄閃退密碼為空和連接串不對(duì)兩座大山現(xiàn)象是裝好數(shù)據(jù)庫(kù)、改好連接串一按登錄按鈕程序直接消失連閃退窗口都看不到。第一次遇到時(shí)會(huì)覺(jué)得是代碼Bug其實(shí)九成是數(shù)據(jù)層異常沒(méi)被捕獲程序靜默崩潰了。最常見(jiàn)的原因是Sys_User表里新導(dǎo)入的用戶密碼字段為NULL登錄時(shí)調(diào)Md5Helper.ComputeHash(password salt)直接把空值和鹽拼在一起拋了ArgumentNullException。我的修復(fù)方式是在加密前判空并且把登錄邏輯包在一層全局異常捕獲里把異常信息先寫(xiě)到本地日志再?gòu)棿皊tring pwdHash null; if (!string.IsNullOrEmpty(password)) { pwdHash Md5Helper.ComputeHash(password salt); } try { user new UserBll().Login(userName, pwdHash ?? ); // 后續(xù)處理 } catch (SqlException ex) { LogHelper.WriteError(ex.ToString()); MessageBox.Show(登錄失敗請(qǐng)查看日志, 錯(cuò)誤); }第二類(lèi)原因是數(shù)據(jù)庫(kù)連接失敗但MessageBox被登錄界面的異常吞了排查方法是直接測(cè)試連接串能不能連通用SqlConnection打開(kāi)試試。不要相信“我看連接串寫(xiě)對(duì)了”實(shí)際拷到測(cè)試環(huán)境里跑一遍才是最穩(wěn)的驗(yàn)證方法。另外登錄窗體F5啟動(dòng)直接閃退還有一類(lèi)原因是App.config編譯后沒(méi)被復(fù)制到輸出目錄ConfigurationManager.ConnectionStrings讀出來(lái)是null取值時(shí)報(bào)空引用檢查一下app.config的“復(fù)制到輸出目錄”屬性是不是“始終復(fù)制”。5.2 權(quán)限改了不生效管理員和普通用戶各執(zhí)一詞現(xiàn)象是管理員在權(quán)限管理界面給角色勾了“刪除訂單”按鈕被授權(quán)用戶反饋“界面上根本沒(méi)有這個(gè)按鈕”兩邊都重啟過(guò)開(kāi)始懷疑是代碼寫(xiě)錯(cuò)。原因在于登錄時(shí)權(quán)限集合緩存進(jìn)了UserContext的靜態(tài)數(shù)組里按鈕掃描走的是緩存數(shù)據(jù)完全不感知數(shù)據(jù)庫(kù)已經(jīng)變了。這個(gè)問(wèn)題的解法就是上一章說(shuō)的PermissionBus事件但要考慮一個(gè)邊緣情況如果權(quán)限管理窗體和業(yè)務(wù)窗體不在同一個(gè)進(jìn)程事件跨進(jìn)程是觸發(fā)不到的——同一個(gè)WinForm進(jìn)程內(nèi)沒(méi)問(wèn)題如果你拆了多個(gè)進(jìn)程就得退而求其次在業(yè)務(wù)窗體加一個(gè)“重新加載權(quán)限”的右鍵菜單手動(dòng)刷新。我自己的項(xiàng)目里兩種方案都做了事件負(fù)責(zé)自動(dòng)刷新右鍵菜單兜底。排查這類(lèi)問(wèn)題最快的辦法是寫(xiě)一個(gè)測(cè)試按鈕直接打印UserContext.RolePermKeys集合里的值對(duì)比數(shù)據(jù)庫(kù)里實(shí)際配置的權(quán)限點(diǎn)立刻能定位是緩存沒(méi)刷新還是權(quán)限點(diǎn)本身沒(méi)匹配上。5.3 多用戶同時(shí)操作卡死連接池占滿與事務(wù)隔離級(jí)別現(xiàn)象是十幾個(gè)人同時(shí)登錄后程序越來(lái)越慢偶爾直接報(bào)“連接池已滿”或者“事務(wù)死鎖”。這里要分兩種原因。連接池占滿是連接未釋放排查數(shù)據(jù)訪問(wèn)層代碼看是否有忘記調(diào)Dispose或Close的情況。WinForm里最常見(jiàn)的泄漏點(diǎn)是DataTable作為返回值時(shí)連接被隱式保持用SqlDataAdapter.Fill()之后連接會(huì)自動(dòng)關(guān)閉但很多人習(xí)慣先Open()再Fill()這個(gè)Open()的裸連接如果沒(méi)放進(jìn)using里就泄漏了。死鎖則是事務(wù)隔離級(jí)別問(wèn)題權(quán)限系統(tǒng)里批量更新比如給角色分配幾百個(gè)按鈕權(quán)限時(shí)先刪除再插入很容易在并發(fā)下形成鎖競(jìng)爭(zhēng)。我的做法是給批量更新加上顯式事務(wù)并設(shè)置隔離級(jí)別為READ COMMITTED同時(shí)在連接串上配置PoolingTrue和合理的Max Pool Size。還要注意MySQL和SQL Server的事務(wù)隔離級(jí)別默認(rèn)值還不一樣如果數(shù)據(jù)庫(kù)是MySQL默認(rèn)REPEATABLE READ在批量插入時(shí)死鎖概率比SQL Server的READ COMMITTED高得多。5.4 WinForm界面美化和DataGridView顯示權(quán)限狀態(tài)翻車(chē)這套系統(tǒng)的界面都是原生控件客戶看到的第一反應(yīng)往往是“這個(gè)系統(tǒng)怎么像Windows 98”。做界面美化要克制直接用第三方主題組件庫(kù)是個(gè)可行方向但要注意授權(quán)企業(yè)商用收費(fèi)不便宜。不花錢(qián)的替代方案是把默認(rèn)按鈕的邊框和背景色統(tǒng)一調(diào)整用FlatStyle配合自定義繪制這樣至少風(fēng)格統(tǒng)一。另一個(gè)高頻翻車(chē)點(diǎn)是權(quán)限管理界面用DataGridView顯示“用戶擁有的角色列表”業(yè)務(wù)字段是0和1默認(rèn)情況下顯示成一個(gè)難看的文本列。解決方案是使用DataGridViewCheckBoxColumn并設(shè)置TrueValue1和FalseValue0代碼里再配合CurrentCellDirtyStateChanged事件確保用戶點(diǎn)擊復(fù)選框時(shí)值能及時(shí)更新到數(shù)據(jù)源DataGridViewCheckBoxColumn col new DataGridViewCheckBoxColumn(); col.HeaderText 啟用; col.DataPropertyName IsEnabled; col.TrueValue 1; col.FalseValue 0; dataGridView1.Columns.Add(col);如果不明白TrueValue和FalseValue的作用你就會(huì)看到一個(gè)詭異現(xiàn)象數(shù)據(jù)庫(kù)里明明存的1/0界面上勾選了但保存后依然是原值或者顯示與存儲(chǔ)完全對(duì)不上。原因是DataGridViewCheckBoxColumn默認(rèn)把true/false映射到單元格值不告訴它“1”代表“真”它就把“1”當(dāng)字符串顯示出來(lái)。排錯(cuò)時(shí)先看單元格的Value類(lèi)型別上來(lái)就改數(shù)據(jù)庫(kù)。5.5 集成第三方SDK觸發(fā)Access Violation C0000005權(quán)限系統(tǒng)如果還要對(duì)接掃碼槍、加密狗、門(mén)禁設(shè)備或PLC上位機(jī)特別是工業(yè)現(xiàn)場(chǎng)桌面軟件你很可能要引第三方原生DLL?,F(xiàn)象是調(diào)用一個(gè)簽名看起來(lái)沒(méi)問(wèn)題的接口程序直接崩潰Windows事件日志里寫(xiě)Access Violation C0000005這個(gè)錯(cuò)誤是內(nèi)存訪問(wèn)違規(guī)WinForm托管代碼本身幾乎不會(huì)觸發(fā)九成是C#調(diào)用C類(lèi)庫(kù)時(shí)出了問(wèn)題。常見(jiàn)原因是DLL調(diào)用約定不匹配——C導(dǎo)出函數(shù)默認(rèn)cdeclC#默認(rèn)StdCallDllImport里要顯式指定CallingConvention。更隱蔽的原因是委托被垃圾回收把一個(gè)回調(diào)函數(shù)委托傳給原生DLL后沒(méi)保持引用原生代碼回調(diào)時(shí)托管堆上那塊內(nèi)存已經(jīng)被回收直接崩掉。排查步驟先確認(rèn)DLL是32位還是64位跟程序集的目標(biāo)平臺(tái)對(duì)齊再統(tǒng)一DllImport簽名把回調(diào)委托保存在靜態(tài)字段最后用DllImport聲明里的SetLastErrortrue觀察Marshal.GetLastWin32Error()的輸出把崩潰收斂成可讀的錯(cuò)誤碼。6. 驗(yàn)證權(quán)限系統(tǒng)是否達(dá)標(biāo)5個(gè)自測(cè)動(dòng)作和一個(gè)必守的編碼紀(jì)律方案落地后我每次交付前都會(huì)按固定順序做5個(gè)自測(cè)動(dòng)作能過(guò)完這套流程基本說(shuō)明權(quán)限系統(tǒng)沒(méi)有硬傷。第一個(gè)動(dòng)作是新建一個(gè)低權(quán)限角色只給“查看”權(quán)限登錄進(jìn)去確認(rèn)菜單、按鈕、數(shù)據(jù)范圍三層全都受限。第二個(gè)動(dòng)作是用管理員權(quán)限去反面驗(yàn)證——給低權(quán)限角色加一個(gè)“刪除”權(quán)限用戶不用重啟在已打開(kāi)的界面上等幾秒按F5刷新看按鈕是否出現(xiàn)。第三個(gè)是數(shù)據(jù)范圍測(cè)試建三個(gè)賬號(hào)分別掛在“全部/本部門(mén)/僅本人”的角色下查詢(xún)同一張表確認(rèn)行數(shù)逐級(jí)遞減。第四個(gè)是并發(fā)測(cè)試兩個(gè)客戶端同時(shí)修改同一個(gè)角色的權(quán)限配置確認(rèn)不會(huì)出現(xiàn)死鎖或者保存后互相覆蓋。最后一個(gè)是日志檢查在數(shù)據(jù)庫(kù)操作日志里看每個(gè)權(quán)限點(diǎn)變更都能追溯到操作人和時(shí)間戳沒(méi)有日志的權(quán)限系統(tǒng)等于沒(méi)做審計(jì)。這個(gè)流程走完再補(bǔ)一個(gè)我從項(xiàng)目里學(xué)到的紀(jì)律所有權(quán)限判斷只能出現(xiàn)在一個(gè)地方——封裝成HasPermission(string key)方法任何窗體不允許出現(xiàn)if (UserContext.Current.RoleId 1)這類(lèi)代碼。因?yàn)椤癛oleId等于1”是硬編碼它假設(shè)了數(shù)據(jù)庫(kù)里ID為1的角色永遠(yuǎn)是管理員但這個(gè)假設(shè)在產(chǎn)品維護(hù)期大概率會(huì)被打破。我接手過(guò)一套系統(tǒng)到處是這種判斷后來(lái)客戶要求把“超級(jí)管理員”改成角色名是“系統(tǒng)管理員”的另一個(gè)角色翻遍代碼改了三天。用HasPermission方法統(tǒng)一判斷權(quán)限變更只影響數(shù)據(jù)庫(kù)配置代碼零改動(dòng)。WinForm權(quán)限管理系統(tǒng)的價(jià)值在于交付后不用頻繁發(fā)版角色和權(quán)限的調(diào)整全部收斂到數(shù)據(jù)庫(kù)里這對(duì)維護(hù)期的團(tuán)隊(duì)來(lái)說(shuō)就是最大的省心。希望這篇能幫你少走一些我走過(guò)的彎路。本文還有配套的精品資源點(diǎn)擊獲取
返回列表
PREV
查看更多資訊
NEXT
返回資訊列表
开心五月激情| 色婷婷五月影视| 第四色五月天| 电影蜘蛛女| 超碰人人摸人人操| 天堂久久精品| 五月婷婷六月丁香色| 五月丁香自拍| 狠狠干激情五月| 综合网网欲色| 无码91中文字幕| 草做免费在线观看| 日韩无码成人电影| 日韩AV在线影片| 99热这里只有精品4| 噜噜色天天开心| 五月婷婷很很色| 99免费在线视频| 婷婷五月天成人五月天| 午夜爱插插| 精品亚洲国产成AV人片传媒| 伊人五月天在线| 丁香六月毛片| 色五月久久成人婷婷| 日本理论久久| 1024久婷| 亚洲av综合在线| 五月久久婷婷丁香| 久久激情五月婷婷| 99热九九热| 热中文字幕| 婷婷狠狠青青| 日本高清不卡免费一区二区三区| 色色a| 日本成人小说婷婷六月| 伊人丁香花综合影院| 丁香色色色| 亚洲AV永久无码影院黑人| www.婷婷| 五月天伊人| 色色色色色色色色色色色色色97| 丁香五月人妻| 五月丁查人人| 第四色婷婷丁香五月| 婷婷激情五月天7| 色五月婷婷五月天| 久久色六月| 亚洲欧美婷婷五月色综合| 蜜臀丁香黄色婷婷五月天| 激情碰碰碰| 中文字幕在线免费看线人| 天天高潮夜夜爽| 亚洲成人综合在线| 99在线er热| 色婷婷网| 99热这里有精品6| 影音先锋一区二区三区| 丁香五月成人| 丁香香五月激情免费视频| 99 re视频一区| 久久婷婷丁香视频网| 伊人爱爱日本| 国产亚洲色婷婷久久99精品91 www.riverspirits.org www.hnnun.com www.changh | 五月天丁香看婷婷| WWW、日本色丁香、co m| AA片在线观看视频在线播放| 九九精品免费视频99| 色噜噜狠狠色综合日日| 国产亚洲精品久久久久久豆腐| 中文字幕不卡+婷婷五月| 一本色道久久综合狠狠躁小说| 99热精品一区| 99热这里有精品| www.狠狠操| 五月综合777| 五月丁香六月激情狠狠| 伊人婷婷五月天av| 国产精品国产| 大香蕉九九| 婷婷五月综合网| av网址在线| 玖玖在线| 久久综合久色欧美综合狠狠| 超级碰人人操人人干| 99视频在线看| 五月天婷婷xxx| 五月天婷婷色| 五月天婷婷激情综合| 久久综合五月天| 日本丁香五月| 99九九视频| 九月丁香婷婷综合| 亚洲熟妇AV乱码在线观看| 丰满人妻妇伦又伦精品国产 | www.99久久久| 狠狠搞综合色| 日韩精品一区二区亚洲AV观看| 综合网啪| 草了bav视频在线观看| 中文字幕网伦射乱中文| 色五月成人| 袁子仪视频观看| 日本精品99网站| 九九热在线亚洲免费视频| 夜夜涩涩涩| 天天日天天操天天干| 婷婷.com| 国产69久久久欧美黑人A片 | 久久久com| 五月婷丁香| 影音先锋噜一噜| 婷婷综合五月天| 婷婷日韩| 5月丁香综合网| 九九色综合九九色| 国产美女无遮挡裸体毛片A片| 91色综合久久| 婷婷久久五月天亚洲欧美国产日韩在线观看| 日本99视频| 日韩狠狠色| 亚洲乱码成人| 激情第四色| www.com色播五月天| 色婷婷狠| 久热69| 色99色| 婷婷自拍| 丁香久久| 夂夂夂夂夂夂夂夂夂夂夂夂夂夂夂夂夂夂夂亚洲亚洲亚洲亚洲亚洲亚洲亚洲亚洲色 | 99热在线观看| 色五月色五天色情网| 久热视频这里只有精品68| 色99在线| 精品国产AV色一区二区深夜久久 | 色婷婷狠狠| site:pzdcoin.com| 亚洲av成人在线| 日本WwW色偷偷丁香花久久久京东热| 99ri精品在线| 色五月婷婷九月| 激情玖玖sh| 天天插操| 在线可以看的av网址| 五月天激情国产综合婷婷| 欧美精品狠狠色丁香婷婷| 久久五月天激情美女| 五月天激情综合10p| 色5月婷婷| 色综合色色色色色| 2020日日干| 777.色色| 白人荫道BBWBBB大荫道| site:picc-up.com| 少妇熟女视频一区二区三区| 亚洲九九免费| 九九久久99| 大香蕉Av在线| 九九人人精品| 99热99干| 日日操日日撸| 亚洲性爱电影| 91碰碰| 五月天综合久久丁香91| 久热大香蕉| 色色丁香婷婷| 99性爱视频网站| 天天日天天舔| hd五月婷婷在线| 狠狠色中色| 成人小说 五月天 婷婷| 精品一区二区三区四区五区六区| 四季8848精品成人免费网站| 六月天丁婷婷| 五月天色站| 婷婷香五月天| 亚洲色综合| 丁香色五月 97干| 婷婷色五月丁香六月欧美啪| 玖玖爱综合网| 激情四射五月天| 天色综合网| 91视频综合网| 丁香五月激情六月欧亚激情综合导航| 久久99久久99久久99人受| 成人AV免费观看| 亚洲综合另类| 五月婷婷六月天| 婷婷成人小说综合| 天天干天天拍| 激情五月天婷婷久久久久久久久久久| 五月激情在线| 天天色天天色天天色天天色天天色天天色| 亚洲妇女熟BBW| 天天干天天操天天上| 91九色最新视频| 五月天婷婷高清无码| 五月婷婷很很色| 婷婷激情丁香六月| 色吧综合网| 亚洲国产精品VA在线看黑人| 久久久久久综合五月婷婷| 日本WwW色偷偷丁香花久久久京东热| 美女视频图片久久91| 国内婷婷丁香社区在线播放| 变天就操逼婷婷五月| 深爱五月激情| 插插五月天| 色婷狠狠| 777精品久无码人妻蜜桃| 欧美三级视频下载| 精品夜夜澡人妻无码AV| 丁香五月天激情综合网| 99久久网站| 八戒青柠影视剧在线观看| 婷婷丁香亚洲五月天| 超色欲天天| 99精品在线观看视频| 大地资源色婷婷视频在线| 天天婷婷综合亚洲亚洲| 中文字幕成人| 日韩色情亚洲五月天婷婷| 欧洲精品爱爱| 日本久久精品| 五月天AV大香蕉| 五月天激情丁香| 五月婷婷人妻| 蜜桃婷婷丁香五月天狠狠久久综合| 伊人久久大香线蕉亚洲五月天,| 九九99在线免费在线观看视频| 婷婷天天综合| 天天网站天天爽| 99九九视频精彩在线| 国产做A爰片毛片A片美国| 婷婷五月综合在线视频| 天天久久66xxx| www.久操| 欧美日韩婷婷五月天| 久久色婷婷| 激情五月天免费视频| 色婷婷狠| 久久激情五月网| 久久五月天精品视频| 天天搽天天射| 超碰97干| 97人人看一| 任你草| 色色色在线观看| 丁香六月AV| 丁香五月激情婷婷| 91久久99久久91熟女精品| 日日干夜夜撸夜夜骑| AV操逼网| 亚洲综合视频在线| 91碰| 国产精品成人AV在线| 日日操夜夜操不卡| av在线免费播放观看| 91精品久久久久久77777| 99热成人在线观看| 六月丁香影院| 婷婷色基地在线看 | 成人做爰A片免费看网站找不到了| 97久久婷婷色| A一级操| 亚欧州精品视频| 深爱激情网五月天| 青青草六月丁香| 色色永久| 日本熟女内射| 五月婷婷丁香五月婷婷丁香| 婷婷成人视频| 六月色播| 久久3p| 色色色色网站| 色情五月天丁香社区| 亚洲另类日本| 九热...av| 丁香五月情| 4399在线观看免费高清黄色视频| 99热亚洲| 91啪啪视频| 97碰| 国产精品在线视频| 涩婷婷视频快播人妻| 久久无意婷婷| 99热亚州综合| 久久免费操| 91网站黄| 激情五月婷婷欧美极品| 婷婷色系婷色| 婷婷五月天激情文学| 天堂草在线看www| 婷香五月激情视频| 综合激情视频| 91丁香色| 色人久夂| 美女100%露全身无挡网站| 五月丁香六月合| 美女五月天婷婷| 九九九九操逼| 91色操| 伊人九九九久| 婷婷六月天激情| 激情丁香淫荡婷婷| 婷婷五月天美女视频| 五月六月激情| 可以直接看的AV| 九九热精品视频在线观看| 成人永久免费视频在线观看| 99热免费| 一本色道久久88综合日韩精品| 丁香五月婷婷综合啪啪| 婷婷久久免费| 久久这里99| 精品人妻伦一二三区久| 亚洲精品久久久久久久久久飞鱼| 国产成人精品一区二三区熟女在线| 色婷婷丁香花五月天| 婷婷丁香五月天熟女丝袜| 日韩在线99| 色色色精品无码区| 色哟哟www| 国产欧美日韩综合精品一区二区| 日韩啪啪视品| 另类图片激情五月天| 五月天,激情四射,婷婷频道| 狠狠爱综合| 九月性爱网| www.超碰| 日韩99视频| 国产FREESEXVIDEOS性中国| 国产成人精品123区免费视频| 涩涩婷婷五月| 五月丁香六月婷婷综合网缴情| 丁香色五月 97干| 五月天社区婷婷| WWW免费视频碰碰碰碰| 五月天婷婷六月| 五月丁香六月激情综合| 色情成人五月天| 五月天婷五月天综合网小说首页-五月天激激婷婷大综合,婷婷亚洲综合五月天小说 | 免费97碰碰| 国产日韩欧美性生活| 丁香五月亚洲| 先锋影音av色五月天资源站| 99热精品观看| 久色精品| sisi热国产| 超碰人人99| 一本大道熟女人妻中文字幕在线| 97精品欧美91久久久久久久| 99热手机在线精品| 影音先锋男人av资源站| 99秘 在线| 久久久久人妻精品| 激情久久婷婷| 色播五月天激情| www.丁香黄色五月天人与| 亚洲五月天色| 亚洲综合99| 99热主页日本| 97人凄人人操人人爽| 天堂亚洲 在线| 婷婷.com| 97婷婷五月激情六月丁香伊人| 九色视频这里只有精品| 丁香五月-激情综合| 五月激情另类| 思思re最新视频| 五月欧美色播| 26uuu欧美| 久婷婷五月丁香在线观看| 亚洲超碰在线| 色色日韩| 国产精品久久久爽爽爽麻豆色哟哟| 丁香5月激情网| 在线99色| 任你日视频| 99碰| 丁香五月婷婷在线观看| 婷婷视频在线碰| α久久| 综合色色五月| 91精品综合久久久久久五月丁香 | 亚洲网站999| 五月狠狠| se99视频| 国产亚洲在线| 国产精品日本一区二区在线播放| 亚洲欧州色情在线观看| 欧美色碰| 狠狠操狠狠插| 91丁香综合| 一级A片天天操夜夜操| 亚洲视频在线观看| 久久人妻伦理| 99热这里| 曰韩少妇内射免费播放| 日日狠狠久久偷偷四色综合免费 | 桃色成人网| 思思综合热| 69久久久| 丁香六月在线| www.26uuu.com亚洲电影| 久青草大香蕉| 五月丁香综合激情网| 五五月丁香花激情综合网| 综合色五月| 99久久这里只有精品免费官网| 丁香狠狠干| 99aese| 淫荡A片| 色香蕉影院| 五月天成人在线视频丁香| 97超级碰人人| 26UUU欧美激情一区二区| 色性综合| 影音先锋 一区| 在线另类| 5月丁香婷婷激情网| 99日韩| 丁香五月天操B| 五月婷婷AV| 色一情一乱一乱一区91Av| 操老逼综合网| 激情五月婷婷丁香| 五月色婷婷综合| 五月综合视频在线| 欧美网站视频4399| 日本二级毛片二级毛片| 亚洲成人免费电影| 日本高清综合网五月丁香| 五月天狠狠网站| 91久久久久久久| 五月天,激情四射,婷婷频道| 同性gv国产精品一区二区| 六月丁香婷婷综合影院| 五月网站| 天天弄天天操| 在线看片av| 五月天激情国产综合AV| 性爱五月丁香| 热婷婷久| 天天综合精品| 色五月综合激情| 成人性生活免费观看。| 色婷视频| 婷婷激情六月综合| 丁香五月婷婷俺也要去| 狠狠狠人妻| 亚洲色色色| 五月天综合激情网| 九九热精品视频| www.日日夜夜| 狠狠操天天操综合| 欧美性丁香色色五月天干干| 99精品国产在热久久婷婷| 久久99免费视屏| 色和综合网| 丁香六月五月天| 亚洲成人无码网站| 激情综合激情综合| 99热6精品| 久久开心五月婷婷| 91婷婷丁香五月亚洲| 天天视频亚洲| 性色99| 欧美超级视频97| Caoporn公开| 五月天激情日色在线| 色五月丁香六月资源站| 99视频内射三四| 人妻激情在线| 国产1区2区3区| 亚洲AV无码影院| 超碰丁香五月| 欧美婷婷综合网| 色五月激情问网站| 六月婷综合| 激情网 久久| 亚洲无码色色| 丁香五月香蕉| 五月丁香色婷婷| 日日干日日| 99视频精品| 亭亭五月丁香五月天激情| 色五月婷婷色五月| 五月天成人在线视频网站| 深爱激清网| 激情www| 思思re99视频在线观看| 五月婷婷激情综合av| 99视频在线精品| 婷婷色五月在线视频| 国产亚洲色婷婷久久99精品91| 久久五月天婷婷| 色婷久| 五月激情婷婷综合| 狠狠大香婷婷爱| 五月丁香久人妻中文| 丁香五月婷婷无码AV| 四月婷婷五月色综合| WWW,五月天| 免费精品66| 我爱va亚洲va52| 日本 @ va 免费| 色五月天电影| 色色99| 青青久在线视频免费观看| www.zbzhongsen.com| 97很鲁在线视频| 97偷拍对白视频| 婷婷五月色图| 天天肏天天插| 成人电影在线免费试看| 久久国产色| 婷婷丁香五月天激情| 日日做A爰片久久毛片A片英语| 国产真实乱对白精彩| 亚洲一二三网| 色噜噜狠狠色综| www.狠狠操.co m| 天天天天天天天操| 色丁香五月天| 日韩AV免费看| 9久久婷婷国产综合精品性色| 26uuu色噜噜精品一区| 欧美丁香五月天| 一区二区免费看| 操操国产| 五月婷婷激情五月| 停停综合色色| 人人色性网| 亚洲乱码日产精品BD| 婷婷黄色五月| 玖玖色综合| 夜夜骑福利资源| 日韩AAAAAAAAAAA片| 五月婷婷激情网| 日本三级网址| 曰本久久女| 婷婷五月香蕉| 五月丁香婷色| 99热这里全是精品| 久人人操| 狠狠狠狠操| 99热91| 壅壅儕家a| 狠狠做六月爱婷婷综合aⅴ| 色色色图| 好吊兆人妻| 色色综合色视频| 囯产精品久久欠久久久久久九大| 成人电影丁香六月天| 深爱五月天| 国产乱子轮XXX农村| 丁香婷婷婷五月综合色情| 五月丁香六月婷婷免费| 色欲婷婷五月天| 五月婷婷狠狠久久| 日日夜夜噜噜爽爽| 国产69久久久欧美黑人A片| 97在线/亚洲| 精品国产人人爱人人| 99久热在线精品| 99操逼| 99热这里都是精品| 久久草人妻| 在线观看玖玖资源免费观看| 婷婷久久草| 欧美A级成人婬片免费看理论| 六月婷婷色综合| 成人精品人妻| 五月桃花网综合| 99re这里只有精品免费| 丰满老熟妇BBBBB搡BBB| 91精品国产99久久久久久天美| 天天爽天天日天天舔| 国产精品扒开腿做爽爽爽A片唱戏| www.久久| 4399成人黄A片| 丁香五月激情婷婷视频| 欧美乱码国产一级A片| 99精色| 青青草tp| 99啪啪| 亚洲天堂久久| 狠狠干婷婷| 79亚洲精品少妇| 激情婷婷五月天| 久久久久久激情| 91色婷婷综合久久中文字幕二区| 夜色.cnm| 亚洲顶级VA在线观看-高清完整版在线影院观看-S022AV | 色,激情五月天| 亚洲中文字幕网| 激情五月天黄色小说| 狠狠操天天干| 五月天婷婷色在线视频免费观看 | 婷婷天天日婷婷| 91婷婷丁香五月| 五月丁香欧美综合| 18av天堂| 九九爱激情| 五月天激情小说欧美激情| 大香久久伊人网| 色狠久| 玖玖@三月天天丁香婷婷| 婷婷色五月天在线| 亚洲在线操| 色综合伊人网| AV网站免费在线| 天天日天天舔| 99re这里只有精品视频了| 丁香五月天社区婷婷| 另类小说色婷婷| 久久思思99| 亚洲免费婷婷| 天天插天天| 色色婷婷色色| 涩涩五月天| 97干视频| 婷婷色色欧美综合网| 婷婷丁香五月综合| 大香蕉久| 婷婷五月丁香人妻无码高清| 大香蕉久| 婷婷.com| 婷婷性爱视频在线| 婷婷五月天成人| 色欲色香伊人| 五月婷丁香花| 亚洲黄色av网站| 婷婷播5月| 丁香五月性| 九九热在线视频| 五月丁香综合网| 天堂婷婷五月在线| 香蕉伊人综合| 国产AV一区二区三区最新精品 | 公的粗大挺进了我的密道| 色婷婷五月天天天干天天操天天爽| 3p久久| 激情玖玖sh| 婷婷色av| 久久性操| 色色色色色五月| 成人免费120分钟啪啪| 天天综合网亚洲网站| 99热亚洲| 五月丁香综合激情网| 色天天综合天天综合频道。 | 婷婷综合久久| 99热超碰天堂网| 超碰免费人| 色综合五月| 六月丁香综合网| 色综合激情| 亚洲欧美日韩VIP| 久久九九网| 天天日天天插| 亚洲bt丁香五月天婷婷激情小说| 日本美女天天日天天爽| 欧美天天草人人草| 五月丁香无码| 久久香蕉婷婷| 国产欧美大香蕉一区| 性一交一乱一交A片久| 久久久激情| 丁香五月色| 一级A片天天操夜夜操| 久久久久久草黄色片AV在线观看| 精品久久9| 婷婷五月天.com| 天堂网色婷婷| 狼人伊人干| 色色色五月天婷婷| 亚洲乱码日产精品BD| 狠狠爱综合网| 国产成人+综合亚洲+天堂| 日本女天天爽| 噜噜噜噜婷婷五月天| 免费婷婷| 婷婷五月综合激情| 久久日婷婷| 超碰久热| 99热在线观看免费精品| 严洲天天插| 无码人妻一区二区三区免费九色| 无码地址| 国产一级婬片毛片| 天天草天天日| 51avj视频大全| 五月天婷婷成人| 99热这里只有精品在线观看| www.婷婷.com| 亚洲天堂99| 五月激情小说| 国产成人精品123区免费视频 | 久草大| 91精品婷婷国产综合久久| 欧美精产国品一二三区| 欧美日本VA| 都市激情蜜桃婷婷五月天| 久久6这里只有精品| 九九操综合网| 人人干av| 97色色综合| 成AV人片一区二区三区久久| 久久精品99国产精品日本| 色九四色| 婷婷五月天网址| 丁香五月综合婷婷| 秋霞学生妹一二级| 激情五月丁香综合网站| 91久久精品无码一区二区三区| 色综合色五月| 99人妻碰碰久久久禁片| se.久久视频在线观看| 粉嫩av懂色av蜜臀av熟妇| 日日日,com| 五月婷婷视频ab| 久久99大全| 操操啪| 操婷婷基地| 五月香蕉网| 噜噜干日本| 丁香五月婷婷呀| 激情五月婷婷网| 婷婷久久亚洲| 亚洲网站观看视频| 国产激情在线| 另类综合激情| 五月综合色播播丁香婷婷| 91无码高清| 在线中文亚洲| 激情婷婷五月天| 久久婷婷五月综合色天| 第四色五月婷婷| anquye伊人| 色婷婷五月天偷拍| 国产乱子轮XXX农村| 五月天婷婷久久视频| 亚洲精品第一国产综合亚AV | 人人综合五月人人婷婷| 丁香五月激情啪| 九九无码AV| 五月天激情四射| 五月天婷婷无码视频| 五月婷婷啪啪| 丁香五月色网| 丁香五月天综合网| 色婷五月| 日本91在线| 日本va欧美va欧美精品88| 高清无码网址| 婷婷伊人综合中文字幕| 雪千夏麻豆| 热久久思思热思思| 99色色| 草久私拍| 人人舔人人色人人高潮| 嫩草AV久久伊人妇女超级A| 国产日韩欧美性生活| 精品人妻久久久久久| 色级停停| 五月天婷婷爱丁香中文字幕| 五月天激情亚洲| 婷婷综合久久综合| 丁香五月天精品| 国产成人网| 9色在线| 日本欧美成人片AAAA| www.婷婷久久五月天| 五月色丁香综合| 亚洲色综合| 午夜丁香综合婷婷| 丁香成人五月天| 97色综合视频| 婷婷色成人| 丁香五月婷婷欧美性爱| 国产成人VA| 天天爽天天操| WWW色五月天| 色婷婷久久| 久久狼人天堂| 欧美综合123区| 99热在线资源| 超碰在线免费| 91操片| 99热碰碰热| 91操在线视频| 97在线精品| 在线99精品| 综合色播| 丁香五月婷婷偷拍| 新激情五月天色播| 五月天丁香婷婷视频网址| 五月丁香九九九综合| 九九九九精品精| 五月婷丁香亚洲| 免費观看aV在线网址| 这里只精品热在线18| 99爱在线| 天天插天天插| 九九色99| 99欧美| 思思热性操| 91碰碰视频在线观看| 五月激情婷婷在线| 色婷婷综合成人| 色欲婷婷五月天| 伊人网欧美在线男人天堂五月丁香 | 色五月六月| 大伊香蕉玖玖爱| 97影院一级片| 亚洲欧洲99| 搡BBBB搡BBB搡五十| 99视频精品全部免费观看| 9l视频自拍九色9l黑人| 五月欧美丁香在线观看| 97色色色| 熟妇内谢69XXXXXA片| 久久草婷婷丁香网站| 超级碰 久久9| 991国产精选视频在线播放下载| 激情五月婷婷综合| 国产午夜精品一区二区三区四区| 日韩九九| 五月天婷婷色色| 亚洲偷| 超碰人人干| 五月天合网| 玖玖@三月天天丁香婷婷| 亚洲成人无码网站| 深爱五月激情网| 69精品人人人人| 日日夜夜爽| 99狠狠色| 91蝌蚪窝视频在线| 亚洲成人网站在线播放| 美女婷婷六月色| 色色色天堂网| 天天日夜夜| 五月天天爱| 色婷婷婷av| 色婷婷五月天无码视频| 色五月婷婷五月天| 99热骚货| 亚洲一级色电影| 性爱网五月婷婷| 婷婷射丁香| 人人做人人看人人摸| 91超碰在线观看| 大香蕉在线99热| 久艹大香蕉| 五月丁香六月情婷婷久久| 人伦30P| 91狼友视频在线观看| 色播五月丁香| 色色色色网站| www.久久66| 超级碰碰碰碰视频| 碰碰碰97国产| 我爱大香蕉| 97色天堂| 五月婷视屏在线观看| 丁香五月 综合| 婷婷狠狠操| 丁香六月欧美| 色婷綜合网| 91无码高清| 91九色偷拍| 亚洲无码99| 色5月婷婷色| 亚洲视频图片婷婷五月| 逼逼AV| www色婷婷久久综合久色| 插逼综合网| 男人天堂AV在线一区二区| 午夜天堂一区人妻| 五月丁香亭亭| 五月丁香激情啪啪| 亚洲性视频| 人妻无码精品一区| 丁香五月人妻熟女| 丁香五月婷婷六月婷| 日本一级一级一级一级| 大香蕉中文| 色噜久| 99热官网精品在线| 婷婷丁香大香蕉| 婷婷丁香无码专区| 久久精品国产精品| 一本大道嫩草AV无码专区| 激情色色色| 婷婷性爱| 99热这里只有精品在线| 五月激情啪啪| 色婷婷视频在线| 亚洲色啪| 色99在线| 三级三久久线久久99久目本WW| 九九精品综合| 九九亚洲综合| 久久久99久久| 99视频精品| 九九青青草成人| 婷婷综合网站| 99A片| 亚洲婷婷五月草久| 5月婷婷五月天| 99re这里有精品手机在线| 精品九九视频| 亭亭五月天成人| 色五月丁香婷婷| 国产精品色婷婷久久久精品| 操碰99| 成人短视频在线观看| 蜜乳av一级av| 婷婷伊人视婷婷婷| 色婷视频| 99视频在线观看欧| 五月丁香婷婷深深爱| 91精品久久久久久| 五月天激情小说| 丁香五月激情综合久久| 色私五月婷婷| 欧美婷婷五月无砖| 婷婷激情小说网| 天天日天天爽| 噢美99| 91丨九色丨老熟女激情| 综合福利网| 五月丁香日逼| 青青草99热久久精品国| 五月丁香婷婷综合久久| 97婷婷丁香五月综合| 九九亚洲视频| 91丨九色丨白浆秘| 丁香五月性爱| 韩国97天堂| 日本三久久| 国产噜一噜天天噜| 夜夜操天天爽| av狠狠操| 79精品视频在线观看,| 婷婷色网| 日韩AC在线免费观看| 天天插操| 99ER热精品视频| 丝袜熟女一区二区三区| 五月丁香久久呀| 天天插综合在线| 天堂草在线观看| 99久久久久久久| 色婷婷av在线| 婷婷之六月丁香| 五月婷婷九九热| 99热精品在线在线| 久热久re| 色欲婷婷夜夜| www,色色色网站| 夜夜干天天操| JAPANRCEP老熟妇乱子伦视频 | 色哟呦av| 91碰超| 狠狠干在线视频| 五月丁香六月婷婷不卡免费无码| 九九热精品视频| 极品少妇XXXX精品少妇偷拍| 九月婷婷综合网| 2050人人操免费工开爱| 九九成人| 亚洲操女| 亚洲视频在线观看99| 99亚洲色| 色丁香五月婷婷| 日韩黄色电影| 开心五月色婷婷综合开心网| 色色色成人网| 五月丁香色婷基地综合久久| 色婷婷狠狠色| 色色无码| 成人精品人妻| 五月天伊人综合| 婷婷丁香五月天激情| 《丁香激情综合久久伊人久久》影视在线观看 -高清预告手机免费播放 -三妹影院 | AV色婷婷| 五月婷婷网五月在线| 婷婷五月花| 久久这里只有精品视频15| 婷婷五月中文在线| 操逼视频一区| 黄页免费一级视频懂色| 色婷丨日丨天丨综合久久| 色色色色综合网| 综合激情五月丁香| 99综合久久| 任你爽精品免费视频6| 丁香婷婷九月| 热99在线精品| 亚洲成人无码网站| 骚五月婷婷| www.99热在线| 色婷婷久久综| 97色久| 丁香九月久久| 久久久中文| 色婷婷电影网| 色偷偷五月天| 婷婷五月丁香五月丁香| 五月婷婷性爱| jiujiu无码五区| 大学生高潮无套内谢视频| 99er免费在线观看| 最近中文字幕大全免费版在线 | 婷婷深爱五月天在线| 国产亚洲精品久久久久苍井松| 四色 爱 婷婷 精品 亚洲 五月天| 思思热在线| 天天婷婷操| 成人 在线观看国产| 色五月婷婷婷婷| 大香蕉久久伊人网| 俺去也婷婷| 九九热av| 中文字幕按摩做爰| 婷婷丁香人妻久久在线观看| 天色色综合网| www.maotanji.com| 精品思思久久| 人与禽A片啪啪| 亚洲激情97五月天| 国产AV不卡福利| 丁香六月在线| 森林影视大全,最好看的2019年视频| 五月激情综合网婷婷| rr天天操| 欧美99热| 中文字幕 中文字幕明步| 五月丁香六月婷婷综合网缴情| 视频久久9| 久久免费精彩视频| 精品人妻久久久久久久| 婷婷六月综合基地| 五月天综合色| 国产日日操夜夜操的肉棒视频| 五月婷婷97| 九九無妻| 日日舔夜夜操| 亚洲激情婷婷| 97操在线资源| 久草五月天| 亚洲六月色婷婷| 亚洲精品又粗又大又爽A片| 91人妻视频| 日韩在线99| www.五月天| 五月婷婷色播| 五月久久噜噜| 婷婷自拍| 成功精品影院| 激情五月色婷婷| 色色色精品无码区| 六月激情综合| 日本熟妇精品99| 久久一级片| 国产超碰在线| 五月丁香六月婷婷激情视频在线观看免费| 91久久久久久久久久久| 牛色色碰| 五月香婷婷| 婷婷瑟瑟五月天| 日本a片网址| 久激情| 免费看欧美成人A片无码| 五月婷婷九九热| 久热最新视频| 色色色999| 色吊丝中文字幕| 丁香五月天社区| 色九亚洲| 婷婷五月成人系列| 综合亚洲五月天| 亚洲无码成人| 人人操91色| 亚洲免费99| 另类激情中文| 婷婷五月天久久久| 五月丁香婷婷AV天堂| 77777亚洲午夜久久| 中文字幕日本最新乱码视频| 日韩欧洲亚洲| 五月婷婷综合在线视频小说| 影音先锋女人av鲁色资源网小说免费| 日韩黄色电影| 亚洲黄色操逼| 中文字幕按摩做爰| 久久婷婷热| 五月天婷婷社区| 五月丁香无码| 六月米奇色综合| 五月丁香久人妻中文| 综合激情在线| 伊人玖玖网| 天堂在线婷婷| 思思干精品| 中文字幕日产A片在线看| 精品久热| 丁香五月激情啪| 亚洲第一综合| 热99在线| 色播激情五月天| 99色最新在线视频网站| 色五月婷婷五月久久| 婷婷5月色| www.激情在线| 色色综合色视频| 色色五月天激情| 婷婷丁香97| 亚洲不卡欧洲| 91丨熟女丨首页| 99色1| 亚洲中文无码成人| 色噜噜狠狠色综合日日| 超碰二区| 色丁香久久| 99精品久久久久久久婷婷| 婷婷操超碰| 色www.con| 91色在线| 99热久草| 啪啪一区| 日操| www.十八禁不禁AV.com| 操逼在线视频| 欧美激情-区二区三区| 丁香五月激情鲁| 精品亚洲VA网站| 婷婷免费视频| 日韩av在线免费观看| 久久久久久激情| 在线不卡视频| 99视频内射三四| 专区无日本视频高清8| 日本一级黄色片。| 欧美天堂婷婷日韩| 在线sebiav精品视频| 人妖色AV色综合| 亚洲AV无码一区二| 色婷婷五月色| 久久草人妻| 99色色最新视频| 啪到高潮激情丁香五月| 狠狠狠色激情综合适合| 中文字幕综合网| www.天天干| 91男同视频| 久99久视频精选| 开心五月婷婷婷美女| 狠狠干五月天婷婷网| 春色激情第四色| 五月天激情婷婷久久| 碰碰女| 色久综合| 激情网色五月| 97狠狠色| 亚洲综合草草| 99色视频| 综合色、色综合| 五月天丁香综合在线| 中文字幕在线日亚洲9| www.夜夜夜| se99视频| 日韩无码色色| 五月激情四射网站| 婷婷性爱视频在线| 亚洲一个色| 四色AVwww| 婷婷五月天色| 天天插操| 日本久久人人| 色婷婷五月亚洲| 超级碰碰91| 丰满少妇猛烈A片免费看观看| 综合色视频| av婷婷丁香 六月| 激情综合网五月激情| 99欧美| 91女人18毛片水多国产| 激情黄色小说色五月| 俺去也在线官网| 丁香婷婷五月六月久久| 国产婷婷色综合AV蜜臀AV | 中文资源在线a| 人妻久久久久久久久妻久久久久| 99热免费| 色欧美色色色| 青青草tp| 天天xxxxxx天天日| 99热这里是精品| 久久九九re热| 色婷婷在线综合色播网| 五月天婷婷色| 九九九激情综合| 99久久婷| 第四色婷婷丁香五月| 国产人妻人伦精品一区二区| 欧洲S级在线观看| 亚洲VA在线| 能看的av| 思思99久久| 婷婷五月激情天| 国产人妻777人伦精品HD| 最新色色五月天| 五月婷婷婷| 五月天久久婷| 婷丁五月| 六月激情婷婷| 极品九九九九九九| 午夜无码精品色综合久久| 久机视频这只有精品| 99综合熟女| 婷婷干五月综合在线播放| 办公室少妇激情呻吟A片在线观看 白人荫道BBWBBB大荫道 | 综合激情网激情五月。| 99热在线这里只有精品| 激情五月天网站| 婷婷99中文字幕| 夜夜爱网站| 另类婷婷五月天啪帕帕| www.狠狠狠.com| 99热这里只有精品55| AV网站免费在线| 天天日天天爽| 中文字幕不卡视频| 情婷婷五月天| Blackedraw视频一区二区| 色99视| 日韩色色视频| 久热九九| 欧美精品999| 97操碰视频| 五月婷婷久久大香蕉| 色五月婷婷伊人| 亚洲视频色婷婷| 伊人五月天久久| 99视频这里只有精品10| 日操夜操天天操不卡| 开心五月婷婷在线| 思思9久久| 手机AVAV天堂看网| 亚洲蜜桃精久久久久久久久久久久 | 久草大| 伊人成综合五月婷婷| 丁香五月婷婷激情蜜桃| 三日本无码| 五月天激情无码专区| 亚洲天堂AV综合网| 看久久性爱视频| 超碰免费电影| 丁香久久| 黄色激情久久| 久久综合五月| 色婷婷色五月另类综合|