Explicación detallada de Shiro (súper completa)

1. Introducción

  • El marco de seguridad de Shiro es un marco de seguridad potente y flexible proporcionado por Apache
  • El marco de seguridad de Shiro proporciona funciones relacionadas con la autenticación, la autorización, la gestión de sesiones empresariales, el cifrado y la gestión de caché. El uso de Shiro puede completar fácilmente el desarrollo de módulos de gestión de autoridad de proyectos.
  • Simple y flexible, se puede separar del resorte.

2. La estructura general de Shiro

inserte la descripción de la imagen aquí

1, Asunto

El Sujeto es el sujeto (el usuario actual puede entenderse como el sujeto). Las aplicaciones externas interactúan con el Sujeto. El Sujeto registra al usuario operativo actual y entiende el concepto del usuario como el sujeto de la operación actual. Puede ser un usuario solicitando a través de un navegador, o Probablemente un programa en ejecución. El sujeto es una interfaz en Shiro, que define muchos métodos relacionados con la autenticación y la autorización. Los programas externos realizan la autenticación y la autorización a través del Sujeto, y el Sujeto realiza la autenticación y la autorización a través del administrador de seguridad SecurityManager.

2, Administrador de seguridad

​ SecurityManager es el administrador de seguridad, que gestiona la seguridad de todos los Sujetos. Es el núcleo de Shiro y es responsable de la gestión de la seguridad de todos los Sujetos. A través del SecurityManager se puede completar la autenticación y autorización del Sujeto, en esencia, el SecurityManager se autentica a través del ** Autenticador , se autoriza a través del Autorizador **, y la gestión de sesiones a través del SessionManager.

​ SecurityManager es una interfaz que hereda las tres interfaces de Authenticator, Authorizer y SessionManager.

3, criptografía

​La criptografía es la gestión de contraseñas. Shiro proporciona un conjunto de componentes de cifrado/descifrado para facilitar el desarrollo. Por ejemplo, proporciona funciones comunes como hashing y cifrado/descifrado.

4, autenticador

Authenticator es un autenticador que autentica las identidades de los usuarios. Authenticator es una interfaz. Shiro proporciona la clase de implementación ModularRealmAuthenticator. ModularRealmAuthenticator básicamente puede satisfacer la mayoría de las necesidades, y también puede personalizar el autenticador.

5, Autorizador

El autorizador es el autorizador. El usuario pasa la autenticación a través del autenticador. Al acceder a la función, necesita usar el autorizador para juzgar si el usuario tiene la autoridad de operación de esta función.

6, reino

​ Realm es un reino, que es equivalente a una fuente de datos de origen de datos. SecurityManager necesita obtener datos de permisos de usuario a través de Realm para la autenticación de seguridad. Por ejemplo, si los datos de identidad del usuario están en la base de datos, Realm necesita obtener la información de identidad del usuario de la base de datos. .

​Nota : no entienda que el reino es simplemente obtener datos de la fuente de datos, hay códigos relacionados para la autenticación y verificación de autorización en el reino.

7, administrador de sesión

sessionManager es la gestión de sesiones. El marco Shiro define un conjunto de gestión de sesiones. No depende de la sesión del contenedor web, por lo que Shiro se puede utilizar en aplicaciones no web y también puede centralizar la gestión de sesiones de aplicaciones distribuidas. Esta función puede hacer que implemente el inicio de sesión único.

8, SesiónDAO

​ SessionDAO es un dao de sesión, que es un conjunto de interfaces para operaciones de sesión. Por ejemplo, si desea almacenar la sesión en la base de datos, puede almacenar la sesión en la base de datos a través de jdbc.

9, administrador de caché

​ CacheManager es la administración de caché, que almacena datos de permisos de usuario en el caché, lo que puede mejorar el rendimiento.

3. Caso introductorio

Este caso se basa en la integración del marco SSM

  1. importar dependencias
<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. crear mesa
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. Crear clases de entidad Usuario y Rol
@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. Interfaz de UserMapper
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. Interfaz de servicio de usuario
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. Controlador de usuario
@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. MiReinoShiro
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. archivo de configuración de shiro
<?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. Importe el archivo de configuración de shiro en applicationContext y deje que Spring lo administre
<import resource="spring-shiro.xml"/>
  1. Configurar filtro shiro 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. iniciar sesión.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. Proceso de certificación

1. Proceso de certificación

diagrama de flujo de autenticación shiro
  1. Cree un token token, que contenga la información de autenticación enviada por el usuario, es decir, el número de cuenta y la contraseña;

  2. Ejecute subject.login(token), y finalmente el administrador de seguridad se autentica a través del autenticador;

  3. Implementación del autenticador ModularRealmAuthenticator llama a MyShiroRealm para obtener la cuenta real y la contraseña del usuario en el sistema;

  4. MyShiroRealm primero busca la cuenta en el sistema de acuerdo con la cuenta en el token y arroja una UnknownAccountException si no puede encontrarla. Si lo encuentra, devuelva AuthenticationInfo (incluida la contraseña real);

  5. El autenticador hace coincidir la contraseña de acuerdo con la información de autenticación devuelta por el dominio. Si falla, se lanza una excepción de credenciales incorrectas. Si tiene éxito, la autenticación pasa.

