Shiro会话管理和加密

一、会话相关API及会话使用

Shiro提供了完整的企业级会话管理功能,不依赖于底层容器(如Web容器Tomcat),可以在JavaSE和JavaEE环境中使用。会话相关API主要包括:

  • Subject.getSession(): 获取当前用户的会话,如果当前没有创建会话对象,则会创建一个新的会话。这等价于Subject.getSession(true)
  • Subject.getSession(boolean create): 根据参数决定是否创建一个新的会话。如果createtrue且当前没有会话,则创建一个新的会话;如果为false且当前没有会话,则返回null
  • session.setAttribute(key, value): 设置会话属性。
  • session.getAttribute(key): 获取会话属性。
  • session.removeAttribute(key): 删除会话属性。

会话使用时,建议在Controller层使用原生的HttpSession对象,在Service层使用Shiro提供的Session对象。

二、缓存

问题分析

在每次访问设置了权限的页面时,Shiro都会执行doGetAuthorizationInfo()方法来获取权限信息。这可能导致性能问题,因为每次请求都需要重新计算权限。

解决办法

对权限授权数据进行缓存处理。可以使用第三方的Shiro-Redis集成Redis来实现缓存。

具体实现

  1. 在Shiro配置类中配置Redis缓存管理器。
  2. 在自定义Realm中使用缓存管理器来缓存权限信息。
  3. 在用户登录或权限变更时,手动清除缓存中的旧权限信息。

示例代码(Spring Boot环境):

// Shiro配置类  
@Configuration  
public class ShiroConfig {  
    // ...  
    @Bean  
    public RedisCacheManager cacheManager(RedisManager redisManager) {  
        RedisCacheManager cacheManager = new RedisCacheManager();  
        cacheManager.setRedisManager(redisManager);  
        return cacheManager;  
    }  
      
    // ...  
}  
  
// 自定义Realm  
public class CustomRealm extends AuthorizingRealm {  
    // ...  
    @Autowired  
    private RedisCacheManager cacheManager;  
      
    @Override  
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {  
        // 从缓存中获取权限信息  
        String cacheKey = getAuthorizationCacheKey(principals);  
        AuthorizationInfo cachedAuthInfo = (AuthorizationInfo) cacheManager.getCache("authorizationCache").get(cacheKey);  
        if (cachedAuthInfo != null) {  
            return cachedAuthInfo;  
        }  
          
        // 如果缓存中没有,则查询数据库并缓存结果  
        AuthorizationInfo authInfo = // 查询数据库获取权限信息  
        cacheManager.getCache("authorizationCache").put(cacheKey, authInfo);  
          
        return authInfo;  
    }  
      
    // ...  
      
    private String getAuthorizationCacheKey(PrincipalCollection principals) {  
        // 生成缓存键,例如使用用户名  
        return principals.getPrimaryPrincipal().toString();  
    }  
      
    // 清除缓存的方法  
    public void clearCachedAuthorizationInfo(PrincipalCollection principals) {  
        String cacheKey = getAuthorizationCacheKey(principals);  
        cacheManager.getCache("authorizationCache").remove(cacheKey);  
    }  
}
演示测试

在测试环境中,可以通过模拟用户登录和访问受保护资源来验证缓存是否生效。观察日志或调试信息,确认Shiro是否从缓存中获取了权限信息而不是每次都查询数据库。

三、加密

哈希与盐

为了增强密码的安全性,Shiro支持使用哈希算法对密码进行加密,并可以添加盐值以防止彩虹表攻击。

加密与验证

在Shiro中,可以通过配置HashedCredentialsMatcher来实现密码的哈希加密和验证。HashedCredentialsMatcher可以设置哈希算法(如MD5、SHA-256等)和哈希迭代次数。

具体实现
  1. 在Shiro配置类中配置HashedCredentialsMatcher
  2. 在自定义Realm中使用HashedCredentialsMatcher进行密码验证。

示例代码:

