NewLife.XCode是一個有10多年歷史的開源數據中間件,支持nfx/netcore,由新生命團隊(2002~2019)開發完成並維護至今,以下簡稱XCode。
整個系列教程會大量結合示例代碼和運行日志來進行深入分析,蘊含多年開發經驗於其中,代表作有百億級大數據實時計算項目。
開源地址:https://github.com/NewLifeX/X (求star, 864+)
前面講解了XCode的各種用法,這一章我們來講講內置的Membership,同時也是XCode的第一標准示例!
設計背景
現代管理信息系統絕大部分采用BS架構,無一例外需要用戶角色權限的支持!
結合團隊諸多兄弟姐妹的經驗,設計了一個大小適中的用戶權限系統Membership,目標是滿足80%的使用場景,並具備一定的擴展性。
Membership剛開始就采用了角色授權體系,每個用戶只有一種角色,角色擁有菜單資源權限集。
隨着Membership實用性日益增加,2015年初正式合並進入XCode,作為一個模塊存在。
2016年第二代魔方NewLife.Cube采用ASP.Net MVC5重構,讓Membership的榮譽達到了鼎峰!
在MVC中,每個Controller就是一個菜單資源,其下的Search/Detail/Insert/Update/Delete等Action作為角色在該菜單資源下的權限子項,保存在角色屬性數據中。
2018年為了增強魔方功能,在某些場景下支持單用戶多角色,且兼容已有系統,用戶表增加RoleIDs字段,保存擴展角色,原來的RoleID作為主角色。
管理提供者
管理提供者接口 IManageProvider ,提供了Membership基本操作實現。
- 當前登錄用戶 GetCurrent、SetCurrent,靜態訪問 ManageProvider.User
- 查找用戶 FindByID、FindByName
- 注冊登錄注銷 Register、Login、Logout
- 當前用戶主機(訪問者IP)ManageProvider.UserHost
- IManageProvider 默認由XCode.Membership中的UserX/Role/Menu支持,如若用戶使用自己的用戶權限表,可重新實現該接口
用戶權限
用戶 UserX
用戶數據模型:
<Table Name="User" Description="用戶" RenderGenEntity="true"> <Columns> <Column Name="ID" DataType="Int32" Identity="True" PrimaryKey="True" Description="編號" /> <Column Name="Name" DataType="String" Master="True" Nullable="False" Description="名稱。登錄用戶名" /> <Column Name="Password" DataType="String" Description="密碼" /> <Column Name="DisplayName" DataType="String" Description="昵稱" /> <Column Name="Sex" DataType="Int32" Description="性別。未知、男、女" Type="SexKinds" /> <Column Name="Mail" DataType="String" Description="郵件" /> <Column Name="Mobile" DataType="String" Description="手機" /> <Column Name="Code" DataType="String" Description="代碼。身份證、員工編號等" /> <Column Name="Avatar" DataType="String" Length="200" Description="頭像" /> <Column Name="RoleID" DataType="Int32" Description="角色。主要角色" /> <Column Name="RoleIDs" DataType="String" Length="200" Description="角色組。次要角色集合" /> <Column Name="DepartmentID" DataType="Int32" Description="部門。組織機構" /> <Column Name="Online" DataType="Boolean" Description="在線" /> <Column Name="Enable" DataType="Boolean" Description="啟用" /> <Column Name="Logins" DataType="Int32" Description="登錄次數" /> <Column Name="LastLogin" DataType="DateTime" Description="最后登錄" /> <Column Name="LastLoginIP" DataType="String" Description="最后登錄IP" /> <Column Name="RegisterTime" DataType="DateTime" Description="注冊時間" /> <Column Name="RegisterIP" DataType="String" Description="注冊IP" /> <Column Name="Ex1" DataType="Int32" Description="擴展1" /> <Column Name="Ex2" DataType="Int32" Description="擴展2" /> <Column Name="Ex3" DataType="Double" Description="擴展3" /> <Column Name="Ex4" DataType="String" Description="擴展4" /> <Column Name="Ex5" DataType="String" Description="擴展5" /> <Column Name="Ex6" DataType="String" Description="擴展6" /> <Column Name="UpdateUser" DataType="String" Description="更新用戶" /> <Column Name="UpdateUserID" DataType="Int32" Description="更新用戶" /> <Column Name="UpdateIP" DataType="String" Description="更新地址" /> <Column Name="UpdateTime" DataType="DateTime" Nullable="False" Description="更新時間" /> <Column Name="Remark" DataType="String" Length="200" Description="備注" /> </Columns> <Indexes> <Index Columns="Name" Unique="True" /> <Index Columns="RoleID" /> <Index Columns="UpdateTime" /> </Indexes> </Table>
常用字段有ID、用戶名和密碼,登錄注冊相關信息;
角色RoleID、RoleIDs用於實現權限集控制;
部分場景需要郵箱Mail、手機Mobile或者工號Code登錄;
如果仍然不能滿足要求,可以考慮使用Ex1~Ex6等擴展字段。
常用功能點:
- 初始化時,如果數據表為空,自動插入admin/admin用戶賬號,角色是“管理員”
- 支持注冊登錄,使用MD5保存密碼
- 支持編號查詢FindByID和名稱查詢FindByName,分別采用了對象緩存和對象從鍵,輕松實現百萬級賬號快速查詢
- 支持IIdentity接口
角色 Role
角色數據模型:
<Table Name="Role" Description="角色" RenderGenEntity="true"> <Columns> <Column Name="ID" DataType="Int32" Identity="True" PrimaryKey="True" Description="編號" /> <Column Name="Name" DataType="String" Master="True" Nullable="False" Description="名稱" /> <Column Name="Enable" DataType="Boolean" Description="啟用" /> <Column Name="IsSystem" DataType="Boolean" Description="系統。用於業務系統開發使用,不受數據權限約束,禁止修改名稱或刪除" /> <Column Name="Permission" DataType="String" Length="500" Description="權限。對不同資源的權限,逗號分隔,每個資源的權限子項豎線分隔" /> <Column Name="Ex1" DataType="Int32" Description="擴展1" /> <Column Name="Ex2" DataType="Int32" Description="擴展2" /> <Column Name="Ex3" DataType="Double" Description="擴展3" /> <Column Name="Ex4" DataType="String" Description="擴展4" /> <Column Name="Ex5" DataType="String" Description="擴展5" /> <Column Name="Ex6" DataType="String" Description="擴展6" /> <Column Name="CreateUser" DataType="String" Description="創建用戶" /> <Column Name="CreateUserID" DataType="Int32" Description="創建用戶" /> <Column Name="CreateIP" DataType="String" Description="創建地址" /> <Column Name="CreateTime" DataType="DateTime" Nullable="False" Description="創建時間" /> <Column Name="UpdateUser" DataType="String" Description="更新用戶" /> <Column Name="UpdateUserID" DataType="Int32" Description="更新用戶" /> <Column Name="UpdateIP" DataType="String" Description="更新地址" /> <Column Name="UpdateTime" DataType="DateTime" Nullable="False" Description="更新時間" /> <Column Name="Remark" DataType="String" Length="200" Description="備注" /> </Columns> <Indexes> <Index Columns="Name" Unique="True" /> </Indexes> </Table>
角色表比較簡單主要是名稱和啟用,以及保存菜單權限數據的Permission
角色支持的操作權限:
/// <summary>操作權限</summary> [Flags] [Description("操作權限")] public enum PermissionFlags { /// <summary>無權限</summary> [Description("無權限")] None = 0, /// <summary>查看權限</summary> [Description("查看")] Detail = 1, /// <summary>添加權限</summary> [Description("添加")] Insert = 2, /// <summary>修改權限</summary> [Description("修改")] Update = 4, /// <summary>刪除權限</summary> [Description("刪除")] Delete = 8, /// <summary>所有權限</summary> [Description("所有")] All = 0xFF, }
主要功能點:
- 數據表為空時初始化4個基本角色:管理員、高級用戶、普通用戶、游客
- 啟動時角色權限校驗,清理角色中無效的權限項(可能菜單已刪除),以及授權管理員訪問所有角色都無權訪問的新菜單
- 支持編號查詢FindByID和名稱查詢FindByID,采用實體緩存,目標系統不會超過1000個角色
- 支持權限判斷與設置 Has/Get/Set/Reset 等
- 重載實體類 Delete/Save/Update/OnLoad/OnPropertyChanged,加載實體對象時展開權限,保存時合並
菜單 Menu
菜單數據模型:
<Table Name="Menu" Description="菜單" BaseType="EntityTree" RenderGenEntity="true"> <Columns> <Column Name="ID" DataType="Int32" Identity="True" PrimaryKey="True" Description="編號" /> <Column Name="Name" DataType="String" Master="True" Nullable="False" Description="名稱" /> <Column Name="DisplayName" DataType="String" Description="顯示名" /> <Column Name="FullName" DataType="String" Length="200" Description="全名" /> <Column Name="ParentID" DataType="Int32" Description="父編號" /> <Column Name="Url" DataType="String" Length="200" Description="鏈接" /> <Column Name="Sort" DataType="Int32" Description="排序" /> <Column Name="Icon" DataType="String" Description="圖標" /> <Column Name="Visible" DataType="Boolean" Description="可見" /> <Column Name="Necessary" DataType="Boolean" Description="必要。必要的菜單,必須至少有角色擁有這些權限,如果沒有則自動授權給系統角色" /> <Column Name="Permission" DataType="String" Length="200" Description="權限子項。逗號分隔,每個權限子項名值豎線分隔" /> <Column Name="Ex1" DataType="Int32" Description="擴展1" /> <Column Name="Ex2" DataType="Int32" Description="擴展2" /> <Column Name="Ex3" DataType="Double" Description="擴展3" /> <Column Name="Ex4" DataType="String" Description="擴展4" /> <Column Name="Ex5" DataType="String" Description="擴展5" /> <Column Name="Ex6" DataType="String" Description="擴展6" /> <Column Name="CreateUser" DataType="String" Description="創建用戶" /> <Column Name="CreateUserID" DataType="Int32" Description="創建用戶" /> <Column Name="CreateIP" DataType="String" Description="創建地址" /> <Column Name="CreateTime" DataType="DateTime" Nullable="False" Description="創建時間" /> <Column Name="UpdateUser" DataType="String" Description="更新用戶" /> <Column Name="UpdateUserID" DataType="Int32" Description="更新用戶" /> <Column Name="UpdateIP" DataType="String" Description="更新地址" /> <Column Name="UpdateTime" DataType="DateTime" Nullable="False" Description="更新時間" /> <Column Name="Remark" DataType="String" Length="200" Description="備注" /> </Columns> <Indexes> <Index Columns="Name" /> <Index Columns="ParentID,Name" Unique="True" /> </Indexes> </Table>
菜單實體類采用樹形實體基類 EntityTree ,通過 ParentID 實現上下級關聯,同級 ParentID+Name 唯一
主要功能點:
- 支持自動掃描Controller作為菜單,因此魔方只需要增加Controller,即可在菜單表看到新頁面
- 實體樹適用於1000行以內樹形數據表,一次性加載數據到內存,在內存中根據ParentID構造實體對象樹,最常用樹形是Parent/Childs
日志統計
日志 Log
數據模型:
<Table Name="Log" Description="日志" ConnName="Log" RenderGenEntity="true"> <Columns> <Column Name="ID" DataType="Int32" Identity="True" PrimaryKey="True" Description="編號" /> <Column Name="Category" DataType="String" Description="類別" /> <Column Name="Action" DataType="String" Description="操作" /> <Column Name="LinkID" DataType="Int32" Description="鏈接" /> <Column Name="UserName" DataType="String" Description="用戶名" /> <Column Name="Ex1" DataType="Int32" Description="擴展1" /> <Column Name="Ex2" DataType="Int32" Description="擴展2" /> <Column Name="Ex3" DataType="Double" Description="擴展3" /> <Column Name="Ex4" DataType="String" Description="擴展4" /> <Column Name="Ex5" DataType="String" Description="擴展5" /> <Column Name="Ex6" DataType="String" Description="擴展6" /> <Column Name="CreateUser" DataType="String" Description="創建用戶" /> <Column Name="CreateUserID" DataType="Int32" Description="用戶編號" /> <Column Name="CreateIP" DataType="String" Description="IP地址" /> <Column Name="CreateTime" DataType="DateTime" Nullable="False" Description="時間" /> <Column Name="Remark" DataType="String" Length="500" Description="詳細信息" /> </Columns> <Indexes> <Index Columns="Category" /> <Index Columns="CreateUserID" /> <Index Columns="CreateTime" /> </Indexes> </Table>
日志表記錄分類、操作和日志內容。
主要功能點:
- 日志提供者LogProvider,提供了唯一核心方法 WriteLog,默認實現就是寫該日志表。可從對象容器取得日志提供者 ObjectContainer.Resolve<LogProvider>()
- 從IManageProvider接口獲取當前登錄用戶以及遠程訪問IP寫入日志相應字段
在線 UserOnline
數據模型:
<Table Name="UserOnline" Description="用戶在線" ConnName="Log"> <Columns> <Column Name="ID" DataType="Int32" Identity="True" PrimaryKey="True" Description="編號" /> <Column Name="UserID" DataType="Int32" Description="用戶" /> <Column Name="Name" DataType="String" Master="True" Description="名稱" /> <Column Name="SessionID" DataType="String" Description="會話。Web的SessionID或Server的會話編號" /> <Column Name="Times" DataType="Int32" Description="次數" /> <Column Name="Page" DataType="String" Description="頁面" /> <Column Name="Status" DataType="String" Length="200" Description="狀態" /> <Column Name="OnlineTime" DataType="Int32" Description="在線時間。本次在線總時間,秒" /> <Column Name="CreateIP" DataType="String" Description="創建地址" /> <Column Name="CreateTime" DataType="DateTime" Nullable="False" Description="創建時間" /> <Column Name="UpdateTime" DataType="DateTime" Nullable="False" Description="修改時間" /> </Columns> <Indexes> <Index Columns="UserID" /> <Index Columns="SessionID" /> <Index Columns="CreateTime" /> </Indexes> </Table>
借助用戶行為模塊 UserBehaviorModule , 維護用戶在線記錄,持久化在 UserOnline 表
訪問統計 VisitStat
<Table Name="VisitStat" Description="訪問統計" ConnName="Log"> <Columns> <Column Name="ID" DataType="Int32" Identity="True" PrimaryKey="True" Description="編號" /> <Column Name="Level" DataType="Int32" Description="層級" Type="XCode.Statistics.StatLevels" /> <Column Name="Time" DataType="DateTime" Description="時間" /> <Column Name="Page" DataType="String" Nullable="False" Description="頁面" /> <Column Name="Title" DataType="String" Master="True" Description="標題" /> <Column Name="Times" DataType="Int32" Description="次數" /> <Column Name="Users" DataType="Int32" Description="用戶" /> <Column Name="IPs" DataType="Int32" Description="IP" /> <Column Name="Error" DataType="Int32" Description="錯誤" /> <Column Name="Cost" DataType="Int32" Description="耗時。毫秒" /> <Column Name="MaxCost" DataType="Int32" Description="最大耗時。毫秒" /> <Column Name="CreateTime" DataType="DateTime" Nullable="False" Description="創建時間" /> <Column Name="UpdateTime" DataType="DateTime" Nullable="False" Description="更新時間" /> <Column Name="Remark" DataType="String" Length="5000" Description="詳細信息" /> </Columns> <Indexes> <Index Columns="Page,Level,Time" Unique="True" /> <Index Columns="Level,Time" /> </Indexes> </Table>
借助用戶行為模塊 UserBehaviorModule , 維護用戶訪問記錄,寫入日志表,並寫入訪問統計表。
主要功能要點:
- 記錄頁面訪問統計,簡單支持IP數和用戶數
- 支持年月日三級統計,作為XCode日期統計表的標准示例
其它
部門 Department
數據模型:
<Table Name="Department" Description="部門。組織機構,多級樹狀結構" BaseType="EntityTree" RenderGenEntity="true"> <Columns> <Column Name="ID" DataType="Int32" Identity="True" PrimaryKey="True" Description="編號" /> <Column Name="Code" DataType="String" Description="代碼" /> <Column Name="Name" DataType="String" Master="True" Nullable="False" Description="名稱" /> <Column Name="FullName" DataType="String" Length="200" Description="全名" /> <Column Name="ParentID" DataType="Int32" Description="父級" /> <Column Name="Level" DataType="Int32" Description="層級。樹狀結構的層級" /> <Column Name="Sort" DataType="Int32" Description="排序。同級內排序" /> <Column Name="Enable" DataType="Boolean" Description="啟用" /> <Column Name="Visible" DataType="Boolean" Description="可見" /> <Column Name="Ex1" DataType="Int32" Description="擴展1" /> <Column Name="Ex2" DataType="Int32" Description="擴展2" /> <Column Name="Ex3" DataType="Double" Description="擴展3" /> <Column Name="Ex4" DataType="String" Description="擴展4" /> <Column Name="Ex5" DataType="String" Description="擴展5" /> <Column Name="Ex6" DataType="String" Description="擴展6" /> <Column Name="CreateUser" DataType="String" Description="創建用戶" /> <Column Name="CreateUserID" DataType="Int32" Description="創建用戶" /> <Column Name="CreateIP" DataType="String" Description="創建地址" /> <Column Name="CreateTime" DataType="DateTime" Nullable="False" Description="創建時間" /> <Column Name="UpdateUser" DataType="String" Description="更新用戶" /> <Column Name="UpdateUserID" DataType="Int32" Description="更新用戶" /> <Column Name="UpdateIP" DataType="String" Description="更新地址" /> <Column Name="UpdateTime" DataType="DateTime" Nullable="False" Description="更新時間" /> <Column Name="Remark" DataType="String" Length="200" Description="備注" /> </Columns> <Indexes> <Index Columns="Name" /> <Index Columns="ParentID,Name" Unique="True" /> <Index Columns="Code" /> <Index Columns="UpdateTime" /> </Indexes> </Table>
字典參數 Parameter
數據模型:
<Table Name="Parameter" Description="字典參數"> <Columns> <Column Name="ID" DataType="Int32" Identity="True" PrimaryKey="True" Description="編號" /> <Column Name="Category" DataType="String" Description="類別" /> <Column Name="Name" DataType="String" Master="True" Description="名稱" /> <Column Name="Value" DataType="String" Length="200" Description="數值" /> <Column Name="LongValue" DataType="String" Length="2000" Description="長數值" /> <Column Name="Kind" DataType="Int32" Description="種類。0普通,21列表,22名值" Type="XCode.Membership.ParameterKinds" /> <Column Name="Enable" DataType="Boolean" Description="啟用" /> <Column Name="Ex1" DataType="Int32" Description="擴展1" /> <Column Name="Ex2" DataType="Int32" Description="擴展2" /> <Column Name="Ex3" DataType="Double" Description="擴展3" /> <Column Name="Ex4" DataType="String" Description="擴展4" /> <Column Name="Ex5" DataType="String" Description="擴展5" /> <Column Name="Ex6" DataType="String" Description="擴展6" /> <Column Name="CreateUser" DataType="String" Description="創建用戶" /> <Column Name="CreateUserID" DataType="Int32" Description="創建用戶" /> <Column Name="CreateIP" DataType="String" Description="創建地址" /> <Column Name="CreateTime" DataType="DateTime" Nullable="False" Description="創建時間" /> <Column Name="UpdateUser" DataType="String" Description="更新用戶" /> <Column Name="UpdateUserID" DataType="Int32" Description="更新用戶" /> <Column Name="UpdateIP" DataType="String" Description="更新地址" /> <Column Name="UpdateTime" DataType="DateTime" Nullable="False" Description="更新時間" /> <Column Name="Remark" DataType="String" Length="200" Description="備注" /> </Columns> <Indexes> <Index Columns="Category,Name" Unique="True" /> <Index Columns="Name" /> <Index Columns="UpdateTime" /> </Indexes> </Table>
系列教程
NewLife.XCode教程系列[2019版]
- 增刪改查入門。快速展現用法,代碼配置連接字符串
- 數據模型文件。建立表格字段和索引,名字以及數據類型規范,推薦字段(時間,用戶,IP)
- 實體類詳解。數據類業務類,泛型基類,接口
- 功能設置。連接字符串,調試開關,SQL日志,慢日志,參數化,執行超時。代碼與配置文件設置,連接字符串局部設置
- 反向工程。自動建立數據庫數據表
- 數據初始化。InitData寫入初始化數據
- 高級增刪改。重載攔截,自增字段,Valid驗證,實體模型(時間,用戶,IP)
- 臟數據。如何產生,怎么利用
- 增量累加。高並發統計
- 事務處理。單表和多表,不同連接,多種寫法
- 擴展屬性。多表關聯,Map映射
- 高級查詢。復雜條件,分頁,自定義擴展FieldItem,查總記錄數,查匯總統計
- 數據層緩存。Sql緩存,更新機制
- 實體緩存。全表整理緩存,更新機制
- 對象緩存。字典緩存,適用用戶等數據較多場景。
- 百億級性能。字段精煉,索引完備,合理查詢,充分利用緩存
- 實體工廠。元數據,通用處理程序
- 角色權限。Membership
- 導入導出。Xml,Json,二進制,網絡或文件
- 分表分庫。常見拆分邏輯
- 高級統計。聚合統計,分組統計
- 批量寫入。批量插入,批量Upsert,異步保存
- 實體隊列。寫入級緩存,提升性能。
- 備份同步。備份數據,恢復數據,同步數據
- 數據服務。提供RPC接口服務,遠程執行查詢,例如SQLite網絡版
- 大數據分析。ETL抽取,調度計算處理,結果持久化