Detaillierte Erklärung von Shiro (sehr umfassend)

1. Einleitung

  • Das Shiro-Sicherheitsframework ist ein leistungsstarkes und flexibles Sicherheitsframework, das von Apache bereitgestellt wird
  • Das Shiro-Sicherheitsframework bietet Funktionen im Zusammenhang mit Authentifizierung, Autorisierung, Unternehmenssitzungsverwaltung, Verschlüsselung und Cache-Verwaltung. Mit Shiro kann die Entwicklung von Projektautoritätsverwaltungsmodulen problemlos abgeschlossen werden
  • Einfach und flexibel, von der Feder trennbar

2. Die Gesamtstruktur von Shiro

Fügen Sie hier eine Bildbeschreibung ein

1、Betreff

​ Subjekt ist das Subjekt (der aktuelle Benutzer kann als Subjekt verstanden werden). Externe Anwendungen interagieren mit dem Subjekt. Das Subjekt zeichnet den aktuellen Betriebsbenutzer auf und versteht das Konzept des Benutzers als Subjekt des aktuellen Vorgangs. Es kann ein sein Benutzer, der über einen Browser eine Anfrage stellt, oder wahrscheinlich ein laufendes Programm. Subject ist eine Schnittstelle in Shiro. Viele Methoden im Zusammenhang mit Authentifizierung und Autorisierung sind in der Schnittstelle definiert. Externe Programme führen die Authentifizierung und Autorisierung über Subject durch, und Subject führt die Authentifizierung und Autorisierung über den Sicherheitsmanager SecurityManager durch.

2、Sicherheitsmanager

​ SecurityManager ist der Sicherheitsmanager, der die Sicherheit aller Subjekte verwaltet. Er ist der Kern von Shiro und für die Sicherheitsverwaltung aller Subjekte verantwortlich. Über den SecurityManager kann die Authentifizierung und Autorisierung des Subjekts abgeschlossen werden. Im Wesentlichen wird der SecurityManager über den ** Authenticator authentifiziert , über den Authorizer autorisiert ** und die Sitzungsverwaltung über den SessionManager.

​ SecurityManager ist eine Schnittstelle, die die drei Schnittstellen Authenticator, Authorizer und SessionManager erbt.

3、Kryptographie

​Kryptografie ist Passwortverwaltung. Shiro bietet eine Reihe von Verschlüsselungs-/Entschlüsselungskomponenten für eine einfache Entwicklung. Es stellt beispielsweise allgemeine Funktionen wie Hashing und Verschlüsselung/Entschlüsselung bereit.

4、Authentifikator

Authenticator ist ein Authentifikator, der Benutzeridentitäten authentifiziert. Authenticator ist eine Schnittstelle. Shiro stellt die Implementierungsklasse ModularRealmAuthenticator bereit. ModularRealmAuthenticator kann grundsätzlich die meisten Anforderungen erfüllen, und Sie können den Authentifikator auch anpassen.

5、Autor

​Autorisierer ist der Autorisierer. Der Benutzer leitet die Authentifizierung über den Authentifikator weiter. Beim Zugriff auf die Funktion muss der Autorisierer verwendet werden, um zu beurteilen, ob der Benutzer über die Betriebsberechtigung dieser Funktion verfügt.

6、Reich

Realm ist ein Realm, der einer Datenquelle entspricht. SecurityManager muss zur Sicherheitsauthentifizierung Benutzerberechtigungsdaten über Realm abrufen. Wenn sich beispielsweise Benutzeridentitätsdaten in der Datenbank befinden, muss Realm Benutzeridentitätsinformationen aus der Datenbank abrufen .

​Hinweis : Unter Realm versteht man nicht nur das Abrufen von Daten aus der Datenquelle. Im Realm gibt es zugehörige Codes zur Authentifizierung und Autorisierungsüberprüfung.

7、sessionManager

sessionManager ist eine Sitzungsverwaltung. Das Shiro-Framework definiert eine Reihe von Sitzungsverwaltungen. Es hängt nicht von der Sitzung des Webcontainers ab, sodass Shiro in Nicht-Webanwendungen verwendet werden kann und auch die Sitzungsverwaltung verteilter Anwendungen zentralisieren kann. Mit dieser Funktion kann Single Sign-On implementiert werden.

8、SessionDAO