// Shiro配置类  
@Configuration  
public class ShiroConfig {  
    // ...  
    @Bean  
    public HashedCredentialsMatcher hashedCredentialsMatcher() {  
        HashedCredentialsMatcher hashedCredentialsMatcher = new HashedCredentialsMatcher();  
        hashedCredentialsMatcher.setHashAlgorithmName("MD5"); // 设置哈希算法  
        hashedCredentialsMatcher.setHashIterations(1024); // 设置哈希迭代次数  
        return hashedCredentialsMatcher;  
    }  
      
    @Bean  
    public SecurityManager securityManager(CustomRealm customRealm) {  
        DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();  
        securityManager.setRealm(customRealm);  
        securityManager.setCredentialsMatcher(hashedCredentialsMatcher()); // 设置密码加密验证器  
        return securityManager;  
    }  
      
    // ...  
}  
  
// 自定义Realm  
public class CustomRealm extends AuthorizingRealm {  
    // ...  
    @Override  
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {  
        UsernamePasswordToken upToken = (UsernamePasswordToken) token;  
        String username = upToken.getUsername();  
          
        // 查询数据库获取用户信息  
        User user = userService.findUserByName(username);  
        if (user == null) {  
            throw new UnknownAccountException("用户不存在");  
        }  
          
        // 返回认证信息,包含用户名、密码(已加密)、盐值和Realm名称  
        return new SimpleAuthenticationInfo(user.getUsername(), user.getPassword(), ByteSource.Util.bytes(user.getSalt()), getName());  
    }  
      
    // ...  
}

在上面的代码中,User类应该包含用户名、密码(已加密)、盐值等属性。在注册用户时,应该使用与HashedCredentialsMatcher相同的哈希算法和迭代次数对密码进行加密,并将加密后的密码和盐值存储在数据库中。

四、登录次数限制

Shiro本身没有直接提供登录次数限制的功能,但可以通过自定义Realm或拦截器来实现。例如,可以在自定义Realm中维护一个登录失败次数的计数器,当登录失败次数超过一定限制时,可以锁定用户账户或增加额外的验证步骤。

实现登录次数限制的示例代码(简化版):

// 自定义Realm  
public class CustomRealm extends AuthorizingRealm {  
    // ...  
    private Map<String, Integer> loginFailureCounts = new ConcurrentHashMap<>(); // 登录失败次数计数器  
    private static final int MAX_FAILURE_COUNT = 5; // 最大失败次数限制  
      
    @Override  
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {  
        UsernamePasswordToken upToken = (UsernamePasswordToken) token;  
        String username = upToken.getUsername();  
          
        // 检查登录失败次数是否超过限制  
        if (loginFailureCounts.getOrDefault(username, 0) >= MAX_FAILURE_COUNT) {  
            throw new LockedAccountException("账户已被锁定,请稍后再试");  
        }  
          
        // 查询数据库获取用户信息  
        User user = userService.findUserByName(username);  
        if (user == null) {  
            // 登录失败,增加失败次数计数器  
            loginFailureCounts.put(username, loginFailureCounts.getOrDefault(username, 0) + 1);  
            throw new UnknownAccountException("用户不存在");  
        }  
          
        // 验证密码(省略具体实现)  
        // ...  
          
        // 登录成功,清除失败次数计数器  
        loginFailureCounts.remove(username);  
          
        // 返回认证信息  
        return new SimpleAuthenticationInfo(user.getUsername(), user.getPassword(), ByteSource.Util.bytes(user.getSalt()), getName());  
    }  
      
