• shiro集成 spring-加密md5配置--权限管理-shiro中的session 等等!!


    目录

    1.shiro集成 spring

    1.1 导入依赖的包

    1.2 web.xml配置

    2. 开发自定义Realm

    2.1 创建测试数据表

    2.3 编写后台支持服务

    2.4 编写自定义的Realm

    2.5配置文件 放入spring 中

    2.6登录Controller

    3.权限管理 登录后

    1. 自定义Realm 此处上面的Realm中已有代码

    2.权限标签

    3. 使用注解控制权限

    3.1 springMVC配置

    4.2 注解权限验证失败不跳转路径问题

    4. shiro中的缓存

    1.1 引入需要的第三方包

    1.2 ehcache配置文件

    1.2 配置spring的配置文件

    2. shiro中的session

    2.1 shiro中的session特点和常用方法

    2.2 如何使用

    2.3 Session监听

    2.4 SessionDao 将数据报错数据库 让后同步数据


    1.shiro集成 spring

    1.1 导入依赖的包

    导入shiro需要的依赖包

    1. <shiro-version>1.2.5shiro-version>
    2. <dependency>    
    3.    <groupId>org.apache.shirogroupId>    
    4.    <artifactId>shiro-coreartifactId>    
    5.    <version>${shiro-version}version>
    6. dependency>
    7.    <dependency>    
    8.    <groupId>org.apache.shirogroupId>    
    9.    <artifactId>shiro-webartifactId>    
    10.    <version>${shiro-version}version>
    11.    dependency>
    12. <dependency>    
    13.    <groupId>org.apache.shirogroupId>    
    14.    <artifactId>shiro-springartifactId>    
    15.    <version>${shiro-version}version>
    16. dependency>

    1.2 web.xml配置

    1. <filter>    
    2.    <filter-name>shiroFilterfilter-name>    
    3.    <filter-class>org.springframework.web.filter.DelegatingFilterProxyfilter-class>
    4. filter>
    5. <filter-mapping>    
    6.    <filter-name>shiroFilterfilter-name>    
    7.    <url-pattern>/*url-pattern>
    8. filter-mapping>

    2. 开发自定义Realm

    2.1 创建测试数据表

    获取地址:shiro测试数据 密码:3kvh

    创建好 实体 model

     

    2.3 编写后台支持服务

    用户 mapper 接口 编写

    1. package com.zking.shiro.mapper;
    2. import com.zking.shiro.model.User;
    3. import org.springframework.stereotype.Repository;
    4. import java.util.Set;
    5. @Repository
    6. public interface IUserMapper {
    7.    /**
    8.     * 用户登录功能
    9.     * @param us
    10.     * @return
    11.     */
    12.  User login(User us);
    13.    /**
    14.     * 获取用户信息
    15.     * @param userName
    16.     * @return
    17.     */
    18.  Set<String> getRolesByUserName(String userName);
    19.    /**
    20.     * 通过用户名称获取权限信息
    21.     * @param userName
    22.     * @return
    23.     */
    24.    Set<String> getPermissionsByUserName(String userName);
    25. }

    用户 mybatis xml文件

    1. "1.0" encoding="UTF-8" ?>
    2. mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
    3. <mapper namespace="com.zking.shiro.mapper.IUserMapper">
    4.    <select id="login" resultType="com.zking.shiro.model.User">
    5. select user_id userId,username userName,password ,salt,locked,create_datetime createDatetime from t_sys_user
    6.       <where>
    7.           username = #{userName}
    8.       where>
    9.    select>
    10.    <select id="getRolesByUserName" resultType="java.lang.String">
    11.       SELECT t2.role_name
    12.       FROM `t_sys_user` t join t_sys_user_role t1 on t.user_id =t1.user_id join t_sys_role t2 on t1.role_id = t2.role_id
    13.       <where>
    14.           t.username= #{userName}
    15.       where>
    16.    select>
    17.    <select id="getPermissionsByUserName" resultType="java.lang.String">
    18.       SELECT t4.permission
    19.       FROM `t_sys_user` t join t_sys_user_role t1 on t.user_id =t1.user_id join t_sys_role t2 on t1.role_id = t2.role_id join
    20.             t_sys_role_permission t3 on t2.role_id = t3.role_id join t_sys_permission
    21.           t4 on t3.permission_id=t4.permission_id
    22.        <where>
    23.           t.username= #{userName}
    24.        where>
    25.    select>
    26. mapper>

    编写 service 省略

    2.4 编写自定义的Realm

    shiro中的Realm UML:

    1. package com.zking.shiro.shiro;
    2. import com.zking.shiro.model.User;
    3. import com.zking.shiro.service.IUserService;
    4. import org.apache.shiro.authc.*;
    5. import org.apache.shiro.authz.AuthorizationInfo;
    6. import org.apache.shiro.authz.SimpleAuthorizationInfo;
    7. import org.apache.shiro.realm.AuthorizingRealm;
    8. import org.apache.shiro.subject.PrincipalCollection;
    9. import org.apache.shiro.util.ByteSource;
    10. import org.springframework.beans.factory.annotation.Autowired;
    11. import java.util.Objects;
    12. public class CustomerRealm extends AuthorizingRealm {
    13.    @Autowired
    14.    private IUserService userService;
    15.    /**
    16.     * 提供授权信息
    17.     * @param principalCollection
    18.     * @return
    19.     */
    20.    @Override
    21.    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
    22.        
    23.        String username =principalCollection.getPrimaryPrincipal().toString();
    24.        SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
    25.        //放入用户信息 用户身份
    26.        info.setRoles(userService.getRolesByUserName(username));
    27.        //获取用户所拥有的权限
    28.        info.setStringPermissions(userService.getPermissionsByUserName(username));
    29.        return info;
    30.   }
    31.    /**
    32.     * 提供认证信息
    33.     * @param authenticationToken
    34.     * @return
    35.     * @throws AuthenticationException
    36.     */
    37.    @Override
    38.    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
    39.        String username =authenticationToken.getPrincipal().toString();
    40.        User user = new User();
    41.        user.setUserName(username);
    42.        User db_login = userService.login(user);
    43.        if(Objects.isNull(db_login)){
    44.         throw new UnknownAccountException("用户 :" +username +"不存在");
    45.       }
    46.        //这里 可以写死 为 1 此处在用户实体中定义了一个常量
    47.       if(db_login.getLocked() == User.USER_LOCKED){
    48.           throw new LockedAccountException("用户 :" +username +"被锁定");
    49.       }
    50.        //此处考虑了加密 所以我们需要准备 md5 的加密
    51.        //告诉 shiro 我的md5 加密盐为 ByteSource.Util.bytes(db_login.getSalt())
    52.        SimpleAuthenticationInfo simpleAuthenticationInfo = new SimpleAuthenticationInfo(db_login.getUserName(), db_login.getPassword(), ByteSource.Util.bytes(db_login.getSalt()),this.getName());
    53.        return simpleAuthenticationInfo;
    54.   }
    55. }
    56.  

    2.5配置文件 放入spring 中

    1.  
    2.    <bean id="customerRealm" class="com.zking.shiro.shiro.CustomerRealm">
    3.        <property name="credentialsMatcher">
    4.            <bean id="credentialsMatcher" class="org.apache.shiro.authc.credential.HashedCredentialsMatcher">
    5.                
    6.                <property name="hashAlgorithmName" value="md5"/>
    7.                
    8.                <property name="hashIterations" value="1024"/>
    9.                
    10.                <property name="storedCredentialsHexEncoded" value="true"/>
    11.            bean>
    12.        property>
    13.    bean>
    14. <bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
    15.    <property name="realm" ref="customerRealm"/>
    16. bean>
    17.    
    18.    <bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
    19.        
    20.        <property name="securityManager" ref="securityManager" />
    21.        
    22.        <property name="loginUrl" value="/"/>
    23.        
    24.        
    25.        
    26.        
    27.        
    28.        <property name="filterChainDefinitions">
    29.            <value>
    30.                
    31.                
    32.                
    33.                
    34.               /user/login=anon
    35.               /book/**=authc
    36.               /common/**=authc
    37.                
    38.            value>
    39.        property>
    40.    bean>
    41.    
    42.    <bean id="lifecycleBeanPostProcessor" class="org.apache.shiro.spring.LifecycleBeanPostProcessor"/>

    md5加密

    注: MD5 MD5信息摘要算法(英语:MD5 Message-Digest Algorithm),一种被广泛使用的密码散列函数,可以产生出一个128位(16字节)的散列值(hash value),用于确保信息传输完整一致。MD5算法是不可逆的,即便得到了加密以后的密文,也不可能通过解密算法反算出明文。 用途: 1)密码管理,如用户密码的MD5加密后再保存数据库 2)电子签名,MD5 算法还可以作为一种电子签名的方法来使用,使用 MD5算法就可以为任何文件(不管其大小、格式、数量)产生一个独一无二的“数字指纹”,借助这个“数字指纹”,通过检查文件前后 MD5 值是否发生了改变,就可以知道源文件是否被改动。(回想一下JWT的令牌签名)

    2.6登录Controller

    1. package com.zking.shiro.controller;
    2. import com.sun.prism.impl.shape.ShapeUtil;
    3. import com.zking.shiro.model.User;
    4. import com.zking.shiro.service.IUserService;
    5. import com.zking.shiro.utils.RetrunData;
    6. import org.apache.shiro.SecurityUtils;
    7. import org.apache.shiro.authc.AuthenticationException;
    8. import org.apache.shiro.authc.LockedAccountException;
    9. import org.apache.shiro.authc.UnknownAccountException;
    10. import org.apache.shiro.authc.UsernamePasswordToken;
    11. import org.apache.shiro.authz.annotation.RequiresPermissions;
    12. import org.apache.shiro.subject.Subject;
    13. import org.springframework.beans.factory.annotation.Autowired;
    14. import org.springframework.stereotype.Controller;
    15. import org.springframework.ui.Model;
    16. import org.springframework.web.bind.annotation.RequestMapping;
    17. import org.springframework.web.bind.annotation.ResponseBody;
    18. import javax.servlet.http.HttpSession;
    19. import java.util.HashMap;
    20. @Controller
    21. /* 访问时 需要添加 user */
    22. //@RequestMapping("/user")
    23. public class UserController {
    24.    @RequestMapping("/")
    25.    public String index(){
    26.        return "login";
    27.   }
    28.   @RequestMapping("/user/login")
    29.    public String login(User us, Model model, HttpSession session){
    30.        Subject subject= SecurityUtils.getSubject();
    31.        UsernamePasswordToken passwordToken =new            UsernamePasswordToken(us.getUserName(), us.getPassword());
    32.        try{
    33.            subject.login(passwordToken);
    34.       }catch (UnknownAccountException | LockedAccountException e){
    35.            model.addAttribute("message",e.getMessage());
    36.           return "login";
    37.         }catch (AuthenticationException e){
    38.            model.addAttribute("message","账号或密码错误");
    39.            return "login";
    40.       }
    41.        session.setAttribute("user",us);
    42.        return "index";
    43.   }
    44. }

    登录界面 注意此处 可能 会有所不同

    1.  
    2. <%--
    3.  Created by IntelliJ IDEA.
    4.  User: lisensir
    5.  Date: 2022/6/22
    6.  Time: 22:20
    7.  To change this template use File | Settings | File Templates.
    8. --%>
    9. <%@ page contentType="text/html;charset=UTF-8" language="java" %>
    10. <%@ page pageEncoding="utf-8" %>
    11. <html>
    12. <head>
    13.    <title>Titletitle>
    14. head>
    15. <body>
    16. <h1>登录页面h1>
    17. ${message}
    18. <form id="loginForm" action="<%=request.getContextPath()%>/user/login" method="post">
    19.    <input type="text" id="userName" name="userName"/> <br/>
    20.    <input type="text" id="password" name="password"/>  <br/>
    21.    <input type="submit" value="登录"/>
    22. form>
    23. body>
    24. html>

    3.权限管理 登录后

    1. 自定义Realm 此处上面的Realm中已有代码

    2.权限标签

    2.1 引入标签库

    <%@taglib prefix="shiro" uri="Taglib | Apache Shiro" %>

    Shiro标签库 guest标签 :验证当前用户是否为“访客”,即未认证(包含未记住)的用户 user标签 :认证通过或已记住的用户 authenticated标签 :已认证通过的用户。不包含已记住的用户,这是与user标签的区别所在 notAuthenticated标签 :未认证通过用户,与authenticated标签相对应。与guest标签的区别是,该标签包含已记住用户 principal 标签 :输出当前用户信息,通常为登录帐号信息 hasRole标签 :验证当前用户是否属于该角色 lacksRole标签 :与hasRole标签逻辑相反,当用户不属于该角色时验证通过 hasAnyRole标签 :验证当前用户是否属于以下任意一个角色 hasPermission标签 :验证当前用户是否拥有指定权限 lacksPermission标签 :与hasPermission标签逻辑相反,当前用户没有制定权限时,验证通过

    2.2 使用标签控制权限

    注:只是用于演示权限标签,如果有权限则显示功能连接,否则不显示,所以并没有指定具体的链接。

     

    1. <%--
    2.  Created by IntelliJ IDEA.
    3.  User: lisensir
    4.  Date: 2022/6/23
    5.  Time: 11:09
    6.  To change this template use File | Settings | File Templates.
    7. --%>
    8. <%@ page contentType="text/html;charset=UTF-8" language="java" %>
    9. <%@ taglib prefix="s" uri="http://shiro.apache.org/tags" %>
    10. <html>
    11. <head>
    12.    <title>Titletitle>
    13. head>
    14. <body>
    15. <s:hasRole name="admin">
    16. <h1>管理员h1>
    17. s:hasRole>
    18. <s:hasPermission name="system:dict:view">
    19. <li><a href="#">书本查询a>li>
    20. s:hasPermission>
    21. <s:hasPermission name="system:dict:add">
    22.    <li><a href="#">书本新增a>li>
    23. s:hasPermission>
    24. <s:hasPermission name="bookmanager:book:edit">
    25.    <li><a href="#">书本修改a>li>
    26. s:hasPermission>
    27. <s:hasPermission name="bookmanager:book:del">
    28.    <li><a href="#">书本删除a>li>
    29. s:hasPermission>
    30. <a href="<%=request.getContextPath()%>/userRealm">测试a>
    31. body>
    32. html>

    权限需要根据数据库 查看

    3. 使用注解控制权限

    常用注解: @RequiresAuthenthentication:表示当前Subject已经通过login进行身份验证;即 Subject.isAuthenticated()返回 true @RequiresUser:表示当前Subject已经身份验证或者通过记住我登录的 @RequiresGuest:表示当前Subject没有身份验证或者通过记住我登录过,即是游客身份 @RequiresRoles(value = {"admin","user"},logical=Logical.AND):表示当前Subject需要角色admin和user @RequiresPermissions(value = {"user:delete","user:b"},logical = Logical.OR):表示当前Subject需要权限user:delete或者user:b

    3.1 springMVC配置

    开启注解,必须将Shiro注解的开启放置到spring-mvc.xml中(即放在springMVC容器中加载),否则Shiro注解开启无效

     
    
    1.  <bean class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator"
    2.      depends-on="lifecycleBeanPostProcessor">
    3.    <property name="proxyTargetClass" value="true">property>
    4. bean>
    5. <bean class="org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor">
    6.    <property name="securityManager" ref="securityManager"/>
    7. bean>

     

    在Controller中加入用于演示的请求处理器:

     

    在index.jsp中加入功能连接,用于演示权限控制。

     

    4.2 注解权限验证失败不跳转路径问题

    问题原因:由于我们架构是用springmvc框架来搭建的所以项目的路径跳转是由springmvc 来控制的,也就是说我们在shiro里面的配置没有用

     

    解决 springmvc中有一个org.springframework.web.servlet.handler.SimpleMappingExceptionResolver类就可以解决这个问题

    1. <bean id="exceptionResolver" class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver">
    2.    <property name="exceptionMappings">
    3.        <props>
    4.            <prop key="org.apache.shiro.authz.UnauthorizedException">
    5.               unauthorized
    6.            prop>
    7.        props>
    8.    property>
    9.  bean>

    编写一个用于提示没有权限的页面,页面名称为unauthorized,与上面的配置文件中配置的保持一致,、

    1. <%--
    2.  Created by IntelliJ IDEA.
    3.  User: lkf
    4.  Date: 2022/9/6
    5.  Time: 19:13
    6.  To change this template use File | Settings | File Templates.
    7. --%>
    8. <%@ page contentType="text/html;charset=UTF-8" language="java" %>
    9. <html>
    10. <head>
    11.    <title>Titletitle>
    12. head>
    13. <body>
    14. <h1> 权限不足 h1>
    15. body>
    16. html>

    4. shiro中的缓存

    在权限验证时每次从数据库中获取权限数据显然是不合适的,更合适方式是将数据缓存到内存,以提高系统性能,shiro中可以方便的配置缓存,具体的配置如下:

    1.1 引入需要的第三方包

    1. <dependency>
    2. <groupId>org.apache.shirogroupId>
    3. <artifactId>shiro-coreartifactId>
    4. <version>${shiro-version}version>
    5. dependency>
    6. <dependency>
    7. <groupId>org.apache.shirogroupId>
    8. <artifactId>shiro-webartifactId>
    9. <version>${shiro-version}version>
    10. dependency>
    11. <dependency>
    12. <groupId>org.apache.shirogroupId>
    13. <artifactId>shiro-springartifactId>
    14. <version>${shiro-version}version>
    15. dependency>
    16.        
    17.        <dependency>
    18.            <groupId>org.apache.shirogroupId>
    19.            <artifactId>shiro-ehcacheartifactId>
    20.            <version>${shiro-version}version>
    21.        dependency>
    22.        <dependency>
    23.            <groupId>org.springframeworkgroupId>
    24.            <artifactId>spring-context-supportartifactId>
    25.            <version>${spring-version}version>
    26.        dependency>

    1.2 ehcache配置文件

    1. "1.0" encoding="UTF-8"?>
    2. <ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    3.         xsi:noNamespaceSchemaLocation="http://ehcache.org/ehcache.xsd"
    4.         updateCheck="false">
    5.    <diskStore path="java.io.tmpdir"/>
    6.    
    7.    <defaultCache eternal="false" maxElementsInMemory="1000" overflowToDisk="false" diskPersistent="false"
    8.                  timeToIdleSeconds="0" timeToLiveSeconds="600" memoryStoreEvictionPolicy="LRU"/>
    9.    
    10.  
    11. ehcache>

     

    1.2 配置spring的配置文件

    1. <bean id="cacheManagerFactory" class="org.springframework.cache.ehcache.EhCacheManagerFactoryBean">
    2. <property name="configLocation" value="classpath:ehcache.xml"/>
    3. <property name="shared" value="true">property>
    4. bean>
    5. <bean id="shrioEhcache" class="org.apache.shiro.cache.ehcache.EhCacheManager">
    6. <property name="cacheManager" ref="cacheManagerFactory">property>
    7. bean>
    8. //此安全管理器 上方配置文件中 已经带有 只需要 把下面的缓存配置 加进去即可
    9. <bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
    10. <property name="realm" ref="shiroRealm" />
    11.    
    12. <property name="cacheManager" ref="shrioEhcache">property>
    13. bean>

    2. shiro中的session

    2.1 shiro中的session特点和常用方法

    shiro的session和httpsession概念上是相同的,指定都是客户端和服务器之间的一次会话。 shiro的session的特点如下:

    • 不依赖于底层的容器(比如Tomcat),httpsession是依赖于底层容器的,这意味中shiro的session可以脱离容器使用

    • 提供了会话管理,会话监听,会话存储等功能, 可以支持会话过期,实现单点登录等。

    常用的方法: Subject.getSession(true/false) 获取session,如果为参数为true,则没有session时会创建session,如果为false则没有session返回空 session.getId() 获取当前会话的ID号 session.getHost() 获取当权会话的主机地址 session.getTimeout() 获取过期时间 session.setTimeout() 设置当前时间 session.getStartTimestamp() 获取会话启动的时间戳 session.getLastAccessTime() 获取会话的最后访问时间 session.touch() 更新最后一次访问时间 session.stop() 销毁会话 session.setAttribute(kay,val) session.getAttribute(key) session.removeAttribute(key)

    shiro中的session也提供了监听器,和HttpSessionListener类似,提供如下方法: onStart() -- 监听启动事件 onStop() -- 监听停止事件 onExpiration() -- 监听过期事件

    2.2 如何使用

    shiro中的session使用起来非常简单,通过设置在中的数据,可以在Shiro的Session中直接获取 通过 shiro中的session保存的数据 通过 HttpSession 也一样可以获取

    1. @PostMapping("/user")
    2.    public String getUser(User user, Model model, HttpSession session) {
    3.        session.setAttribute("uname", user.getUsername());
    4.        //两者都同步数据
    5. System.out.println(session.getAttribute("us"));
    6. ...
    7. }
    1. @Service
    2. public class SessionService implements ISessionService {
    3.    @Override
    4.    public void testSession() {
    5. //在service中通过Subject获取session使用,这里的uname属性是通过HttpSession类设置的
    6.        Session session = SecurityUtils.getSubject().getSession();
    7.        System.out.println("===== session : " + session.getAttribute("uname"));
    8.          SecurityUtils.getSubject().getSession().setAttribute("us","haoya");
    9.   }
    10. }

    如何验证缓存配置的有效性:

    • 首先不配置缓存,在自定义的Realm中输出一些提示信息,启动服务后会发现每次调用登录,或其他配置了权限认证的功能,都会输出提示信息

    • 配置缓存,然后重新运行相同的通过,查看后台,加载一次后及不会再有输出

    2.3 Session监听

    用于监听session的创建,过期等事件,如果在需要时可以再session创建时做些初始化操作,或在过期时做些清理操作。

    1) 创建一个自定义监听器

    1. @Slf4j
    2. public class SessionListener extends SessionListenerAdapter {
    3.    @Override
    4.    public void onStart(Session session) {
    5.        log.info("Shiro session onStart .... ");
    6.   }
    7.    @Override
    8.    public void onStop(Session session) {
    9.        log.info("Shiro session onStop .... ");
    10.   }
    11.    @Override
    12.    public void onExpiration(Session session) {
    13.        log.info("Shiro session onExpiration ....");
    14.   }
    15. }

    2)配置文件,在spring配置文件中做如下配置

    1.    <bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
    2.        <property name="realm" ref="shiroRealm" />
    3.        
    4.        <property name="cacheManager" ref="shrioEhcache"/>
    5.       //只需要在 shiro的安全管理器中配置 下一条即可  
    6.        
    7.        <property name="sessionManager" ref="sessionManager"/>
    8.    bean>
    9.    
    10.    <bean id="sessionManager" class="org.apache.shiro.web.session.mgt.DefaultWebSessionManager">
    11.        <property name="sessionListeners">
    12.            <list>
    13.               //此路径 需要配置你在及项目中过滤器
    14.                <bean class="com.zking.shirodemo.listener.SessionListener"/>
    15.            list>
    16.        property>
    17.    bean>

    2.4 SessionDao 将数据报错数据库 让后同步数据

     

    首先先编写 数据访问层 mapper 接口定义

    1. package com.zking.shiro.mapper;
    2. import com.zking.shiro.model.SessionModel;
    3. import org.springframework.stereotype.Repository;
    4. @Repository
    5. public interface ISessionMapper {
    6.    void addSession(SessionModel session);
    7.    SessionModel getSession(SessionModel session);
    8.    void delSession(SessionModel session);
    9.    void updateSession(SessionModel session);
    10. }

    xml 实现

    1. "1.0" encoding="UTF-8" ?>
    2. mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
    3. <mapper namespace="com.zking.shiro.mapper.ISessionMapper">
    4.    <insert id="addSession">
    5.       insert into t_sys_session(session_id,session) values (#{sessionid},#{session})
    6.    insert>
    7.    <update id="updateSession">
    8.       update t_sys_session <set>
    9.        <if test="session != null">
    10.           session = #{session}
    11.        if>
    12.    set>
    13.    <where>
    14.       and session_id=#{sessionid}
    15.    where>
    16.    update>
    17.    <delete id="delSession">
    18.       delete from t_sys_session where session_id=#{sessionid}
    19.    delete>
    20.    <select id="getSession" resultType="com.zking.shiro.model.SessionModel">
    21.       select id,session_id sessionid,session from t_sys_session where session_id= #{sessionid}
    22.    select>
    23. mapper>

    自行编写 service 层 !!!!

     

    实现自定义SessionDao的步骤:

    • 编写自定义的SessionDao,集成自EnterpriseCacheSessionDao

    • 增删改查

    • 保存方式选择了json 下方有工具包 代码

    1. package com.zking.shiro.listener;
    2. import com.zking.shiro.model.SessionModel;
    3. import com.zking.shiro.service.ISessionService;
    4. import com.zking.shiro.utils.JsonUtils;
    5. import lombok.extern.slf4j.Slf4j;
    6. import org.apache.shiro.session.Session;
    7. import org.apache.shiro.session.mgt.eis.EnterpriseCacheSessionDAO;
    8. import org.apache.shiro.subject.support.DefaultSubjectContext;
    9. import org.springframework.beans.factory.annotation.Autowired;
    10. import java.io.Serializable;
    11. import java.util.Objects;
    12. /**
    13. * 自定义Session持久化,将Shiro的Session数据保存到数据库中。
    14. * 完成该类的编写后,需要在spring配置文件中进行配置
    15. */
    16. @Slf4j
    17. public class DbSessionDao extends EnterpriseCacheSessionDAO {
    18.    @Autowired
    19.    private ISessionService service;
    20.    @Override
    21.    protected Serializable doCreate(Session session) {
    22.        Serializable sid = super.doCreate(session);
    23.        SessionModel sessionModel = new SessionModel();
    24.        sessionModel.setSessionid(sid.toString());
    25.        //把session转为json保存
    26.        sessionModel.setSession(JsonUtils.toJson(session));
    27.        log.debug("将session保存到数据库, sessionId = {}", sid);
    28.        service.addSession(sessionModel);
    29.        return sid;
    30.   }
    31.    @Override
    32.    protected Session doReadSession(Serializable sessionId) {
    33.        Session session = super.doReadSession(sessionId);
    34.        //如果从内存中获取了session,则直接返回
    35.        if (!Objects.isNull(session)) {
    36.            log.debug("从内存中获取session,sessionId = " + sessionId + ", 直接返回");
    37.            return session;
    38.       }
    39.        log.debug("从内存中没有获取到session,id={}, 将从数据库获取session", sessionId);
    40.        SessionModel model = new SessionModel();
    41.        model.setSessionid(sessionId.toString());
    42.        SessionModel session1 = service.getSession(model);
    43.        if(Objects.isNull(session1)) {
    44.            log.debug("数据库中也没有找到id={}的session,将返回null");
    45.            return session;
    46.       }
    47.        session  = (Session) JsonUtils.toJson(session1.getSession(),Session.class);
    48.        return session;
    49.   }
    50.    @Override
    51.    protected void doDelete(Session session) {
    52.        SessionModel model=new SessionModel();
    53.        model.setSessionid(session.getId().toString());
    54.        log.debug("删除session,sessionId: " + session.getId().toString());
    55.        service.delSession(model);
    56.        super.doDelete(session);
    57.   }
    58.    @Override
    59.    protected void doUpdate(Session session) {
    60.        String sessionId = session.getId().toString();
    61.        SessionModel tmpModel = new SessionModel();
    62.        tmpModel.setSessionid(sessionId);
    63.        SessionModel model = service.getSession(tmpModel);
    64.        if(Objects.isNull(model)) {
    65.            //检查 session 是否 有效 无效 就不加入数据库
    66.            Object obj = session.getAttribute(DefaultSubjectContext.AUTHENTICATED_SESSION_KEY);
    67.            //数据库中是否有session,如果没有检查session无效,则直接返回,否则保存到数据库中
    68.            if(Objects.isNull(obj) || !Boolean.parseBoolean(obj.toString())) {
    69.                return ;
    70.           }
    71.            SessionModel saveModel = new SessionModel();
    72.            saveModel.setSessionid(session.getId().toString());
    73.            saveModel.setSession(JsonUtils.toJson(session));
    74.            log.debug("session已经过验证,且在数据库中不存在,将session保存到数据库 ..... ");
    75.            service.addSession(saveModel);
    76.       } else {
    77.            //如果session在数据库中已存在,则更新session
    78.            model.setSession(JsonUtils.toJson(session));
    79.            log.debug("session在数据库中已存在,将session更新到数据库 ..... ");
    80.            service.updateSession(model);
    81.       }
    82.        //调用父类方法,更新session
    83.        super.doUpdate(session);
    84.   }
    85. }

    使用的json工具

    依赖文件

    1.  
    2.    <dependency>
    3.      <groupId>com.fasterxml.jackson.coregroupId>
    4.      <artifactId>jackson-databindartifactId>
    5.      <version>2.13.3version>
    6.    dependency>

    工具包

    1. package com.zking.shiro.utils;
    2. import com.fasterxml.jackson.core.JsonProcessingException;
    3. import com.fasterxml.jackson.databind.ObjectMapper;
    4. public final class  JsonUtils {
    5.    private JsonUtils(){}
    6.    private static ObjectMapper map = new ObjectMapper();
    7.    /**
    8.     * 将 对象转字符串
    9.     *
    10.     * @param obj
    11.     * @return
    12.     */
    13.    public static String toJson(Object obj
    14.   ) {
    15.        String s = null;
    16.        try {
    17.            s = map.writeValueAsString(obj);
    18.       } catch (JsonProcessingException e) {
    19.            throw new RuntimeException(e);
    20.       }
    21.        return s;
    22.   }
    23.    /**
    24.     * 将 json字符串 转为 对象
    25.     *
    26.     * @param json
    27.     * @return
    28.     */
    29.    public static   Object toJson(String json, T t) {
    30.        try {
    31.            return map.readValue(json, t.getClass());
    32.       } catch (JsonProcessingException e) {
    33.            throw new RuntimeException(e);
    34.       }
    35.   }
    36. }

    在 spring 配置文件中配置 时效

     
      
    1.  <bean id="sessionManager" class="org.apache.shiro.web.session.mgt.DefaultWebSessionManager">
    2.        <property name="sessionListeners">
    3.            <list>
    4.                <bean class="com.zking.shiro.listener.SessionListener"/>
    5.            list>
    6.        property>
    7.        
    8.        
    9.        <property name="sessionValidationSchedulerEnabled" value="true" />
    10.        
    11.        <property name="globalSessionTimeout" value="1800000" />
    12.        <property name="sessionDAO" ref="customShiroSessionDao" />
    13.    bean>

    将session 管理器配置到shiro 管理器中 刚刚以及配置过

  • 相关阅读:
    2023-11-09 LeetCode每日一题(逃离火灾)
    语言大模型的进化轨迹
    k8s安装使用教程 ingress
    基于PHP+MySQL月子中心管理系统的设计与实现
    经典算法学习之---折半插入排序
    java技术专家面试指南80问【java学习+面试宝典】(七)
    品牌线上渠道管控,如何考察第三方控价公司
    使用装饰器实现python的单例模式
    Codeforces Round #835 (Div. 4) A. Medium Number
    PAT 1022 Digital Library
  • 原文地址:https://blog.csdn.net/qq_62898618/article/details/126910965