如何快速的入門shiro(二)使用JbcRealm

本博文將會在博文一的基礎上更改部分代碼,若不熟悉,請看博文一的詳細內容。本博文將主要描述shiro內置的JdbcRealm,JdbcRealm主要是連接到數據庫,從數據庫獲取數據,達到認證和授權的目的。廢話不多說,直接上代碼。

目錄

1. pom.xml引入mysql-connector和druid數據源

2. 根據RBAC的相關原則,先使用內置的JdbcRealm內置的默認SQL語句來查詢,根據默認的SQL語句如下

3. 根據默認的JdbcRealm編寫相關的代碼

 4. 如果我們需要自己自定義查詢語句,就需要5張表才能很好的運用權限和角色以及用戶的表

5. 我們需要在博文一的基礎上,shiroTest.java同名的文件夾下新建一個jdbcRealmTest.java類文件用於測試JdbcRealm

6. 總結

6.1 iniRealm和JdbcRealm的區別

6.2 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 編譯運行測試

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章