02. Erklären Sie den tatsächlichen Kampf im Reich der Apachen Shiro im Detail

Einführung: Erklären Sie den Standardbereich von shiro und allgemeine Verwendungsmethoden

  • Realm-Rolle: Shiro erhält Sicherheitsdaten von Realm

  • Der Realm, der standardmäßig dabei ist: idae überprüft die Realm-Vererbungsbeziehung, es gibt Realms mit Standardimplementierung und benutzerdefinierter Vererbung

  • zwei Konzepte

    • Prinzipal: Es kann mehrere Prinzipale geben, aber sie müssen eindeutig sein. Übliche sind Benutzername, Mobiltelefonnummer, E-Mail-Adresse usw.
    • Anmeldedaten: Anmeldedaten, normalerweise Passwörter
    • Im Allgemeinen sagen wir also, Prinzipal + Anmeldeinformationen sind Konto + Passwort
  • In der Entwicklung handelt es sich oft um einen benutzerdefinierten Realm, dh um AuthorizingRealm! ! ! ! ! !

Realms Vererbungs- und Implementierungsbeziehung

Bild.png

Schnellstart Shiro integrierte IniRealm praktische Bedienung und Berechtigungsüberprüfungs-API

Tatsächlicher Kampf: Holen Sie sich den Benutzer Jack aus der Datei shiro.ini und beurteilen Sie dann die relevanten Berechtigungen dieses Benutzers

Hinweis ⚠️: Diese Schreibweise soll uns verstehen lassen, was das Shiro-Framework tut, ohne eine Verbindung zur Datenbank herzustellen, um schnell die Rolle des Sicherheitsframeworks von Shiro zu erfahren. In der tatsächlichen Entwicklung wird diese Methode definitiv nicht verwendet werden.

Erstellen Sie eine shiro.ini-Datei im Ressourcenverzeichnis

shiro.ino

# 格式 name=password,role1,role2,..roleN

[users]

# user 'root' with password 'secret' and the 'admin' role,

jack = 456, user

# user 'guest' with the password 'guest' and the 'guest' role

lll = 123, root,admin

# 格式 role=permission1,permission2...permissionN 也可以用通配符

# 下面配置user的权限为所有video:find,video:buy,如果需要配置video全部操作crud 则 user = video:*

[roles]
user = video:find,video:buy

# 'admin' role has all permissions, indicated by the wildcard '*'
admin = *
复制代码

Testklasse: QuickStartTest3.java

package com.lzh;

/**
 * @Author:kaiyang.cui
 * @Package:com.lzh
 * @Project:lzh_shiro
 * @name:QuickStartTest
 * @Date:2023/3/27 下午2:05
 * @Filename:QuickStartTest
 * @Description:从shiro.ini 文件中取到用户jack,然后判断这个用户的相关权限
 * @Version:1.0
 */

import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.config.IniSecurityManagerFactory;
import org.apache.shiro.mgt.SecurityManager;
import org.apache.shiro.subject.Subject;
import org.apache.shiro.util.Factory;
import org.junit.Test;

public class QuickStartTest3 {


    @Test
    public void testAuthentication() {

        // 创建SecurityManager工厂,通过配置文件ini创建
        Factory<SecurityManager> factory = new IniSecurityManagerFactory("classpath:shiro.ini");
        SecurityManager securityManager = factory.getInstance();

        // 将securityManager设置到当前运行环境中
        SecurityUtils.setSecurityManager(securityManager);

        Subject subject = SecurityUtils.getSubject();

        // 模拟用户输入的用户名和密码
        UsernamePasswordToken usernamePasswordToken = new UsernamePasswordToken("jack", "456");
        subject.login(usernamePasswordToken);

        // 获取验证结果 isAuthenticated() 是否授权,结果是boolen
        System.out.println("认证结果:" + subject.isAuthenticated());

        // 是否有对应的角色
        System.out.println("是否有user角色:" + subject.hasRole("user"));

        System.out.println("getPrincipal认证结果-实际上就是获取登录用户账号" + subject.getPrincipal());

        System.out.println("检查是否有视频删除权限,如果有则不报错,没有就报错。不用担心");
        try {
            subject.checkPermission("video:delete");
        } catch (Exception e) {
            System.err.println("没有video:delete权限");
        }


        //isPermitted() 和 checkPermission() 方法的区别是,前者有返回值,后者没有
        System.out.println("是否有视频购买权限:" + subject.isPermitted("video:buy"));

        // 退出登录
        subject.logout();

        // 检查用户退出登录后的认证结果
        System.out.println("认证结果:" + subject.isAuthenticated());
    }
}
复制代码
认证结果:true
是否有user角色:true
getPrincipal认证结果-实际上就是获取登录用户账号jack
检查是否有视频删除权限,如果有则不报错,没有就报错。不用担心
没有video:delete权限
是否有视频购买权限:true
认证结果:false
复制代码

