本博文將會在博文一的基礎上更改部分代碼,若不熟悉,請看博文一的詳細內容。本博文將主要描述shiro內置的JdbcRealm,JdbcRealm主要是連接到數據庫,從數據庫獲取數據,達到認證和授權的目的。廢話不多說,直接上代碼。
目錄
1. pom.xml引入mysql-connector和druid數據源
2. 根據RBAC的相關原則,先使用內置的JdbcRealm內置的默認SQL語句來查詢,根據默認的SQL語句如下
4. 如果我們需要自己自定義查詢語句,就需要5張表才能很好的運用權限和角色以及用戶的表
5. 我們需要在博文一的基礎上,shiroTest.java同名的文件夾下新建一個jdbcRealmTest.java類文件用於測試JdbcRealm
1. pom.xml引入mysql-connector和druid數據源
代碼片段如下
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.48</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.1.6</version>
</dependency>
PS1:由於mysql5.x和8.x版本差異太大,導致jdbc連接庫也差異太大,爲了更好的使用,建議用5.x的版本連接mysql
PS2:druid是阿里巴巴開發的用於數據源管理的工具,不在此文章詳細討論的範圍內
2. 根據RBAC的相關原則,先使用內置的JdbcRealm內置的默認SQL語句來查詢,根據默認的SQL語句如下
建立與之相匹配的表,建表語句如下
/*
Navicat Premium Data Transfer
Source Server : mysql
Source Server Type : MySQL
Source Server Version : 50725
Source Host : localhost:3306
Source Schema : testshiro
Target Server Type : MySQL
Target Server Version : 50725
File Encoding : 65001
Date: 05/04/2020 11:17:18
*/
SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0;
-- ----------------------------
-- Table structure for permission
-- ----------------------------
DROP TABLE IF EXISTS `permission`;
CREATE TABLE `permission` (
`permission_id` int(11) NOT NULL COMMENT '權限id\r\n',
`permission_name` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '權限名稱',
PRIMARY KEY (`permission_id`) USING BTREE,
INDEX `permission_name`(`permission_name`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;
-- ----------------------------
-- Records of permission
-- ----------------------------
INSERT INTO `permission` VALUES (3, 'add');
INSERT INTO `permission` VALUES (2, 'delete');
INSERT INTO `permission` VALUES (1, 'update');
-- ----------------------------
-- Table structure for role
-- ----------------------------
DROP TABLE IF EXISTS `role`;
CREATE TABLE `role` (
`role_id` int(11) NOT NULL COMMENT '角色id',
`role_name` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '角色名稱',
PRIMARY KEY (`role_id`) USING BTREE,
INDEX `role_name`(`role_name`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;
-- ----------------------------
-- Records of role
-- ----------------------------
INSERT INTO `role` VALUES (1, 'admin');
INSERT INTO `role` VALUES (3, 'adminplus');
INSERT INTO `role` VALUES (2, 'adminpro');
-- ----------------------------
-- Table structure for roles_permissions
-- ----------------------------
DROP TABLE IF EXISTS `roles_permissions`;
CREATE TABLE `roles_permissions` (
`role_permission_id` int(11) NOT NULL COMMENT 'role_permisison_id',
`role_name` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '角色名',
`permission` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '權限名',
PRIMARY KEY (`role_permission_id`) USING BTREE,
INDEX `role_name`(`role_name`) USING BTREE,
INDEX `permission`(`permission`) USING BTREE,
CONSTRAINT `roles_permissions_ibfk_1` FOREIGN KEY (`role_name`) REFERENCES `role` (`role_name`) ON DELETE RESTRICT ON UPDATE RESTRICT,
CONSTRAINT `roles_permissions_ibfk_2` FOREIGN KEY (`permission`) REFERENCES `permission` (`permission_name`) ON DELETE RESTRICT ON UPDATE RESTRICT
) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;
-- ----------------------------
-- Records of roles_permissions
-- ----------------------------
INSERT INTO `roles_permissions` VALUES (1, 'admin', 'update');
INSERT INTO `roles_permissions` VALUES (2, 'admin', 'add');
INSERT INTO `roles_permissions` VALUES (3, 'adminpro', 'update');
INSERT INTO `roles_permissions` VALUES (4, 'adminpro', 'delete');
-- ----------------------------
-- Table structure for user_roles
-- ----------------------------
DROP TABLE IF EXISTS `user_roles`;
CREATE TABLE `user_roles` (
`user_role_id` int(11) NOT NULL COMMENT 'user_role_id',
`username` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '用戶名',
`role_name` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '角色名',
PRIMARY KEY (`user_role_id`) USING BTREE,
INDEX `username`(`username`) USING BTREE,
INDEX `role_name`(`role_name`) USING BTREE,
CONSTRAINT `user_roles_ibfk_1` FOREIGN KEY (`username`) REFERENCES `users` (`username`) ON DELETE RESTRICT ON UPDATE RESTRICT,
CONSTRAINT `user_roles_ibfk_2` FOREIGN KEY (`role_name`) REFERENCES `role` (`role_name`) ON DELETE RESTRICT ON UPDATE RESTRICT
) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;
-- ----------------------------
-- Records of user_roles
-- ----------------------------
INSERT INTO `user_roles` VALUES (1, 'zhangsan', 'admin');
INSERT INTO `user_roles` VALUES (2, 'wangwu', 'adminpro');
-- ----------------------------
-- Table structure for users
-- ----------------------------
DROP TABLE IF EXISTS `users`;
CREATE TABLE `users` (
`userid` bigint(255) NULL DEFAULT NULL COMMENT '用戶編號id',
`username` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '用戶名',
`password` varchar(10240) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '用戶密碼',
`password_salt` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '用戶密碼鹽值',
INDEX `username`(`username`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;
-- ----------------------------
-- Records of users
-- ----------------------------
INSERT INTO `users` VALUES (1, 'zhangsan', '123', NULL);
INSERT INTO `users` VALUES (2, 'wangwu', '456', NULL);
SET FOREIGN_KEY_CHECKS = 1;
3. 根據默認的JdbcRealm編寫相關的代碼
代碼片段如下
public class JdbcRealmTest {
// 創建JDBC數據源
DruidDataSource druidDataSource = new DruidDataSource();
{
druidDataSource.setUrl("jdbc:mysql://localhost:3306/testshiro");
druidDataSource.setUsername("root");
druidDataSource.setPassword("root");
}
@Test
public void Test() {
// 創建jdbcRealm數據源對象
JdbcRealm jdbcRealm = new JdbcRealm();
// 將druidDataSource綁定在jdbcRealm
jdbcRealm.setDataSource(druidDataSource);
// 設置開啓可查詢權限角色等SQL功能,一定要開啓這個,不然查不到權限信息-坑1
jdbcRealm.setPermissionsLookupEnabled(true);
DefaultSecurityManager defaultSecurityManager = new DefaultSecurityManager();
defaultSecurityManager.setRealm(jdbcRealm);
SecurityUtils.setSecurityManager(defaultSecurityManager);
Subject subject = SecurityUtils.getSubject();
UsernamePasswordToken token = new UsernamePasswordToken("zhangsan", "123");
subject.login(token);
System.out.println(subject.getPrincipal() + "是否驗證成功" + subject.isAuthenticated());
// 使用ArrayList存儲角色
List<String> roles = new ArrayList<String>();
roles.add("admin");
roles.add("adminplus");
roles.add("adminpro");
// 循環測試角色
for (String role : roles) {
System.out.println("當前用戶是" + subject.getPrincipal() + "\t 是否具有" + role + "角色 \t" + subject.hasRole(role));
}
// 使用arraylist存放權限組
List<String> permissions = new ArrayList<String>();
permissions.add("update");
permissions.add("delete");
permissions.add("add");
permissions.add("get");
// 循環驗證當前用戶是否具有對應的權限
for (String permission : permissions) {
System.out.println("當前用戶是" + subject.getPrincipal() + "\t 是否具有" + permission + "權限 \t"
+ subject.isPermitted(permission));
}
System.out.println(subject.isPermitted("get"));
// 登出當前用戶
subject.logout();
// 驗證當前用戶是否登出
System.out.println(subject.getPrincipal() + "是否登錄成功?" + subject.isAuthenticated());
}
}
編譯運行效果如圖
PS3:在這過程中,有一個坑,就是需要設置開啓可查詢權限角色等SQL功能,一定要開啓這個,
jdbcRealm.setPermissionsLookupEnabled(true) 才能查詢到相關的權限信息,否則是查不到的,只能查詢到用戶以及角色的信息,這是我踩的一個坑,希望各位注意,至於爲什麼,恕此文暫不講解。
4. 如果我們需要自己自定義查詢語句,就需要5張表才能很好的運用權限和角色以及用戶的表
建表語句如下
/*
Navicat Premium Data Transfer
Source Server : mysql
Source Server Type : MySQL
Source Server Version : 50725
Source Host : localhost:3306
Source Schema : shirotest
Target Server Type : MySQL
Target Server Version : 50725
File Encoding : 65001
Date: 05/04/2020 10:46:08
*/
SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0;
-- ----------------------------
-- Table structure for permission
-- ----------------------------
DROP TABLE IF EXISTS `permission`;
CREATE TABLE `permission` (
`permission_id` int(11) NOT NULL AUTO_INCREMENT COMMENT '權限id',
`permission_name` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '權限名稱',
PRIMARY KEY (`permission_id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 6 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;
-- ----------------------------
-- Records of permission
-- ----------------------------
INSERT INTO `permission` VALUES (1, 'update');
INSERT INTO `permission` VALUES (2, 'delete');
INSERT INTO `permission` VALUES (3, 'add');
INSERT INTO `permission` VALUES (4, 'get');
INSERT INTO `permission` VALUES (5, 'hello');
-- ----------------------------
-- Table structure for role
-- ----------------------------
DROP TABLE IF EXISTS `role`;
CREATE TABLE `role` (
`role_id` int(11) NOT NULL COMMENT '角色id',
`role_name` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '角色名稱',
PRIMARY KEY (`role_id`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;
-- ----------------------------
-- Records of role
-- ----------------------------
INSERT INTO `role` VALUES (1, 'admin');
INSERT INTO `role` VALUES (2, 'adminplus');
-- ----------------------------
-- Table structure for role_permission
-- ----------------------------
DROP TABLE IF EXISTS `role_permission`;
CREATE TABLE `role_permission` (
`role_permission_id` int(11) NOT NULL AUTO_INCREMENT COMMENT '角色權限id',
`role_id` int(11) NULL DEFAULT NULL COMMENT '角色id',
`permission_id` int(11) NULL DEFAULT NULL COMMENT '權限id',
PRIMARY KEY (`role_permission_id`) USING BTREE,
INDEX `role_id`(`role_id`) USING BTREE,
INDEX `permission_id`(`permission_id`) USING BTREE,
CONSTRAINT `role_permission_ibfk_1` FOREIGN KEY (`role_id`) REFERENCES `role` (`role_id`) ON DELETE RESTRICT ON UPDATE RESTRICT,
CONSTRAINT `role_permission_ibfk_2` FOREIGN KEY (`permission_id`) REFERENCES `permission` (`permission_id`) ON DELETE RESTRICT ON UPDATE RESTRICT
) ENGINE = InnoDB AUTO_INCREMENT = 8 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;
-- ----------------------------
-- Records of role_permission
-- ----------------------------
INSERT INTO `role_permission` VALUES (1, 1, 1);
INSERT INTO `role_permission` VALUES (2, 1, 2);
INSERT INTO `role_permission` VALUES (5, 2, 3);
INSERT INTO `role_permission` VALUES (6, 2, 4);
-- ----------------------------
-- Table structure for user
-- ----------------------------
DROP TABLE IF EXISTS `user`;
CREATE TABLE `user` (
`user_id` int(11) NOT NULL AUTO_INCREMENT COMMENT '用戶編號id',
`user_name` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '用戶名',
`user_password` varchar(10240) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '用戶密碼',
PRIMARY KEY (`user_id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 4 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;
-- ----------------------------
-- Records of user
-- ----------------------------
INSERT INTO `user` VALUES (1, 'admin', 'admin');
INSERT INTO `user` VALUES (2, 'zhangsan', '123');
INSERT INTO `user` VALUES (3, 'lisi', '456');
-- ----------------------------
-- Table structure for user_role
-- ----------------------------
DROP TABLE IF EXISTS `user_role`;
CREATE TABLE `user_role` (
`user_role_id` int(11) NOT NULL AUTO_INCREMENT COMMENT '用戶角色id',
`user_id` int(11) NULL DEFAULT NULL COMMENT '用戶id',
`role_id` int(11) NULL DEFAULT NULL COMMENT '角色id',
PRIMARY KEY (`user_role_id`) USING BTREE,
INDEX `user_id`(`user_id`) USING BTREE,
INDEX `role_id`(`role_id`) USING BTREE,
CONSTRAINT `user_role_ibfk_1` FOREIGN KEY (`user_id`) REFERENCES `user` (`user_id`) ON DELETE RESTRICT ON UPDATE RESTRICT,
CONSTRAINT `user_role_ibfk_2` FOREIGN KEY (`role_id`) REFERENCES `role` (`role_id`) ON DELETE RESTRICT ON UPDATE RESTRICT
) ENGINE = InnoDB AUTO_INCREMENT = 3 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;
-- ----------------------------
-- Records of user_role
-- ----------------------------
INSERT INTO `user_role` VALUES (1, 2, 1);
INSERT INTO `user_role` VALUES (2, 3, 2);
SET FOREIGN_KEY_CHECKS = 1;
PS4:由於JdbcRealm會有默認的SQL查詢語句,如果需要直接使用默認的SQL語句,請不要按照我以上的建表語句,需要根據默認的語句來建表,我只是爲了方便更好的處理以及更好的閱讀,所以纔沒有按照默認的SQL語句來,如果需要默認的SQL語句,請按照以上第2點來建表。
5. 我們需要在博文一的基礎上,shiroTest.java同名的文件夾下新建一個jdbcRealmTest.java類文件用於測試JdbcRealm
代碼片段如下
public class JdbcRealmTest {
// 創建JDBC數據源
DruidDataSource druidDataSource = new DruidDataSource();
{
druidDataSource.setUrl("jdbc:mysql://localhost:3306/shirotest");
druidDataSource.setUsername("root");
druidDataSource.setPassword("root");
}
@Test
public void Test() {
// 創建jdbcRealm數據源對象
JdbcRealm jdbcRealm = new JdbcRealm();
// 將druidDataSource綁定在jdbcRealm
jdbcRealm.setDataSource(druidDataSource);
// 設置開啓可查詢權限角色等SQL功能,一定要開啓這個,纔可以使用自定義的SQL查詢語句
jdbcRealm.setPermissionsLookupEnabled(true);
// 查詢用戶名,密碼
String UsernamePasswordSQL = "select user_password from user where user_name =?";
jdbcRealm.setAuthenticationQuery(UsernamePasswordSQL);
// 查詢用戶所對應的角色
String RoleSQL="select role_name from role as r left join user_role as ur on ur.role_id=r.role_id\r\n" +
"left join user as u on u.user_id=ur.user_id where u.user_name=?";
jdbcRealm.setUserRolesQuery(RoleSQL);
// 查詢角色所對應的權限
String PermissionSQL="select permission_name from permission as p\r\n" +
"left join role_permission as rp on p.permission_id=rp.permission_id\r\n" +
"left join role as r on rp.role_id=r.role_id where r.role_name=?";
jdbcRealm.setPermissionsQuery(PermissionSQL);
DefaultSecurityManager defaultSecurityManager = new DefaultSecurityManager();
defaultSecurityManager.setRealm(jdbcRealm);
SecurityUtils.setSecurityManager(defaultSecurityManager);
Subject subject = SecurityUtils.getSubject();
UsernamePasswordToken token = new UsernamePasswordToken("zhangsan", "123");
subject.login(token);
System.out.println(subject.getPrincipal() + "是否驗證成功" + subject.isAuthenticated());
// 使用ArrayList存儲角色
List<String> roles = new ArrayList<String>();
roles.add("admin");
roles.add("adminplus");
roles.add("adminpro");
// 循環測試角色
for (String role : roles) {
System.out.println("當前用戶是" + subject.getPrincipal() + "\t 是否具有" + role + "角色 \t" + subject.hasRole(role));
}
// 使用arraylist存放權限組
List<String> permissions = new ArrayList<String>();
permissions.add("update");
permissions.add("delete");
permissions.add("add");
permissions.add("get");
// 循環驗證當前用戶是否具有對應的權限
for (String permission : permissions) {
System.out.println("當前用戶是" + subject.getPrincipal() + "\t 是否具有" + permission + "權限 \t"
+ subject.isPermitted(permission));
}
System.out.println(subject.isPermitted("get"));
// 登出當前用戶
subject.logout();
// 驗證當前用戶是否登出
System.out.println(subject.getPrincipal() + "是否登錄成功?" + subject.isAuthenticated());
}
}
編譯運行後效果如下
PS5: 在這過程中,踩的另外一個坑是編寫查詢權限的SQL語句時,我錯誤的認爲查詢權限是要根據用戶名來的,因此我編寫了根據用戶名來查詢權限的SQL語句,但這一執行才發現雖然數據庫能查到,但shiro並沒有將數據庫查到的注入到其中,因此判斷就出錯了,根據shiro內置的JdbcRealm的默認SQL規則,我發現原來查詢角色是根據用戶名來的,而查詢權限則是根據角色名來的,因此我才更改了查詢語句,才能成功的將權限名注入進去。
6. 總結
6.1 iniRealm和JdbcRealm的區別
iniRelam | JdbcRealm |
不連接數據庫,直接從ini文件讀取 | 連接數據庫,從數據庫讀取 |
從文件讀取比較固定,不太靈活 | 從數據庫讀取比較靈活,自由 |
6.2 JdbcRealm完成認證和授權的核心代碼
6.2.1 數據庫需要根據RBAC原則建立5張表
6.2.2 pom.xml引入mysq-connector.jar 和druid數據源
6.2.3 創建druidDataSource數據源
6.2.4 創建JdbcRealm對象
6.2.5 將druidDataSource數據源綁定到JdbcRealm對象上
6.2.6 如果採用默認SQL語句,直接執行就好
6.2.7 如果採用自定義SQL語句,請自定義編寫SQL語句以及設置語句查詢
6.2.8 編譯運行測試