    // ...  
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/899267.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

接口测试 —— Postman 变量了解一下!

Postman变量是在Postman工具中使用的一种特殊功能&#xff0c;用于存储和管理动态数据。它们可以用于在请求的不同部分、环境或集合之间共享和重复使用值。 Postman变量有以下几种类型&#xff1a; 1、环境变量&#xff08;Environment Variables&#xff09;: 环境变量是在…

kubernetes中的微服务详解

华子目录 什么是微服务微服务的类型ipvs模式ipvs模式配置方式注意 微服务类型详解ClusterIP类型Services创建后集群DNS提供解析ClusterIP中的特殊模式&#xff1a;headless无头服务 NodePort类型访问过程NodePort默认端口 LoadBalancer类型访问过程metalLBmetalLB功能部署metal…

百度搜索推广和信息流推广的区别,分别适用于什么场景!

信息流推广和搜索广告&#xff0c;不仅仅是百度&#xff0c;是很多平台的两个核心推广方式。 1、搜索广告&#xff1a; 就是基于用户的搜索习惯&#xff0c;更多是用户有疑问、还有用户当下就要做出行动的广告。 比如上门服务、线上咨询服务、招商加盟、了解产品各种型号和信…

[JAVA]JDBC如何实现写数据?——利用Java新增MySQL中存储的员工字段信息

我们在实现JDBC写数据之前需要先工具类做一些前置准备。—封装DbUtils工具类&#xff0c;是一个用于操作数据库的工具类&#xff0c;它提供了一些便捷的方式来执行SQL语句&#xff0c;获取数据库连接等。简化程序的开发。DbUtils工具类主要帮我们封装&#xff0c;打开连接&…

LabVIEW提高开发效率技巧----插入式架构

随着LabVIEW项目规模的扩大和系统复杂性的增加&#xff0c;传统的单一代码架构难以应对后期维护和功能扩展的需求。插入式架构&#xff08;Plug-In Architecture&#xff09;作为一种模块化设计方式&#xff0c;通过动态加载和运行子VI&#xff0c;使系统功能更加灵活、模块化&…

【LLM之Agent】《Tool Learning with Large Language Models: A Survey》论文阅读笔记

概述 背景信息 近年来&#xff0c;基于大型语言模型&#xff08;LLMs&#xff09;的工具学习成为增强LLMs应对复杂任务能力的有力范式。尽管这一领域快速发展&#xff0c;现有文献的碎片化以及缺乏系统组织&#xff0c;给新入门者带来了阻碍。因此&#xff0c;本论文旨在对现…

Chrome DevTools 二: Performance 性能面板

Chrome DevTools 第二篇 Performance 主要介绍performance在我们日常开发中所起到的作用&#xff0c;以及如何利用performance 面板进行性能分析和相关优化建议。 性能面板 Performance 记录和分析页面运行中的所有活动&#xff0c;是解决前端性能问题的重要工具。 1. 控制栏…

分布式链路追踪-01初步认识SkyWalking

一 SkyWaling是什么&#xff1f; Skywalking是分布式系统的应用程序性能监视工具&#xff0c;专为微服务、云原生架构和基于容器&#xff08;Docker、K8s、Mesos&#xff09;架构而设计。SkyWalking 是观察性分析平台和应用性能管理系统&#xff0c;提供分布式追踪、服务网格遥…

idea 无法输入中文 快速解决

idea在某些情况会出现无法输入中文的情况&#xff0c;我们不去深究内部原因&#xff0c;直接上解决方案&#xff1a; 1、点击菜单help->Edit Custom VM Options 2、最后一行&#xff0c;追加&#xff1a; -Drecreate.x11.input.methodtrue 、 3、重启

软件分享丨PDF Shaper

【资源名】PDF Shaper 【地址】https://www.pdfshaper.com/ 【资源介绍】 PDF Shaper Professional是一款功能强大的PDF文档编辑与转换工具&#xff0c;使用它可以对PDF文件进行各种转换、提取、合并、旋转、加密、解密等编辑操作&#xff0c;主要功能有分割和合并PDF文件&…

无人机飞手执照培训为什么需要脱产学习?

无人机飞手执照培训需要脱产学习的原因主要基于以下几个方面&#xff1a; 一、知识体系的系统性与复杂性 无人机飞手培训涵盖的内容广泛且深入&#xff0c;包括无人机基础知识、飞行原理、气象学、法律法规等多个方面。这些知识体系相互关联&#xff0c;需要学员进行系统的学…

排序算法 —— 计数排序

目录 1.计数排序的思想 2.计数排序的实现 3.计数排序的分析 时间复杂度 空间复杂度 稳定性 优点 缺点 1.计数排序的思想 顾名思义&#xff0c;计数排序就是通过计数的方式来排序&#xff0c;其基本思想为&#xff1a; 开辟一个计数数组&#xff0c;统计每个数出现的次…

Windows 10、Office 2016/2019 和 PPTP 和 L2TP协议即将退役,企业应尽早做好准备

关心微软技术和产品的朋友一定对这个网站很熟悉&#xff1a;https://microsoftgraveyard.com/&#xff0c;这里静静的躺着很多微软技术和产品。近日&#xff0c;微软又在准备一场新的“告别仪式”了&#xff0c;这次是 Windows 10、Office 2016/2019 和一些老旧的协议与技术。让…

【Linux】按时间抽取附件

#1024程序员节&#xff5c;征文# 希望互相学习&#xff0c;共同进步 风123456789&#xff5e;-CSDN博客 1.背景 附件表 t_file 中有创建时间&#xff0c;需求是抽取202407-202408 月创建的附件到指定目录&#xff0c;并保持层级目录。 解决方案&#xff1a;由于抽取的附件条数…

2024 睿抗机器人开发者大赛(RAICOM)-【网络安全】CTF 部分WP

文章目录 一、前言二、MICS你是黑客么循环的压缩包Goodtime 三、WEBpy 四、Crypto变异凯撒RSAcrypto3 一、前言 WP不完整&#xff0c;仅供参考&#xff01; 除WEB&#xff0c;RE&#xff0c;PWN外&#xff0c;其余附件均已打包完毕 也是一个对MISC比较友好的一个比赛~ 123网…

ES6:let和const命令解读以及变量的解构赋值

有时候&#xff0c;我们需要的不是答案&#xff0c;而是一双倾听的耳朵 文章目录 let和const命令变量的解构赋值 let和const命令 let和const命令都是声明变量的关键字&#xff0c;类同varlet特点 用来声明变量&#xff0c;不能再次定义&#xff0c;但是值可以改变存在块级作用…

【Nuvoton干货分享】开发应用篇 5 -- 32bit MCU Flash 操作

在实际开发中&#xff0c;我们都会碰到需要把部分数据存放在不易失存储空间上&#xff0c;比如外部NOR FLASH、EEPROM、SD等存储空间上&#xff0c;针对数据量不大的情况下&#xff0c;可以考虑将数据存放在芯片ROM存储空间。Nuvoton 32bit MCU ROM存储空间包括LDROM、APROM、S…

什么是缓存?

缓存是将文件副本存储在临时位置的过程&#xff0c;以便可以更快地访问这些文件。从技术上讲&#xff0c;缓存是文件或数据副本的任何临时存储位置&#xff0c;但通常是指互联网技术中的缓存。Web 浏览器缓存 HTML 文件、JavaScript 和图像&#xff0c;以便更快地加载网站&…

python 爬虫抓取百度热搜

实现思路&#xff1a; 第1步、在百度热搜页获取热搜元素 元素类名为category-wrap_iQLoo 即我们只需要获取类名category-wrap_为前缀的元素 第2步、编写python脚本实现爬虫 import requests from bs4 import BeautifulSoupurl https://top.baidu.com/board?tabrealtime he…

npm run serve 提示异常Cannot read property ‘upgrade‘ of undefined

npm run serve 提示Cannot read property ‘upgrade’ of undefined 一般是proxy的target代理域名问题导致的&#xff0c;如下&#xff1a; 解决方案&#xff1a; proxy: { “/remoteDealerReportApi”: { target: ‘http://demo-.com.cn’, //此域名有问题&#xff0c;会导致…