1. 程式人生 > >許可權框架Shiro學習之表結構設計

許可權框架Shiro學習之表結構設計

許可權框架Shiro學習之表結構設計

Shiro是一款優秀的開源安全框架,學習Shiro大家可以參考張開濤老師的部落格:跟我學Shiro,當然也可參考我之前的筆記:Shiro實現身份認證Shiro實現授權

在學習完基礎的Shiro入門知識,我們可以動手寫一個小Demo了,這次我們將以一個使用者-角色-許可權管理的Demo來進一步學習Shiro。

起步

表設計

開發使用者-角色-許可權管理系統,首先我們需要知道使用者-角色-許可權管理系統的表結構設計。

使用者-角色-許可權管理系統找那個一般會涉及5張表,分別為:

  • 1.sys_users使用者表
  • 2.sys_roles
    角色表
  • 3.sys_permissions許可權表(或資源表)
  • 4.sys_users_roles使用者-角色關聯表
  • 5.sys_roles_permissions角色-許可權關聯表(或角色-資源關聯表)

詳細的建表資訊如下

  • sys_users

image

解釋
使用者表中至少包含以上的欄位,主鍵id、使用者名稱username、密碼password、鹽值salt(因為密碼是經過Shiro加密的,需要通過鹽值校驗,由Shiro生成,不需要使用者手動填寫)、角色列表roleId(這個欄位不是必須的,僅實現在展示使用者資訊的時候能同時展示使用者當前角色)、是否鎖定locked(決定當前賬戶是否是鎖定的)。
建立新的使用者,僅需要輸入使用者名稱和密碼即可,鹽值由Shiro生成,角色列表和是否鎖定都可以在後期管理。

其中是否鎖定欄位型別為tinyint(1),設定這種型別,資料庫中實際儲存的是int型別資料,一般是0和1,在使用Mybatis取這個欄位的資料時,Mybatis會自動將tinyint(1)欄位值為0的轉換成false,將欄位值為1以上的轉換為true。

  • sys_roles

image

解釋
角色表中role角色名稱一般為儲存著類似user:create這種格式,Shiro在Realm中校驗使用者身份的時候會通過role這個欄位值進行校驗;description是此角色的描述資訊,比如使用者建立
其中pid表示父節點,就是說,當前的角色可能有上級節點,比如老師,這個角色可能就有父節點計科教師

,如果存在父節點,這個欄位值就是父級節點的ID,根據這個ID,在展示資料的時候就很方便的展示出其在哪個父節點下。
available表示當前節點是否鎖定,同樣是tinyint(1)型別,如果為false就說明沒有鎖定。

  • sys_users_roles

image

解釋
使用者角色表就比較簡單了,僅僅包含了主鍵id、使用者IDuser_id、角色IDrole_id;這張表主要描述指定使用者與角色間的依賴關係。其中使用者表與角色表是一對多的關係,一個使用者可以擁有多個角色。

  • sys_permissions

image

解釋
許可權表和角色表類似,其中不同的欄位是rid,這個欄位表示此許可權關聯的角色的id值,當然不是必要的,但是後端角色更新時用到了,後面會介紹。

  • sys_roles_permissions

image

解釋
角色-許可權表和使用者-角色表類似,包含了主鍵id、角色IDrole_id、許可權IDpermission_id,主要描述角色和許可權間的依賴關係,同樣,角色和許可權間也是一對多的關係,一個角色會關聯多個許可權。

 

schema.sql

上述表設計的原始碼如下:

-- 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;

拓展

上面就是當前使用者-角色-許可權系統的表設計。細心的你可能會發現這些表中並不包含外來鍵約束。

為什麼不設計外來鍵呢?

可能你會跟我一樣有這樣的疑問。比如使用者表和角色表間,我們這裡建立了使用者-角色表來實現兩者的關聯;並沒有通過給兩張表建立外來鍵來實現一對多、多對多的關聯關係。
因為如果你要建立外來鍵來關聯兩張表,你需要遇到如下:

  1. 如果兩張表之間存在一對多的關係,在給的一方新增資料的時候,你要考慮的一方是否存在指定的id。
  2. 如果兩張表之間存在一對多的關係,在刪除的一方時你要先刪除其關聯的的一方,再刪除的一方。
  3. ...

也就是說如果使用了外來鍵關聯,那麼在對錶進行資料操作時就必須考慮另一張關聯的表,相當於兩張表就綁在一起了,操作這張表就必須考慮另一張關聯表。

但是實際中,我們不想立即就修改或更新關聯表的資料,我可能一會再去更新另一張關聯表的資料,那麼就產生了這種方式:通過單獨建立一張關聯來實現兩張表的資料關聯。

所以,我建議大家在設計表時儘量減少表與表直接的外來鍵約束,這樣能避免很多麻煩,並且兩張表之間的關聯關係也會格外清晰。

例項

上面建立了使用者-角色-許可權表以及其關聯表,下面就介紹一些實際的案例吧!

初始化表

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)

根據角色id查詢其許可權

[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)

更新user表中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)

根據許可權ID查詢其角色

[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)



作者:TyCoding
連結:https://www.jianshu.com/p/5c5af91cec9f
來源:簡書
簡書著作權歸作者所有,任何形式的轉載都請聯絡作者獲得授