SessionDAO ist ein Sitzungs-Dao, bei dem es sich um eine Reihe von Schnittstellen für Sitzungsvorgänge handelt. Wenn Sie beispielsweise die Sitzung in der Datenbank speichern möchten, können Sie die Sitzung über JDBC in der Datenbank speichern.

9、CacheManager

​ CacheManager ist eine Cache-Verwaltung, die Benutzerberechtigungsdaten im Cache speichert, was die Leistung verbessern kann.

3. Einführungsfall

​ Dieser Fall basiert auf der Integration des SSM-Frameworks

  1. Abhängigkeiten importieren
<dependency>
    <groupId>org.apache.shiro</groupId>
    <artifactId>shiro-core</artifactId>
    <version>1.3.2</version>
</dependency>
<dependency>
    <groupId>org.apache.shiro</groupId>
    <artifactId>shiro-web</artifactId>
    <version>1.3.2</version>
</dependency>
<dependency>
    <groupId>org.apache.shiro</groupId>
    <artifactId>shiro-spring</artifactId>
    <version>1.3.2</version>
</dependency>
<dependency>
    <groupId>org.apache.shiro</groupId>
    <artifactId>shiro-ehcache</artifactId>
    <version>1.3.2</version>
</dependency>
  1. Tabelle erstellen
SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0;

