3.身份認證
在認證、授權内部實作機制中都有提到,最終處理都将交給Real進行處理。因為在Shiro中,最終是通過Realm來擷取應用程式中的使用者、角色及權限資訊的。通常情況下,在Realm中會直接從我們的資料源中擷取Shiro需要的驗證資訊。可以說,Realm是專用于安全架構的DAO.
認證實作
Shiro
的認證過程最終會交由
Realm
執行,這時會調用
Realm
的
getAuthenticationInfo(token)
方法。
該方法主要執行以下操作:
1、檢查送出的進行認證的令牌資訊
2、根據令牌資訊從資料源(通常為資料庫)中擷取使用者資訊
3、對使用者資訊進行比對驗證。
4、驗證通過将傳回一個封裝了使用者資訊的
AuthenticationInfo
執行個體。
5、驗證失敗則抛出
AuthenticationException
異常資訊。
而在我們的應用程式中要做的就是自定義一個
Realm
類,繼承
AuthorizingRealm
抽象類,重載
doGetAuthenticationInfo ()
,重寫擷取使用者資訊的方法。
既然需要進行身份權限控制,那麼少不了建立使用者實體類,權限實體類。
在權限管理系統中,有這麼幾個角色很重要,這個要是不清楚的話,那麼就很難了解,我們為什麼這麼編碼了。
第一是
使用者表
:在使用者表中儲存了使用者的基本資訊,賬号、密碼、姓名,性别等;
第二是:
權限表(資源+控制權限)
:這個表中主要是儲存了使用者的URL位址,權限資訊;
第三就是
角色表
:在這個表重要儲存了系統存在的角色;
第四就是
關聯表
:使用者-角色管理表(使用者在系統中都有什麼角色,比如admin,vip等),
第五就是
角色-權限關聯表
(每個角色都有什麼權限可以進行操作)。依據這個理論,我們進行來進行編碼,很明顯的我們第一步就是要進行實體類的建立。在這裡我們使用Mysql和JPA進行操作資料庫。
引入mysql和JPA的依賴。JPA版本(Mar 03, 2017),mysql版本預設,可以自己選擇版本
<!-- Spirng data JPA依賴; -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
<version>1.5.2.RELEASE</version>
</dependency>
<!-- mysql驅動; -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
application.yml配置mysql資料庫和JPA
spring:
datasource:
url: jdbc:mysql://localhost:3306/資料庫名稱
username: mysql的登入帳号
password: mysql的登入密碼
driver-class-name: com.mysql.jdbc.Driver
jpa:
database: mysql
show-sql: true
hibernate:
ddl-auto: update
naming:
strategy: org.hibernate.cfg.DefaultComponentSafeNamingStrategy
properties:
hibernate:
dialect: org.hibernate.dialect.MySQL5Dialect
JPA強大之處在于可以自動建表,隻要在實體類中用好注解
UserInfo
、
SysRole
SysPermission
至于之前的關聯表我們使用JPA進行自動生成。
UserInfo使用者資訊實體類
@Entity
聲明為實體類
@Id``@GeneratedValue
說Id是個自增主鍵,映射到你這個類中的Integer uid
@Column(unique =true)
是指username這個字段的值在這張表裡不能重複,所有記錄值都要唯一,就像主鍵那樣
@ManyToMany(fetch=FetchType.EAGER)
不寫預設為
LAZY
如果是
EAGER
,那麼表示取出這條資料時,它關聯的資料也同時取出放入記憶體中.
LAZY
,那麼取出這條資料時,它關聯的資料并不取出來
表關聯
@JoinTable
name
屬性為連接配接兩個表的表名稱。若不指定,則使用預設的表名稱,格式:
"表名1" + "_" + "表名2"
(JPA會為我們建立這個表)
joinColumn
屬性表示,在儲存關系的表中,所儲存關聯關系的外鍵的字段,并配合
@JoinColumn
标記使用;
inverseJoinColumn
屬性與
joinColumn
類似,它儲存的是儲存關系的另外一個外鍵字段;
@Entity
public class UserInfo implements Serializable{
@Id@GeneratedValue
private Integer uid;
@Column(unique =true)
private String username;//帳号
private String name;//名稱(昵稱或者真實姓名,不同系統不同定義)
private String password; //密碼;
private String salt;//加密密碼的鹽
private byte state;//使用者狀态,0:建立未認證(比如沒有激活,沒有輸入驗證碼等等)--等待驗證的使用者 , 1:正常狀态,2:使用者被鎖定.
@ManyToMany(fetch=FetchType.EAGER)//立即從資料庫中進行加載資料;
@JoinTable(name = "SysUserRole", joinColumns = { @JoinColumn(name = "uid") }, inverseJoinColumns ={@JoinColumn(name = "roleId") })
private List<SysRole> roleList;// 一個使用者具有多個角色
set和get方法....
/**
* 密碼鹽.
* @return
*/
public String getCredentialsSalt(){
return this.username+this.salt;
}
//重新對鹽重新進行了定義,使用者名+salt,這樣就更加不容易被破解
}
SysRole
系統角色實體類
@Entity
public class SysRole {
@Id@GeneratedValue
private Integer id; // 編号
private String role; // 角色辨別程式中判斷使用,如"admin",這個是唯一的:
private String description; // 角色描述,UI界面顯示使用
private Boolean available = Boolean.FALSE; // 是否可用,如果不可用将不會添加給使用者
//角色 -- 權限關系:多對多關系;
@ManyToMany(fetch=FetchType.EAGER)
@JoinTable(name="SysRolePermission",joinColumns={@JoinColumn(name="roleId")},inverseJoinColumns={@JoinColumn(name="permissionId")})
private List<SysPermission> permissions;
// 使用者 - 角色關系定義;
@ManyToMany
@JoinTable(name="SysUserRole",joinColumns={@JoinColumn(name="roleId")},inverseJoinColumns={@JoinColumn(name="uid")})
private List<UserInfo> userInfos;// 一個角色對應多個使用者
set和get方法....
}
SysPermission
權限實體類
@Column(columnDefinition="enum('menu','button')")``columnDefinition
屬性表示建立表時,該字段建立的SQL語句,一般用于通過Entity生成表定義時使用。
例如
columnDefinition
屬性的特殊使用:
程式設計語言中字元串一般都用
String
表示,但是資料庫中
varcahr
數值類型有長度限制,一旦需要大文本,則需要
text
數值類型
但是String類型預設映射的數值類型是
varchar
,
columnDefinition
可以進行額外指定
@Column(name = "Remark",columnDefinition="text") private String remark;
這裡枚舉類型enum,resourceType隻能是menu或者button,其他都不行
@Column(columnDefinition="enum('menu','button')")
private String resourceType;
具體的
SysPermission
實體類
@Entity
public class SysPermission implements Serializable{
@Id@GeneratedValue
private Integer id;//主鍵.
private String name;//名稱.
@Column(columnDefinition="enum('menu','button')")
private String resourceType;//資源類型,[menu|button]
private String url;//資源路徑.
private String permission; //權限字元串,menu例子:role:*,button例子:role:create,role:update,role:delete,role:view
private Long parentId; //父編号
private String parentIds; //父編号清單
private Boolean available = Boolean.FALSE;
@ManyToMany
@JoinTable(name="SysRolePermission",joinColumns={@JoinColumn(name="permissionId")},inverseJoinColumns={@JoinColumn(name="roleId")})
private List<SysRole> roles;
set和get方法....
}
到這裡實體類就編碼完畢了,在這裡我們看到的是3個實體類:
UserInfo
,
SysRole
SysPermission
對應的是資料庫的五張表:
表
UserInfo
SysUserRole
SysRole
SysRolePermission
SysPermission
(隻需要跑一下程式就會開始建立表)
建立完表之後要輸入下資料
INSERT INTO `sys_permission` VALUES ('1', '�', '使用者管理', '0', '0/', 'userInfo:view', 'menu', 'userInfo/userList');
INSERT INTO `sys_permission` VALUES ('2', '�', '使用者添加', '1', '0/1', 'userInfo:add', 'button', 'userInfo/userAdd');
INSERT INTO `sys_permission` VALUES ('3', '�', '使用者删除', '1', '0/1', 'userInfo:del', 'button', 'userInfo/userDel');
INSERT INTO `sys_role` VALUES ('1', '�', '管理者', 'admin');
INSERT INTO `sys_role` VALUES ('2', '�', 'VIP會員', 'vip');
INSERT INTO `sys_role_permission` VALUES ('1', '1');
INSERT INTO `sys_role_permission` VALUES ('1', '2');
INSERT INTO `sys_role_permission` VALUES ('1', '3');
INSERT INTO `sys_user_role` VALUES ('1', '1');
INSERT INTO `user_info` VALUES ('1', 'admin', '管理者', 'd3c59d25033dbf980d29554025c23a75', '8d78869f470951332959580424d4bf4f', '0');
下一篇文章将講實作身份認證,權限控制