Schnellstart Shiro eingebauter JdbcRealm praktischer Betrieb

Diese Methode wird für die Entwicklung empfohlen

Erstellen Sie zuerst eine Datenbank, Sie können den Namen der Datenbank wählen, das Folgende ist die SQL, um eine Tabelle zu erstellen und einige grundlegende Daten einzufügen

Diese Tabelle ist ein Benutzer, der mehreren Rollen entspricht, und eine Rolle, die mehreren Berechtigungen entspricht.

/*
 Navicat MySQL Data Transfer

 Source Server         : 阿里云华北root
 Source Server Type    : MySQL
 Source Server Version : 80024
 Source Host           : 39.97.253.89:3306
 Source Schema         : class_shiro

 Target Server Type    : MySQL
 Target Server Version : 80024
 File Encoding         : 65001

 Date: 27/03/2023 16:38:39
*/

SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0;

-- ----------------------------
-- Table structure for roles_permissions
-- ----------------------------
DROP TABLE IF EXISTS `roles_permissions`;
CREATE TABLE `roles_permissions` (
  `id` bigint NOT NULL AUTO_INCREMENT,
  `role_name` varchar(100) DEFAULT NULL,
  `permission` varchar(100) DEFAULT NULL,
  PRIMARY KEY (`id`),
  UNIQUE KEY `idx_roles_permissions` (`role_name`,`permission`)
) ENGINE=InnoDB AUTO_INCREMENT=6 DEFAULT CHARSET=utf8mb3;

-- ----------------------------
-- Records of roles_permissions
-- ----------------------------
BEGIN;
INSERT INTO `roles_permissions` VALUES (4, 'admin', 'video:*');
INSERT INTO `roles_permissions` VALUES (3, 'role1', 'video:buy');
INSERT INTO `roles_permissions` VALUES (2, 'role1', 'video:find');
INSERT INTO `roles_permissions` VALUES (5, 'role2', '*');
INSERT INTO `roles_permissions` VALUES (1, 'root', '*');
COMMIT;

-- ----------------------------
-- Table structure for user_roles
-- ----------------------------
DROP TABLE IF EXISTS `user_roles`;
CREATE TABLE `user_roles` (
  `id` bigint NOT NULL AUTO_INCREMENT,
  `username` varchar(100) DEFAULT NULL,
  `role_name` varchar(100) DEFAULT NULL,
  PRIMARY KEY (`id`),
  UNIQUE KEY `idx_user_roles` (`username`,`role_name`)
) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8mb3;

-- ----------------------------
-- Records of user_roles
-- ----------------------------
BEGIN;
INSERT INTO `user_roles` VALUES (1, 'jack', 'role1');
INSERT INTO `user_roles` VALUES (2, 'jack', 'role2');
INSERT INTO `user_roles` VALUES (4, 'lzh', 'admin');
INSERT INTO `user_roles` VALUES (3, 'lzh', 'root');
COMMIT;