-- ----------------------------
-- Table structure for permission
-- ----------------------------
DROP TABLE IF EXISTS `permission`;
CREATE TABLE `permission`  (
  `id` int(11) NOT NULL AUTO_INCREMENT COMMENT '权限id,主键',
  `name` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '权限名称',
  `url` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '权限访问的url资源',
  PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 10 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Compact;

-- ----------------------------
-- Records of permission
-- ----------------------------
INSERT INTO `permission` VALUES (1, '用户管理', '/sys');
INSERT INTO `permission` VALUES (2, '教师管理', '/teacher');
INSERT INTO `permission` VALUES (3, '学生管理', '/student');

-- ----------------------------
-- Table structure for role
-- ----------------------------
DROP TABLE IF EXISTS `role`;
CREATE TABLE `role`  (
  `id` int(11) NOT NULL AUTO_INCREMENT COMMENT '角色id',
  `role_name` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '角色名',
  `state` tinyint(4) NULL DEFAULT 1 COMMENT '状态,1可用,0不可用',
  PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 3 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Compact;

-- ----------------------------
-- Records of role
-- ----------------------------
INSERT INTO `role` VALUES (1, '管理员', 1);
INSERT INTO `role` VALUES (2, '普通用户', 1);

-- ----------------------------
-- Table structure for role_permission
-- ----------------------------
DROP TABLE IF EXISTS `role_permission`;
CREATE TABLE `role_permission`  (
  `id` int(11) NOT NULL AUTO_INCREMENT COMMENT '主键',
  `role_id` int(11) NOT NULL COMMENT '关联role表的角色id',
  `permission_id` int(11) NOT NULL COMMENT '关联permission表的权限id',
  PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 11 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Compact;

-- ----------------------------
-- 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 (3, 1, 3);

-- ----------------------------
-- Table structure for user
-- ----------------------------
DROP TABLE IF EXISTS `user`;
CREATE TABLE `user`  (
  `id` int(11) NOT NULL AUTO_INCREMENT COMMENT '用户Id,主键',
  `username` varchar(50) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '用户账号',
  `password` varchar(50) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '用户密码',
  PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 3 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Compact;

-- ----------------------------
-- Records of user
-- ----------------------------
INSERT INTO `user` VALUES (1, 'admin', '111');
INSERT INTO `user` VALUES (2, 'zhangsan', '111');

-- ----------------------------
-- Table structure for user_role
-- ----------------------------
DROP TABLE IF EXISTS `user_role`;
CREATE TABLE `user_role`  (
  `id` int(11) NOT NULL AUTO_INCREMENT COMMENT '主键',
  `user_id` int(11) NOT NULL COMMENT '关联user表的用户id',
  `role_id` int(11) NOT NULL COMMENT '关联role表的角色id',
  PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 4 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Compact;

-- ----------------------------
-- Records of user_role
-- ----------------------------
INSERT INTO `user_role` VALUES (1, 1, 1);
INSERT INTO `user_role` VALUES (2, 1, 2);
INSERT INTO `user_role` VALUES (3, 2, 2);

SET FOREIGN_KEY_CHECKS = 1;
  1. Erstellen Sie die Entitätsklassen Benutzer und Rolle
@Data
@AllArgsConstructor
@NoArgsConstructor
public class User {
    
    
    private int id;
    private String username;
    private String password;
    private List<Role> roles; //该用户所具有的所有角色
}

@Data
@AllArgsConstructor
@NoArgsConstructor
public class Role {
    
    
    private int id; //角色表的主键
    private String roleName; //角色的名称
    private int state; //角色的状态
}
  1. UserMapper-Schnittstelle
public interface UserMapper {
    
    
    //根据用户账号查询用户信息
    User queryByUsername(String username);
}
  1. UserMapper.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.hqyj.cl.mapper.UserMapper">
    <!-- 配置映射 -->
    <resultMap id="userMap" type="user">
        <id column="id" property="id" />
        <result column="username" property="username" />
        <result column="password" property="password" />
        <collection property="roles" ofType="role">
            <id column="id" property="id" />
            <result column="role_name" property="roleName" />
            <result column="state" property="state" />
        </collection>
    </resultMap>
    <!-- 根据用户账号查询用户信息-->
    <select id="queryByUsername" resultMap="userMap">
         SELECT
            u.id,
            u.username,
            u.password,
            r.id,
            r.role_name,
            r.state
        FROM
            USER u
            LEFT JOIN user_role ur ON u.id = ur.user_id
            LEFT JOIN role r ON r.id = ur.role_id
        WHERE
            u.username = #{username}
    </select>
</mapper>
  1. UserService-Schnittstelle
public interface UserService {
    
    
    //使用用户名密码登录
    Map<String, Object> login(String username, String password);
    //将已登录的用户登出
    Map<String, Object> logout();
}
  1. UserServiceImpl
@Service
public class UserServiceImpl implements UserService {
    
    
    //使用用户名密码登录
    @Override
    public Map<String, Object> login(String username, String password) {
    
    
        Map<String, Object> result = new HashMap<>();
        //获取主体, 代表当前用户的对象
        Subject subject = SecurityUtils.getSubject();
        //判断当前用户是否已经登录过
        if(!subject.isAuthenticated()){
    
    
            //没认证用户才登录
            //使用待认证的用户名和密码创建安全令牌对象
            AuthenticationToken token = new UsernamePasswordToken(username, password);
            //让shiro框架检查令牌,执行登录
            try{
    
    
                subject.login(token);
            }catch (UnknownAccountException e){
    
    
                //用户不存在
                result.put("code", -1);
                result.put("message", username + "不存在");
                return result;
            }catch (IncorrectCredentialsException e){
    
    
                //用户名和密码不匹配
                result.put("code", -2);
                result.put("message", username + "密码错误");
                return result;
            }catch (AuthenticationException e){
    
    
                //其他任何异常
                e.printStackTrace();
                result.put("code", -3);
                result.put("message", username + "认证失败");
                return result;
            }
        }
        //已经通过认证
        System.out.println(username + "认证通过了....");
        //从shiro提供session对象中获取已经认证成功的用户信息
        Object user = subject.getSession().getAttribute("user");
        result.put("code", 200);
        result.put("message", username +"登录成功");
        result.put("loginUser", user);
        return result;
    }

    // 将已登录的用户登出
    @Override
    public Map<String, Object> logout() {
    
    
        //获取当前用户
        Subject subject = SecurityUtils.getSubject();
        Object username = subject.getPrincipal();
        //执行登出 , 即删除所有已经登录的相关信息
        subject.logout();
        Map<String, Object> result = new HashMap<>();
        result.put("code", 0);
        result.put("message", username + "用户登出成功");
        return result;
    }
}
  1. BenutzerController
@Controller
@RequestMapping("/user")
public class UserController {
    
    
    @Autowired
    private UserService userService;

    //用户登录
    @RequestMapping("/login")
    @ResponseBody //将返回的Map对象转换成json格式字符串,直接放在响应体中
    public Map<String, Object> login(User user){
    
    
        //1、对请求参数做判空
        if(user == null){
    
    
            Map<String, Object> result = new HashMap<>();
            result.put("code",-20);
            result.put("message","请求参数异常");
            return result;
        }
        //2、调用业务层执行业务,获取结果,然后直接返回数据
        return userService.login(user.getUsername(), user.getPassword());
    }

    //用户登出
    @RequestMapping("/logout")
    @ResponseBody
    public Map<String, Object> logout(){
    
    
        //调用业务层实现业务
        return userService.logout();
    }

}
  1. MyShiroRealm
public class MyShiroRealm extends AuthorizingRealm {
    
    

    @Autowired
    private UserMapper userMapper;
        
    //获取授权信息,由开发者提供shiro框架已认证过用户的权限信息
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
    
    
        return null;
    }
    //获取认证信息
    //由开发者来编写,实现从数据库中查询待认证的用户的用户信息。以提供給shiro框架进行密码匹配工作
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
    
    
        //使用token对象获取待登录用户的用户名
        String username = (String)token.getPrincipal();
        //从数据库中查询该username的用户的信息
        User user = userMapper.queryByUsername(username);
        //判断待登录用户是否存在
        if(user == null){
    
    
            throw new UnknownAccountException(username + "不存在");
        }
        //保存用户信息
        //获取shiro提供的当前用户的会话对象
        Session session = SecurityUtils.getSubject().getSession();
        //在shiro提供的会话对象中共享数据
        session.setAttribute("user", user);
        //创建一个SimpleAuthenticationInfo对象
        //三个参数: 1、用户名,2、数据库中用户的密码 3、realm的名称
        //返回AuthenticationInfo对象
        return new SimpleAuthenticationInfo(
                user.getUsername(),user.getPassword(),getName());
    }
}
  1. Shiro-Konfigurationsdatei
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans.xsd">

    <!-- 配置我们自定义realm类 bean-->
    <bean id="myShiroRealm" class="com.hqyj.cl.utils.MyShiroRealm">
    </bean>
    
    <!-- 配置shiro的核心对象 安全管理器-->
    <bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
        <!--依赖注入我们自已定义realm bean  -->
        <property name="realm" ref="myShiroRealm" />
    </bean>
    
    <!-- 配置shiro的过滤器bean 执行授权检查相关功能,这里得先配上 -->
    <bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
        <property name="securityManager" ref="securityManager" />
    </bean>
</beans>
  1. Importieren Sie die Shiro-Konfigurationsdatei in den applicationContext und lassen Sie sie von Spring verwalten
<import resource="spring-shiro.xml"/>
  1. Konfigurieren Sie den Shiro-Filter web.xml
<!-- 配置代理过滤器, 由spring提供实现,代理的目标对象是在ioc容器中的真实过滤器bean
 filter-name标签指定被代理的bean,这里的shiroFilter就是在ioc容器中的shiro过滤器bean的id
-->
<filter>
    <filter-name>shiroFilter</filter-name>
    <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
</filter>
<filter-mapping>
    <filter-name>shiroFilter</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>
  1. login.jsp
<%
    String path = request.getContextPath();
    String basePath = request.getScheme() + "://" +
            request.getServerName() + ":" + request.getServerPort() + path + "/";
%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<!doctype html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>后台登录</title>
    <meta name="renderer" content="webkit|ie-comp|ie-stand">
    <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
    <meta name="viewport" content="width=device-width,user-scalable=yes, minimum-scale=0.4, initial-scale=0.8,target-densitydpi=low-dpi" />
    <meta http-equiv="Cache-Control" content="no-siteapp" />
    <link rel="shortcut icon" href="<%=basePath%>static/favicon.ico" type="image/x-icon" />
    <link rel="stylesheet" href="<%=basePath%>static/css/font.css">
    <link rel="stylesheet" href="<%=basePath%>static/css/xadmin.css">
    <script type="text/javascript" src="<%=basePath%>static/js/jquery-2.1.1.min.js"></script>
    <script src="<%=basePath%>static/lib/layui/layui.js" charset="utf-8"></script>
    <script type="text/javascript" src="<%=basePath%>static/js/xadmin.js"></script>
</head>
<body class="login-bg">
<div class="login">
    <div class="message">用户登录</div>
    <div id="darkbannerwrap"></div>
    <hr class="hr15">
    <form action="" method="post" class="layui-form">
        <input name="username" placeholder="用户名" id="username"  type="text" class="layui-input" >
        <hr class="hr15">
        <input name="password" placeholder="密码" id="password"  type="password" class="layui-input">
        <hr class="hr15">
        <input value="登录" style="width:100%;" type="button" οnclick="login()">
        <hr class="hr20" >
    </form>
    <script>
        function login() {
            console.log()
            $.ajax({
                url:"../user/login",
                dataType:"json",
                type:"post",
                data:{
                    "username":$("#username").val(),
                    "password":$("#password").val(),
                },success:function (data) {
                    console.log(data)
                },error:function () {
                    alert("服务器错误");
                }
            })
        }
    </script>
</div>
</body>
</html>

4. Zertifizierungsprozess

1. Zertifizierungsprozess

Shiro-Authentifizierungsflussdiagramm
  1. Erstellen Sie ein Token-Token, das die vom Benutzer übermittelten Authentifizierungsinformationen enthält, dh die Kontonummer und das Kennwort.

  2. Führen Sie subject.login(token) aus und schließlich authentifiziert sich der securityManager über den Authenticator;

  3. Authentifikator-Implementierung ModularRealmAuthenticator ruft MyShiroRealm auf, um das echte Konto und Passwort des Benutzers im System zu erhalten;

  4. MyShiroRealm sucht zunächst entsprechend dem Konto im Token im System nach dem Konto und löst eine UnknownAccountException aus, wenn es es nicht finden kann. Wenn gefunden, geben Sie AuthenticationInfo zurück (einschließlich des echten Passworts).

  5. Der Authenticator gleicht das Passwort entsprechend der vom Realm zurückgegebenen AuthenticationInfo ab. Wenn dies fehlschlägt, wird eine IncorrectCredentialsException ausgelöst. Wenn dies erfolgreich ist, wird die Authentifizierung erfolgreich durchgeführt.

2. Häufige Ausnahmen

  1. UnknownAccountException Das Konto existiert nicht ungewöhnlich
org.apache.shiro.authc.UnknownAccountException: No account found for user...
  1. IncorrectCredentialsException Ausnahme bei Eingabe eines Passwortfehlers
org.apache.shiro.authc.IncorrectCredentialsException: Submitted credentials for token [org.apache.shiro.authc.UsernamePasswordToken - zhangsan, rememberMe=false] did not match the expected credentials.
  1. AuthenticationException- Authentifizierungsausnahme
    1. DisabledAccountException Konto ist deaktiviert
    2. LockedAccountException-Konto ist gesperrt
    3. ExcessiveAttemptsException Übermäßige Anmeldefehler
    4. ExpiredCredentialsException Anmeldeinformationen abgelaufen

5. Autorisierungsprozess

1. Autorisierungsprozess

[Externer Link-Bildtransfer fehlgeschlagen, die Quellseite verfügt möglicherweise über einen Anti-Diebstahl-Link-Mechanismus, es wird empfohlen, das Bild zu speichern und direkt hochzuladen (img-eY7hr3cg-1682513591073) (G:\Desktop\Lektionsvorbereitung\Klasse\ssm\ Courseware Map\shiro Authorization Process.png )]

  1. Erstellen Sie einen Sicherheitsmanager
  2. Betreffberechtigung
  3. Die Berechtigung des Betreffs wird der Berechtigung des Sicherheitsmanagers erteilt
  4. Security Manager ruft die Authorizer-Autorisierung auf
  5. Erhalten Sie autorisierte Daten (Rollendaten und Berechtigungsdaten) in der Datenbank oder im Cache über Realm

2. Passen Sie den Bereich an, um die Autorisierung zu implementieren

​ Im obigen Einführungsfall haben wir den Authentifizierungsprozess mithilfe eines benutzerdefinierten Bereichs implementiert. Als Nächstes haben wir die Verwendung eines benutzerdefinierten Bereichs zur Implementierung der Autorisierung verbessert.

  1. Ändern Sie die Konfigurationsdatei von Shiro
<!-- 配置shiro的过滤器bean 执行授权检查相关功能,这里得先配上 -->
<bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
    <property name="securityManager" ref="securityManager"/>
    <!-- 配置shiro的过滤器bean 执行授权检查,
        敏感资源: web项目中就是一系列能访问操作数据库的url
        浏览器访问敏感资源,shiro过滤器拦截这次请求,执行授权检查,
        通过授权域realm对象来获取当前用户所具有的权限。
        哪些是敏感资源以及需要的身份,需要在此处定义 -->
    <!-- loginUrl配置:如果没有认证的用户访问敏感资源,将被shiro过滤器强制跳转到指定url资源 -->
    <property name="loginUrl" value="/sys/goLogin"/>
    <!-- 已认证的用户访问需要特定权限的敏感资源时,如果没有该特定权限时,将被shiro过滤器强制跳转到指定url资源 -->
    <property name="unauthorizedUrl" value="/unauthorized.jsp"/>
    <!-- 敏感资源及用户身份的定义-->
    <property name="filterChainDefinitions">
        <value>
            <!-- 过滤链的语法: 敏感资源的url = 身份     (一行写一个配置)
                      身份:    anon  匿名用户(未认证的用户)
                               authc 已通过认证的用户
                               user  曾经认证过的用户
                               roles[角色名]  拥有某个角色的用户
                               perms[权限名]  拥有某个权限的用户
                -->
            /sys/goLogin = anon     <!-- 匿名用户才能访问 -->
            /user/login = anon
            /user/logout = authc  <!-- 已认证的用户可以访问-->
            /sys/goMyself = roles[普通用户] <!-- 普通用户才能访问 -->
            /sys/goIndex = roles[管理员]  <!-- 管理员才能访问 -->
            /static/** = anon
            /* = authc       <!-- /** 根路径下的所有url包括子路径  /* 根路径下的一级中所有的url -->
            <!-- 授权时shiro过滤器会从上往下搜索过滤器链,找到一个url匹配就结束。
                   统配的资源一般写在靠下面位置
                -->
        </value>
    </property>
</bean>
  1. Ändern Sie die Autorisierungsmethode in MyShiroRealm
//获取授权信息,由开发者提供shiro框架已认证过用户的权限信息
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
    
    
    System.out.println("shiro来找我们获取授权信息了");
    //获取当前已认证(待授权用户)的用户的账号
    String username = (String)principals.getPrimaryPrincipal();
    // 查询该用户的角色或权限
    User user = userMapper.queryByUsername(username);
    Set<String> roles = new HashSet<>();
    if(user.getRoles() != null){
    
    
        //遍历用户的角色信息
        for(Role one:user.getRoles()){
    
    
            //角色名添加到role集合中
            roles.add(one.getRoleName());
        }
    }
    //查询用户的权限信息,留给同学们后续实现
    Set<String> perms = new HashSet<>();
    //创建授权信息对象
    SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
    //设置角色信息
    info.setRoles(roles);
    //设置权限信息
    info.setStringPermissions(perms);
    //返回授权信息对象
    return info;
}

Sechs, Shiro-Tag (JSP)

Shiro bietet eine Reihe von JSP-Tags, mit denen die Anzeige von UI-Elementen wie Menüs und Schaltflächen auf JSP-Seiten entsprechend den Autorisierungsinformationen des Benutzers gesteuert werden kann.

1. Etikett

Markenname Etikettenbedingungen (beide zeigen Etiketteninhalt an)
<shiro:authenticated> Vom Benutzer authentifiziert
<shiro:notAuthenticated> Nicht authentifizierter Benutzer
<shiro:guest> Wenn der Benutzer nicht authentifiziert ist
<shiro:user> Beim authentifizierten oder gespeicherten Benutzer
<shiro:hasAnyRoles name=“abc,123“ > Wenn ABC oder 123 Zeichen vorhanden sind
<shiro:hasRole name="abc"> Hat das Zeichen abc
<shiro:lacksRole name="abc"> kein Zeichen ABC
<shiro:hasPermission name="abc"> Hat die Berechtigungsressource abc
<shiro:lacksPermission name="abc"> Ressource ohne ABC-Berechtigung
<shiro:principal property=“username“> Benutzernamen anzeigen

1.1 Fall

  1. Erstellen Sie die Seite shiroTag.jsp
<%@ taglib prefix="shiro" uri="http://shiro.apache.org/tags" %>
<%@ page contentType="text/html;charset=UTF-8" language="java" isELIgnored="false" %>
<html>
<head>
    <title>shiroTag.jsp</title>
</head>
<body>
<!-- 根据当前用户身份,来决定是否展示标签体中的内容 -->
<shiro:guest>匿名用户可以看到</shiro:guest> <br>
<shiro:authenticated>认证过的用户可以看到</shiro:authenticated>
<shiro:hasAnyRoles name="管理员,普通用户">管理员或普通用户可以看到</shiro:hasAnyRoles>
<shiro:hasRole name="管理员">管理员才能看到</shiro:hasRole>
<shiro:hasRole name="普通用户">普通用户才能看到</shiro:hasRole>
</body>
</html>
  1. In der Shiro-Konfigurationsdatei gibt die Filterkette die Seite shiroTag.jsp frei
/jsp/shiroTag.jsp = anon

7. Verschlüsselung

1. Hash-Algorithmus

​ Hash-Algorithmen werden im Allgemeinen verwendet, um zusammenfassende Informationen für einen Text zu generieren. Hash-Algorithmen sind irreversibel und können eine Zusammenfassung des Inhalts erstellen, die Zusammenfassung jedoch nicht in den Originalinhalt umwandeln. Hash-Algorithmen werden häufig zum Hashen von Passwörtern verwendet. Zu den häufig verwendeten Hash-Algorithmen gehören MD5 und SHA. Der allgemeine Hash-Algorithmus muss ein Salz (Salz) und den ursprünglichen Inhalt bereitstellen, um zusammenfassende Informationen zu generieren. Dies dient der Sicherheit. Beispiel: Der MD5-Wert von 111111 lautet: 96e79218965eb72c92a549dd5a330112, es ist einfach, die MD5-Cracking-Website zu knacken mit „96e79218965eb72c92a549dd5a330112“, wenn Sie 111111 hashen und salzen möchten (Salz, eine Zufallszahl), sodass, obwohl alle Passwörter 111111 sind und unterschiedliche Salze unterschiedliche Hash-Werte erzeugen.

2. Verschlüsselungstools

  1. MD5Util-Verschlüsselungstoolklasse
public class MD5Util {
    
    
    public static String md5(String password, String salt){
    
    
        /*
            algorithmName代表进行加密的算法名称、
            source代表需要加密的元数据,如密码、
            salt代表盐,需要加进一起加密的数据、
            hashIterations代表hash迭代次数。
        * */
        return new SimpleHash("MD5", password, salt,1024).toString();
    }
}
  1. prüfen
@Test
public void applyMd5(){
    
    
    String password = "111";
    String slat = "admin";
    String hashedPassword = MD5Util.md5(password, slat);
    System.out.println(hashedPassword);
}
// 输出607a79936b28c5ddfe26940cf5980585

3. Authentifizierungsverschlüsselung

  1. Ändern Sie die Shiro-Konfigurationsdatei
<!-- 配置密码匹配器  散列的凭证匹配器 -->
<bean id="credentialsMatcher" class="org.apache.shiro.authc.credential.HashedCredentialsMatcher">
    <!-- 指定散列算法的细节  这里定义的算法和迭代次数需要和加密工具类定义的一致-->
    <property name="hashAlgorithmName" value="MD5"/>
    <property name="hashIterations" value="1024"/>
</bean>

<!-- 配置我们自定义realm类 bean-->
<bean id="myShiroRealm" class="com.hqyj.cl.utils.MyShiroRealm">
    <!-- 依赖注入我们定义的凭证匹配器,bean-->
    <property name="credentialsMatcher" ref="credentialsMatcher"/>
</bean>
  1. Ändern Sie die MyShiroRealm-Authentifizierungsmethode
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
    
    
    //使用token对象获取待登录用户的用户名
    String username = (String)token.getPrincipal();
    //从数据库中查询该username的用户的信息
    User user = userMapper.queryByUsername(username);
    System.out.println(user + "#AuthenticationInfo");
    //判断待登录用户是否存在
    if(user == null){
    
    
        throw new UnknownAccountException(username + "不存在");
    }
    //保存用户信息
    //获取shiro提供的当前用户的会话对象
    Session session = SecurityUtils.getSubject().getSession();
    //在shiro提供的会话对象中共享数据
    session.setAttribute("user", user);
    //创建一个SimpleAuthenticationInfo对象
    //三个参数: 1、用户名,2、数据库中用户的密码 3、realm的名称
    /* 使用4参数构造方法构造SimpleAuthenticationInfo对象
            SimpleAuthenticationInfo(Object principal,
             Object hashedCredentials,
             ByteSource credentialsSalt,
             String realmName)
         其中第二个参数:Object hashedCredentials 为散列过的用户密码
         其中第三个参数:ByteSource credentialsSalt 即为对用户密码散列时用到的salt,
         这里作为盐的字符串采用用户的账号名,与加密时使用的salt要一致才能认证成功
        */
    ByteSource salt = ByteSource.Util.bytes(user.getUsername());
    //返回AuthenticationInfo对象
    return new SimpleAuthenticationInfo(user.getUsername(),
                                        user.getPassword(), salt, getName());
}

Ich denke du magst

Origin blog.csdn.net/ailaohuyou211/article/details/130394419
Empfohlen
Rangfolge