2. Excepciones comunes

  1. UnknownAccountException La cuenta no existe anormalmente
org.apache.shiro.authc.UnknownAccountException: No account found for user...
  1. IncorrectCredentialsException Excepción de error de contraseña de entrada
org.apache.shiro.authc.IncorrectCredentialsException: Submitted credentials for token [org.apache.shiro.authc.UsernamePasswordToken - zhangsan, rememberMe=false] did not match the expected credentials.
  1. excepción de autenticación AuthenticationException
    1. DisabledAccountException La cuenta está deshabilitada
    2. La cuenta LockedAccountException está bloqueada
    3. ExcessiveAttemptsException Errores de inicio de sesión excesivos
    4. ExpiredCredentialsException Credenciales caducadas

5. Proceso de autorización

1. Proceso de autorización

[Error en la transferencia de la imagen del enlace externo, el sitio de origen puede tener un mecanismo de enlace antirrobo, se recomienda guardar la imagen y cargarla directamente (img-eY7hr3cg-1682513591073) (G:\Desktop\Lesson Preparation\Class\ssm\ Courseware Map\shiro Authorization Process.png )]

  1. Crear administrador de seguridad
  2. Autorización de sujeto
  3. La autorización del sujeto se otorga a la autorización del administrador de seguridad
  4. El administrador de seguridad llama a la autorización del autorizador
  5. Obtenga datos autorizados (datos de roles y datos de permisos) en la base de datos o caché a través de Realm

2. Personaliza el reino para implementar la autorización

En el caso introductorio anterior, implementamos el proceso de autenticación mediante un dominio personalizado. A continuación, mejoramos el uso de un dominio personalizado para implementar la autorización.

  1. Modificar el archivo de configuración de 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. Modificar el método de autorización en 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;
}

Seis, etiqueta shiro (JSP)

Shiro proporciona una serie de etiquetas jsp, que se pueden usar para controlar la visualización de elementos de la interfaz de usuario, como menús y botones en páginas jsp, de acuerdo con la información de autorización del usuario.

1. Etiqueta

Nombre de etiqueta Condiciones de la etiqueta (ambos muestran el contenido de la etiqueta)
<shiro:autenticado> Autenticado por el usuario
<shiro:no autenticado> Usuario no autenticado
<shiro:invitado> Cuando el usuario no está autenticado
<shiro:usuario> Cuando usuario autenticado o recordado
<shiro:tieneCualquierRol nombre=“abc,123” > Cuando hay abc o 123 caracteres
<shiro:hasRole name=“abc”> Tiene el caracter abc
<shiro:lacksRole name=“abc”> sin carácter abc
<shiro:tiene permiso nombre=“abc”> Tiene permiso recurso abc
<shiro:faltaPermiso nombre=“abc”> Recurso sin permiso abc
<shiro:propiedad principal=“nombre de usuario”> mostrar nombre de usuario

1.1 Caso

  1. Crear página 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. En el archivo de configuración de shiro, la cadena de filtros libera la página shiroTag.jsp
/jsp/shiroTag.jsp = anon

7. Cifrado

1. Algoritmo hash

Los algoritmos hash se utilizan generalmente para generar información de resumen para un fragmento de texto. Los algoritmos hash son irreversibles y pueden generar un resumen del contenido, pero no pueden convertir el resumen en el contenido original. Los algoritmos hash a menudo se usan para codificar contraseñas, y los algoritmos hash comúnmente usados ​​incluyen MD5 y SHA. El algoritmo hash general necesita proporcionar una sal (sal) y el contenido original para generar información resumida. El propósito de esto es por seguridad. Por ejemplo, el valor md5 de 111111 es: 96e79218965eb72c92a549dd5a330112. Es fácil descifrar el sitio web de descifrado md5 con "96e79218965eb72c92a549dd5a330112", si desea codificar 111111 y sal (sal, un número aleatorio), aunque las contraseñas son todas 111111 más diferentes sales generarán diferentes valores de hash.

2. Herramientas de cifrado

  1. Clase de herramienta de cifrado MD5Util
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. prueba
@Test
public void applyMd5(){
    
    
    String password = "111";
    String slat = "admin";
    String hashedPassword = MD5Util.md5(password, slat);
    System.out.println(hashedPassword);
}
// 输出607a79936b28c5ddfe26940cf5980585

3. Cifrado de autenticación

  1. Modificar el archivo de configuración de shiro
<!-- 配置密码匹配器  散列的凭证匹配器 -->
<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. Modificar el método de autenticación de MyShiroRealm
@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());
}

Supongo que te gusta

Origin blog.csdn.net/ailaohuyou211/article/details/130394419
Recomendado
Clasificación