-- ----------------------------
-- Table structure for users
-- ----------------------------
DROP TABLE IF EXISTS `users`;
CREATE TABLE `users` (
  `id` bigint NOT NULL AUTO_INCREMENT,
  `username` varchar(100) DEFAULT NULL,
  `password` varchar(100) DEFAULT NULL,
  `password_salt` varchar(100) DEFAULT NULL,
  PRIMARY KEY (`id`),
  UNIQUE KEY `idx_users_username` (`username`)
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8mb3;

-- ----------------------------
-- Records of users
-- ----------------------------
BEGIN;
INSERT INTO `users` VALUES (1, 'jack', '123', NULL);
INSERT INTO `users` VALUES (2, 'lzh', '456', NULL);
COMMIT;

SET FOREIGN_KEY_CHECKS = 1;
复制代码

Erstellen Sie dann die Datei jdbcrealm.ini im Ressourcenverzeichnis: jdbcrealm.ini

#注意 文件格式必须为ini,编码为ANSI

#声明Realm,指定realm类型
jdbcRealm=org.apache.shiro.realm.jdbc.JdbcRealm

#配置数据源

#dataSource=com.mchange.v2.c3p0.ComboPooledDataSource

 
dataSource=com.alibaba.druid.pool.DruidDataSource

# mysql-connector-java 5 用的驱动url是com.mysql.jdbc.Driver,mysql-connector-java6以后用的是com.mysql.cj.jdbc.Driver

dataSource.driverClassName=com.mysql.cj.jdbc.Driver

#避免安全警告
dataSource.url=jdbc:mysql://39.97.253.89:3306/class_shiro?characterEncoding=UTF-8&serverTimezone=UTC&useSSL=false

dataSource.username=你的账号

dataSource.password=你的密码

#指定数据源

jdbcRealm.dataSource=$dataSource

#开启查找权限, 默认是false,不会去查找角色对应的权限,坑!!!!!

jdbcRealm.permissionsLookupEnabled=true


#指定SecurityManager的Realms实现,设置realms,可以有多个,用逗号隔开

securityManager.realms=$jdbcRealm

复制代码

Hier gibt es eine Grube: Obwohl wir den MySQL-Treiber schreiben können, was wir wollen, wenn wir das SpringBoot-Projekt erstellen, hält sich diese Datei streng an die folgenden Regeln: Die von mysql-connector-java 5 verwendete Treiber-URL ist com.mysql.jdbc. Treiber, com.mysql.cj.jdbc.Driver wird nach mysql-connector-java6 verwendet

JdbcRealm-Methode 1: Schreiben Sie jdbcrealm.ini und verwenden Sie jdbcrealm.ini, um Shiro dabei zu helfen, die Benutzeranmeldungs-Abfragedatenbank zu simulieren, um Berechtigungsinformationen zu erhalten

Testen Sie den Code zum Schreiben dieser Datei über jdbcreamm.ini:

package com.lzh;

/**
 * @Author:kaiyang.cui
 * @Package:com.lzh
 * @Project:lzh_shiro
 * @name:QuickStartTest
 * @Date:2023/3/27 下午2:05
 * @Filename:QuickStartTest
 * @Description:从shiro.ini 文件中取到用户jack,然后判断这个用户的相关权限
 * @Version:1.0
 */

import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.config.IniSecurityManagerFactory;
import org.apache.shiro.mgt.SecurityManager;
import org.apache.shiro.subject.Subject;
import org.apache.shiro.util.Factory;
import org.junit.Test;

public class QuickStartTest4 {


    @Test
    public void testAuthentication() {

        // 创建SecurityManager工厂,通过配置文件ini创建
        Factory<SecurityManager> factory = new IniSecurityManagerFactory("classpath:jdbcrealm.ini");
        SecurityManager securityManager = factory.getInstance();

        // 将securityManager设置到当前运行环境中
        SecurityUtils.setSecurityManager(securityManager);

        Subject subject = SecurityUtils.getSubject();

        // 模拟用户输入的用户名和密码
        UsernamePasswordToken usernamePasswordToken = new UsernamePasswordToken("jack", "123");
        subject.login(usernamePasswordToken);

        // 获取验证结果 isAuthenticated() 是否授权,结果是boolen
        System.out.println("认证结果:" + subject.isAuthenticated());

        // 是否有对应的角色
        System.out.println("是否有user角色:" + subject.hasRole("admin"));

        // 是否有对应的权限
        System.out.println("是否有对应的权限:" + subject.isPermitted("video:delete"));
    }
}
复制代码
认证结果:true
是否有user角色:false
是否有对应的权限:false
复制代码

In der Datentabelle haben wir festgestellt, dass der Jack-Benutzer Rolle1 und Rolle2 hat, also gibt die hasRole-Methode false zurück, also haben wir den Java-Code, shiro.ini und die MySQL-Datenbank geöffnet. Gönnen Sie sich etwas Gutes.

Bild.png

Während ich dies schreibe, bin ich neugierig, warum eine jdbcrealm.ini-Konfigurationsdatei plus ein paar Codezeilen die Informationen eines bestimmten Benutzers finden kann, ohne überhaupt SQL-Anweisungen zu schreiben. Hier müssen Sie org.apache.shiro.realm.jdbc.JdbcRealmden Quellcode überprüfen, der Quellcode lautet wie folgt:

Bild.png

Nachdem ich mir den Quellcode angesehen hatte, wurde mir plötzlich klar , dass die Abfrageanweisung in der JdbcRealm-Klasse definiert wurde! ! ! ! !

Warten Sie, ich habe auch herausgefunden, dass die Datentabellen user, user_roles, roles_permissions-Tabellen sind, weshalb alle Tabellen, die wir sehen, denselben Namen haben, wenn wir andere Leute dazu bringen, Projekte zu erledigen, als ob sie vereinbart worden wären! ! ! ! ! ! ! Wenn ich dann später die Datentabelle definiere, muss ich auch den Tabellennamen und die Tabellenfelder auf diese Weise definieren.

Methode 2: Mit dem Datenbankverbindungspool simuliert shiro die Benutzeranmeldung, um Datenbankberechtigungsinformationen abzufragen

package com.lzh;

/**
 * @Author:kaiyang.cui
 * @Package:com.lzh
 * @Project:lzh_shiro
 * @name:QuickStartTest
 * @Date:2023/3/27 下午2:05
 * @Filename:QuickStartTest
 * @Description:方式二使用数据库连接池
 * @Version:1.0
 */

import com.alibaba.druid.pool.DruidDataSource;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.mgt.DefaultSecurityManager;
import org.apache.shiro.realm.jdbc.JdbcRealm;
import org.apache.shiro.subject.Subject;
import org.junit.Test;

public class QuickStartTest5 {


    @Test
    public void testAuthentication() {
        DefaultSecurityManager securityManager = new DefaultSecurityManager();

        DruidDataSource ds = new DruidDataSource();
        ds.setDriverClassName("com.mysql.cj.jdbc.Driver");
        ds.setUrl("jdbc:mysql://39.97.253.89:3306/class_shiro?characterEncoding=UTF-8&serverTimezone=UTC&useSSL=false");
        ds.setUsername("你的账号");
        ds.setPassword("你的密码");

        JdbcRealm jdbcRealm = new JdbcRealm();
        jdbcRealm.setPermissionsLookupEnabled(true);
        jdbcRealm.setDataSource(ds);
        securityManager.setRealm(jdbcRealm);

        // 将securityManager设置到当前运行环境中
        SecurityUtils.setSecurityManager(securityManager);

        Subject subject = SecurityUtils.getSubject();

        // 模拟用户输入的用户名和密码
        UsernamePasswordToken usernamePasswordToken = new UsernamePasswordToken("jack", "123");
        subject.login(usernamePasswordToken);

        // 获取验证结果 isAuthenticated() 是否授权,结果是boolen
        System.out.println("认证结果:" + subject.isAuthenticated());

        // 是否有对应的角色
        System.out.println("是否有user角色:" + subject.hasRole("admin"));

        // 是否有对应的权限
        System.out.println("是否有对应的权限:" + subject.isPermitted("video:delete"));
    }
}
复制代码
认证结果:true
是否有user角色:false
是否有对应的权限:false

复制代码

Zusammenfassen:

In IniRealm stellen wir die Rollen und Berechtigungen der Benutzerinformationen in der Datei shiro.ini dar. Durch die Zusammenarbeit mit dem Java-Code haben wir die Informationen, Rollen und Berechtigungen der simulierten Benutzeranmeldung erhalten, aber wer speichert die Informationen des Benutzers Was etwa in der *.ini-Datei? ? ? ? Benutzer werden in der Datenbank gespeichert.

Dann haben wir die JdbcRealm-Klasse gelernt, was wie das Erlernen von JavaJDBC am Anfang ist. Wir werden Java-Code verwenden, um durch die MySQL-Datenbank zu gelangen, aber diese Operation ist immer noch nicht sehr bequem. Wir verwenden shiro im Unternehmen, um die Anpassung von Benutzerberechtigungsinformationen durch die Anpassung von Realm zu realisieren. Shiro ist ein Serienartikel, bitte achten Sie auf meine Nuggets.

Ich denke du magst

Origin juejin.im/post/7215163152907436088
Empfohlen
Rangfolge