權限框架Shiro學習之表結構設計mysql
Shiro是一款優秀的開源安全框架,學習Shiro你們能夠參考張開濤老師的博客:跟我學Shiro,固然也可參考我以前的筆記:Shiro實現身份認證、Shiro實現受權。git
在學習完基礎的Shiro入門知識,咱們能夠動手寫一個小Demo了,此次咱們將以一個用戶-角色-權限管理的Demo來進一步學習Shiro。github
<!--more-->sql
開發用戶-角色-權限管理系統,首先咱們須要知道用戶-角色-權限
管理系統的表結構設計。數據庫
在用戶-角色-權限
管理系統找那個通常會涉及5張表,分別爲:後端
sys_users
用戶表sys_roles
角色表sys_permissions
權限表(或資源表)sys_users_roles
用戶-角色關聯表sys_roles_permissions
角色-權限關聯表(或角色-資源關聯表)詳細的建表信息以下安全
sys_users
解釋 用戶表中至少包含以上的字段,主鍵id、用戶名username、密碼password、鹽值salt(由於密碼是通過Shiro加密的,須要經過鹽值校驗,由Shiro生成,不須要用戶手動填寫)、角色列表roleId(這個字段不是必須的,僅實如今展現用戶信息的時候能同時展現用戶當前角色)、是否鎖定locked(決定當前帳戶是不是鎖定的)。 建立新的用戶,僅須要輸入用戶名和密碼便可,鹽值由Shiro生成,角色列表和是否鎖定均可以在後期管理。框架
其中是否鎖定字段類型爲tinyint(1)
,設置這種類型,數據庫中實際存儲的是int類型數據,通常是0和1,在使用Mybatis取這個字段的數據時,Mybatis會自動將tinyint(1)
字段值爲0的轉換成false,將字段值爲1以上的轉換爲true。學習
sys_roles
解釋 角色表中role角色名稱通常爲存儲着相似user:create
這種格式,Shiro在Realm中校驗用戶身份的時候會經過role
這個字段值進行校驗;description
是此角色的描述信息,好比用戶建立
。 其中pid
表示父節點,就是說,當前的角色可能有上級節點,好比老師
,這個角色可能就有父節點計科教師
,若是存在父節點,這個字段值就是父級節點的ID,根據這個ID,在展現數據的時候就很方便的展現出其在哪一個父節點下。 available
表示當前節點是否鎖定,一樣是tinyint(1)
類型,若是爲false就說明沒有鎖定。this
sys_users_roles
解釋 用戶角色表就比較簡單了,僅僅包含了主鍵id
、用戶IDuser_id
、角色IDrole_id
;這張表主要描述指定用戶與角色間的依賴關係。其中用戶表與角色表是一對多的關係,一個用戶能夠擁有多個角色。
sys_permissions
解釋 權限表和角色表相似,其中不一樣的字段是rid
,這個字段表示此權限關聯的角色的id值,固然不是必要的,可是後端角色更新時用到了,後面會介紹。
sys_roles_permissions
解釋 角色-權限表和用戶-角色表相似,包含了主鍵id
、角色IDrole_id
、權限IDpermission_id
,主要描述角色和權限間的依賴關係,一樣,角色和權限間也是一對多的關係,一個角色會關聯多個權限。
<br/>
上述表設計的源碼以下:
-- create database shiro default character set utf8; drop table if exists sys_users; drop table if exists sys_roles; drop table if exists sys_permissions; drop table if exists sys_users_roles; drop table if exists sys_roles_permissions; create table sys_users ( id bigint auto_increment comment '編號', username varchar(100) comment '用戶名', password varchar(100) comment '密碼', salt varchar(100) comment '鹽值', role_id varchar(50) comment '角色列表', locked bool default false comment '是否鎖定', constraint pk_sys_users primary key(id) ) charset=utf8 ENGINE=InnoDB; create unique index idx_sys_users_username on sys_users(username); create table sys_roles ( id bigint auto_increment comment '角色編號', role varchar(100) comment '角色名稱', description varchar(100) comment '角色描述', pid bigint comment '父節點', available bool default false comment '是否鎖定', constraint pk_sys_roles primary key(id) ) charset=utf8 ENGINE=InnoDB; create unique index idx_sys_roles_role on sys_roles(role); create table sys_permissions ( id bigint auto_increment comment '編號', permission varchar(100) comment '權限編號', description varchar(100) comment '權限描述', rid bigint comment '此權限關聯角色的id', available bool default false comment '是否鎖定', constraint pk_sys_permissions primary key(id) ) charset=utf8 ENGINE=InnoDB; create unique index idx_sys_permissions_permission on sys_permissions(permission); create table sys_users_roles ( id bigint auto_increment comment '編號', user_id bigint comment '用戶編號', role_id bigint comment '角色編號', constraint pk_sys_users_roles primary key(id) ) charset=utf8 ENGINE=InnoDB; create table sys_roles_permissions ( id bigint auto_increment comment '編號', role_id bigint comment '角色編號', permission_id bigint comment '權限編號', constraint pk_sys_roles_permissions primary key(id) ) charset=utf8 ENGINE=InnoDB;
上面就是當前用戶-角色-權限
系統的表設計。細心的你可能會發現這些表中並不包含外鍵約束。
爲何不設計外鍵呢?
可能你會跟我同樣有這樣的疑問。好比用戶表和角色表間,咱們這裏建立了用戶-角色表來實現二者的關聯;並無經過給兩張表創建外鍵來實現一對多、多對多的關聯關係。 由於若是你要創建外鍵來關聯兩張表,你須要遇到以下:
一
的一方新增數據的時候,你要考慮多
的一方是否存在指定的id。多
的一方時你要先刪除其關聯的一
的一方,再刪除多
的一方。也就是說若是使用了外鍵關聯,那麼在對錶進行數據操做時就必須考慮另外一張關聯的表,至關於兩張表就綁在一塊兒了,操做這張表就必須考慮另外一張關聯表。
可是實際中,咱們不想當即就修改或更新關聯表的數據,我可能一會再去更新另外一張關聯表的數據,那麼就產生了這種方式:經過單獨創建一張關聯來實現兩張表的數據關聯。
因此,我建議你們在設計表時儘可能減小表與表直接的外鍵約束,這樣能避免不少麻煩,而且兩張表之間的關聯關係也會格外清晰。
上面建立了用戶-角色-權限表以及其關聯表,下面就介紹一些實際的案例吧!
insert into sys_users values(1,'TyCoding','123','salt','管理員',0); insert into sys_roles values(21,'user:create','用戶建立',0,0); insert into sys_permissions values(31,'user:create','用戶建立',0,0); insert into sys_users_roles values(1,1,21); insert into sys_roles_permissions values(1,21,31);
[mysql> SELECT r.id, r.role, r.description FROM sys_users u, sys_roles r, sys_users_roles ur WHERE u.username = 'TyCoding' AND u.id = ur.user_id AND r.id = ur.role_id; +----+-------+-------------+ | id | role | description | +----+-------+-------------+ | 21 | admin | 管理員 | +----+-------+-------------+ 1 row in set (0.00 sec)
從上面的SQL中足以看出,經過關聯表查詢另外一張關聯的數據要點在於WHERE條件中添加關聯表與兩張表的關係,在這裏便是關聯表中存在兩張表的主鍵id,因此把相同的字段加入WHERE條件過濾就能查詢到了。
[mysql> SELECT p.id, p.permission, p.description FROM sys_users u, sys_roles r, sys_users_roles ur, sys_permissions p, sys_roles_permissions rp WHERE u.username = 'TyCoding' AND u.id = ur.user_id AND r.id = ur.role_id AND r.id = rp.role_id AND p.id = rp.permission_id; +----+-------------+--------------+ | id | permission | description | +----+-------------+--------------+ | 31 | user:create | 用戶建立 | +----+-------------+--------------+ 1 row in set (0.00 sec)
[mysql> SELECT p.id, p.description FROM sys_permissions p, sys_roles r, sys_roles_permissions rp WHERE r.id = 21 AND rp.role_id = r.id AND rp.permission_id = p.id; +----+--------------+ | id | description | +----+--------------+ | 31 | 用戶建立 | +----+--------------+ 1 row in set (0.00 sec)
role_id
字段咱們設計的sys_users
表中,存在一個字段role_id
,目的是用來展現當前用戶關聯的角色名稱,可是咱們直接更新sys_roles
表的description
字段時,又不會更新sys_users
表中的role_id
字段。
因此,這裏咱們要經過更新的角色數據來更新sys_users
表中的role_id
字段。
[mysql> UPDATE sys_users u, sys_users_roles ur SET u.role_id = '管理員-更新' WHERE ur.role_id = 21 AND u.id = ur.user_id; Query OK, 1 row affected (0.01 sec) Rows matched: 1 Changed: 1 Warnings: 0 mysql> SELECT * FROM sys_users; +----+----------+----------+------+------------------+--------+ | id | username | password | salt | role_id | locked | +----+----------+----------+------+------------------+--------+ | 1 | TyCoding | 123 | salt | 管理員-更新 | 0 | +----+----------+----------+------+------------------+--------+ 1 row in set (0.00 sec)
[mysql> SELECT r.id, r.description, r.pid FROM sys_permissions p, sys_roles r, sys_roles_permissions rp WHERE p.id = 31 AND p.id = rp.permission_id AND r.id = rp.role_id; +----+-------------+------+ | id | description | pid | +----+-------------+------+ | 21 | 管理員 | 0 | +----+-------------+------+ 1 row in set (0.00 sec)
<br/>
若是你們有興趣,歡迎你們加入個人Java交流羣:671017003 ,一塊兒交流學習Java技術。博主目前一直在自學JAVA中,技術有限,若是能夠,會盡力給你們提供一些幫助,或是一些學習方法,固然羣裏的大佬都會積極給新手答疑的。因此,別猶豫,快來加入咱們吧!
<br/>
If you have some questions after you see this article, you can contact me or you can find some info by clicking these links.