怎么查看网站是否备案安徽省工程建设信息网查询信息

张小明 2025/12/31 20:19:25
怎么查看网站是否备案,安徽省工程建设信息网查询信息,辽阳企业网站建设价格,做视频网站需要什么手续Apache Shiro 完整教程 #x1f4da; 教程目标#xff1a;通过理论学习和代码实践#xff0c;全面掌握Apache Shiro的核心功能、架构设计和最佳实践#xff0c;能够在实际项目中灵活应用Shiro实现安全认证和授权。 #x1f4d6; 学习路径导航 章节结构 第一章#xff1…Apache Shiro 完整教程教程目标通过理论学习和代码实践全面掌握Apache Shiro的核心功能、架构设计和最佳实践能够在实际项目中灵活应用Shiro实现安全认证和授权。 学习路径导航章节结构第一章Shiro概述与基础架构- 了解Shiro是什么、核心架构和设计理念第二章身份认证Authentication- 学习用户登录认证的实现第三章角色管理Roles- 掌握基于角色的授权机制第四章权限控制Permissions- 深入学习细粒度权限控制第五章会话管理Session Management- 了解Shiro的会话管理功能第六章密码加密Encryption- 学习安全的密码加密技术第七章自定义Realm- 掌握自定义数据源连接第八章缓存支持Cache- 了解如何优化Shiro性能第九章JWT集成- 学习现代无状态认证方式 教程核心价值通过本教程的学习你将能够✅掌握Shiro核心概念- 理解认证、授权、会话等基础理论✅熟悉架构设计- 了解SecurityManager、Subject、Realm等核心组件✅具备实践能力- 能够编写完整的Shiro应用✅解决实际问题- 应对各种安全场景✅做出技术选型- 根据项目需求选择合适的安全方案第一章Shiro概述与基础架构 学习目标理解Apache Shiro是什么了解Shiro的发展历史和设计理念掌握Shiro的核心架构和组件明确Shiro在现代应用中的定位理解Shiro的核心优势 什么是Apache ShiroApache Shiro是一个功能强大且易于使用的Java安全框架提供了认证、授权、会话管理和加密等功能用于保护任何类型的应用程序 - 从命令行工具到大型企业级Web应用。 设计理念“简单即美”- Shiro的设计哲学是让复杂的安全操作变得简单直观 Shiro核心优势简洁直观的API设计最少知识原则开发者只需要了解必要的API约定优于配置合理的默认配置减少配置负担分层抽象不同层次的抽象满足不同复杂度的需求全面的安全功能覆盖认证多因素认证、JWT授权基于角色、权限、资源的细粒度控制会话支持Web和非Web环境、分布式会话加密支持MD5、SHA、AES等主流加密算法灵活的架构设计模块化架构插件式Realm轻松切换和组合不同的数据源策略模式认证、授权策略可配置事件驱动支持安全事件的监听和处理注解支持基于注解的声明式安全控制优秀的性能表现智能缓存认证和授权结果的智能缓存懒加载安全对象的按需加载连接池数据库连接的有效管理最小化锁并发场景下的性能优化️ 核心架构数据层 - Data Layer核心层 - Core Layer应用层 - Application LayerRealm 数据源连接器JDBC Realm 数据库LDAP Realm 目录服务Custom Realm 自定义数据源Text Realm 文本配置Authenticator 认证器SecurityManager 安全管理器Authorizer 授权器SessionManager 会话管理器CacheManager 缓存管理器AuthenticationStrategy 认证策略CredentialMatcher 凭证匹配器PermissionResolver 权限解析器RolePermissionResolver 角色权限解析器SessionDAO 会话存储SessionFactory 会话工厂SessionValidationScheduler 会话验证调度器SecurityUtils 安全工具Subject 当前用户 核心组件交互流程应用程序SubjectSecurityManagerRealm数据源创建认证请求委托认证处理查询安全数据获取用户凭证返回用户数据返回认证结果认证成功/失败返回认证状态同时处理授权、会话等应用程序SubjectSecurityManagerRealm数据源 核心组件详解组件角色核心职责代码示例Subject 当前用户代表与系统交互的实体SecurityUtils.getSubject()SecurityManager 安全管家协调所有安全操作new DefaultSecurityManager()Realm️ 数据桥梁连接安全数据源new IniRealm(classpath:shiro.ini)Authenticator 身份验证官验证用户身份ModularRealmAuthenticatorAuthorizer⚖️ 权限审核官检查用户权限ModularRealmAuthorizerSessionManager 会话管理员管理用户会话DefaultSessionManagerCacheManager⚡ 性能加速器缓存安全数据MemoryConstrainedCacheManager Shiro 与 Spring Security 对比功能特性Apache ShiroSpring SecurityShiro优势学习曲线平缓陡峭API更简洁直观配置复杂度简单复杂配置更直观独立运行支持依赖Spring可独立使用Web支持完善完善同样强大非Web支持优秀一般更好的通用性缓存机制内置需集成缓存更完善会话管理强大一般会话功能更丰富加密功能完善需集成加密功能更完整授权灵活性高极高平衡灵活与简洁社区活跃度稳定活跃成熟稳定选择建议选择Shiro的场景需要独立运行的安全框架项目不基于Spring框架需要丰富的会话管理功能追求简洁的API和配置需要非Web环境的安全支持选择Spring Security的场景项目已基于Spring框架需要与Spring生态深度集成团队已熟悉Spring技术栈需要更细粒度的安全控制 学习成果检验✅ 基础理解能够解释Shiro的核心概念能够描述Shiro的三层架构能够说出核心组件的作用能够列举Shiro的核心优势第二章身份认证Authentication 学习目标理解身份认证的概念掌握Shiro认证流程学习如何配置用户账户掌握异常处理方法 认证流程详解认证架构设计flowchart TD A[用户提交认证请求] -- B[Subject.login token] B -- C[SecurityManager 接收请求] C -- D[Authenticator 开始认证] D -- E[遍历配置 的Realms] E -- F{Realm支持 此token?} F --|是| G[Realm执行 doGetAuthenticationInfo] F --|否| H[跳过此Realm] G -- I{认证 成功?} I --|是| J[返回 AuthenticationInfo] I --|否| K[抛出 AuthenticationException] H -- E J -- L[创建 Subject身份] K -- M[认证失败 处理] L -- N[认证成功 登录状态] style A fill:#e1f5fe style N fill:#c8e6c9 style M fill:#ffcdd2 style D fill:#e8f5e8 常见认证异常异常类型说明处理方式UnknownAccountException用户名不存在提示用户注册或检查用户名IncorrectCredentialsException密码错误提示用户重新输入密码LockedAccountException账户已锁定联系管理员解锁账户DisabledAccountException账户已禁用联系管理员启用账户AuthenticationException其他认证异常通用异常处理 代码示例项目代码文件src/main/java/com/shiro/tutorial/SimplifiedAuthExample.javapackagecom.shiro.tutorial;importorg.apache.shiro.SecurityUtils;importorg.apache.shiro.authc.AuthenticationException;importorg.apache.shiro.authc.IncorrectCredentialsException;importorg.apache.shiro.authc.UnknownAccountException;importorg.apache.shiro.authc.UsernamePasswordToken;importorg.apache.shiro.mgt.DefaultSecurityManager;importorg.apache.shiro.realm.text.IniRealm;importorg.apache.shiro.subject.Subject;importorg.slf4j.Logger;importorg.slf4j.LoggerFactory;/** * Apache Shiro 简单身份认证示例类 * 开发思路 * 1. 首先配置安全管理器和领域Realm * 2. 获取当前用户主体Subject * 3. 创建身份令牌进行用户认证 * 4. 处理各种认证异常情况 * * author 李昊哲 李胜龙 * version 1.0.0 * since 2025-12-15 */publicclassSimplifiedAuthExample{// 创建日志记录器用于输出程序运行信息privatestaticfinalLoggerLOGGERLoggerFactory.getLogger(SimplifiedAuthExample.class);/** * 程序入口方法 * 开发过程 * 1. 初始化Shiro安全框架组件 * 2. 进行用户身份认证 * 3. 处理认证结果和异常情况 * * param args 命令行参数 */publicstaticvoidmain(String[]args){/* 当前示例是如何工作的 1. 在 SimplifiedAuthExample.java 中认证流程如下 2. 首先检查用户是否已经认证过通常在首次运行时返回 false 3. 如果未认证提示用户输入用户名和密码 4. 创建 UsernamePasswordToken 对象封装用户输入的凭据 5. 调用 currentUser.login(token) 进行认证 Shiro 在后台使用 IniRealm 读取 shiro.ini 文件中的用户信息并与用户输入的凭据进行比较 所以系统是拿着用户输入的账号密码去数据源中验证的。shiro.ini 文件就是我们的数据源虽然在实际项目中我们会使用数据库或 LDAP 等更复杂的存储系统。 */// 创建 IniRealm 实例指定配置文件位置为classpath下的shiro.ini// IniRealm是Shiro提供的基于INI配置文件的身份认证和授权实现IniRealminiRealmnewIniRealm(classpath:shiro.ini);// 创建 SecurityManager 安全管理器实例并传入realm// SecurityManager是Shiro框架的核心负责协调内部安全组件DefaultSecurityManagersecurityManagernewDefaultSecurityManager(iniRealm);// 将 SecurityManager 绑定到 SecurityUtils 工具类// 这样在整个应用程序中都可以通过SecurityUtils获取SecurityManagerSecurityUtils.setSecurityManager(securityManager);// 获取当前执行用户SubjectSubject代表当前正在与软件进行交互的用户SubjectcurrentUserSecurityUtils.getSubject();// 判断当前用户是否已经通过认证if(!currentUser.isAuthenticated()){// 如果未认证则创建UsernamePasswordToken令牌用于封装用户身份信息// 这里使用预设的用户名user和密码passwordUsernamePasswordTokentokennewUsernamePasswordToken(user,password);try{// 使用令牌进行用户登录认证currentUser.login(token);// 认证成功后记录用户登录成功的日志信息LOGGER.info(用户 {} 登录成功,currentUser.getPrincipal());}catch(UnknownAccountExceptionuae){// 捕获用户名不存在异常LOGGER.error(用户名不存在,uae);}catch(IncorrectCredentialsExceptionice){// 捕获密码错误异常LOGGER.error(密码错误,ice);}catch(AuthenticationExceptionae){// 捕获其他身份认证相关异常LOGGER.error(认证失败,ae);}}else{// 如果用户已经通过认证则记录相应日志LOGGER.info(用户已认证);}}} 代码执行逻辑是否是否UnknownAccountExceptionIncorrectCredentialsException其他创建IniRealm实例创建DefaultSecurityManager实例绑定到SecurityUtils获取Subject是否已认证?记录已认证日志创建UsernamePasswordToken尝试登录登录成功?记录登录成功日志异常类型?记录用户名不存在记录密码错误记录认证失败退出程序 配置文件项目配置文件src/main/resources/shiro.ini# 用户配置部分定义系统中的用户及其密码 [users] # 格式: 用户名 密码 user password 学习成果检验✅ 实践任务运行SimplifiedAuthExample类观察输出结果修改用户名或密码观察异常情况尝试添加新用户到配置文件第三章角色管理Roles 学习目标理解角色的概念掌握角色分配方法学习角色检查机制了解角色与权限的关系 角色授权模型RBAC模型深度解析USERbigintidPKstringusernamestringpasswordUSER_ROLEbigintuser_idFKbigintrole_idFKROLEbigintidPKstringnamestringdescriptionROLE_PERMISSIONbigintrole_idFKbigintpermission_idFKPERMISSIONbigintidPKstringpermission分配到包含用户拥有权限分配给角色 角色检查方法方法说明返回值hasRole(String role)检查用户是否具有指定角色booleanhasRoles(ListString roles)检查用户是否具有多个角色boolean[]hasAllRoles(CollectionString roles)检查用户是否具有所有指定角色booleancheckRole(String role)检查用户是否具有指定角色失败抛出异常void 代码示例项目代码文件src/main/java/com/shiro/tutorial/RoleExample.javapackagecom.shiro.tutorial;importorg.apache.shiro.SecurityUtils;importorg.apache.shiro.authc.UsernamePasswordToken;importorg.apache.shiro.mgt.DefaultSecurityManager;importorg.apache.shiro.realm.text.IniRealm;importorg.apache.shiro.subject.Subject;importorg.slf4j.Logger;importorg.slf4j.LoggerFactory;/** * Apache Shiro 角色权限控制示例类 * 开发思路 * 1. 首先配置安全管理器和领域Realm * 2. 获取当前用户主体Subject * 3. 创建身份令牌进行用户认证 * 4. 验证用户角色 * * author 李昊哲 李胜龙 * version 1.0.0 * since 2025-12-15 */publicclassRoleExample{// 创建日志记录器用于输出程序运行信息privatestaticfinalLoggerLOGGERLoggerFactory.getLogger(RoleExample.class);/** * 程序入口方法 * 开发过程 * 1. 初始化Shiro安全框架组件加载角色配置 * 2. 进行用户身份认证 * 3. 验证用户角色权限检查功能 * * param args 命令行参数 */publicstaticvoidmain(String[]args){// 创建 IniRealm 实例使用专门的角色配置文件shiro-role.ini// 该配置文件中包含了用户角色相关信息IniRealminiRealmnewIniRealm(classpath:shiro-role.ini);// 创建 SecurityManager 安全管理器实例并传入realm// SecurityManager是Shiro框架的核心负责协调内部安全组件DefaultSecurityManagersecurityManagernewDefaultSecurityManager(iniRealm);// 将 SecurityManager 绑定到 SecurityUtils 工具类// 这样在整个应用程序中都可以通过SecurityUtils获取SecurityManagerSecurityUtils.setSecurityManager(securityManager);// 获取当前执行用户SubjectSubject代表当前正在与软件进行交互的用户SubjectcurrentUserSecurityUtils.getSubject();// 判断当前用户是否已经通过认证if(!currentUser.isAuthenticated()){// 如果未认证则创建UsernamePasswordToken令牌用于封装用户身份信息// 这里使用预设的用户名user和密码passwordUsernamePasswordTokentokennewUsernamePasswordToken(user,password);// 使用令牌进行用户登录认证currentUser.login(token);// 认证成功后记录用户登录成功的日志信息LOGGER.info(用户 {} 登录成功,currentUser.getPrincipal());}// 检查用户是否具有role角色与配置文件中定义的角色一致// hasRole方法用于判断当前用户是否拥有指定角色if(currentUser.hasRole(role)){LOGGER.info(用户 {} 拥有角色 role,currentUser.getPrincipal());}else{LOGGER.info(用户 {} 没有角色 role,currentUser.getPrincipal());}// 检查用户是否具有admin角色根据配置应该不存在此角色if(currentUser.hasRole(admin)){LOGGER.info(用户 {} 拥有角色 admin,currentUser.getPrincipal());}else{LOGGER.info(用户 {} 没有角色 admin,currentUser.getPrincipal());}}} 代码执行逻辑是否是否是否创建IniRealm实例加载shiro-role.ini配置文件创建DefaultSecurityManager实例将IniRealm传入SecurityManager将SecurityManager绑定到SecurityUtils获取当前用户Subject检查用户是否已认证检查用户是否具有role角色创建UsernamePasswordToken使用token进行登录认证记录用户登录成功日志输出用户拥有角色 role日志输出用户没有角色 role日志检查用户是否具有admin角色输出用户拥有角色 admin日志输出用户没有角色 admin日志程序结束 配置文件项目配置文件src/main/resources/shiro-role.ini# 用户配置部分用于定义系统中的用户、密码及其所属角色 [users] # 格式: 用户名 密码, 角色1, 角色2... # 示例配置了一个用户名为user密码为password的用户该用户属于role角色 user password, role # 角色权限配置部分用于定义角色所拥有的权限 [roles] # 格式: 角色名 权限 # 示例配置了role角色拥有permission权限 role permission 学习成果检验✅ 实践任务运行RoleExample类观察角色检查结果修改配置文件为用户添加多个角色尝试使用hasRoles()和hasAllRoles()方法检查多个角色使用checkRole()方法检查角色第四章权限控制Permissions 学习目标理解权限的概念和格式掌握细粒度权限控制学习权限表达式语法了解权限检查方法学习通配符权限 权限表达式语法详解权限格式定义权限格式资源:操作:实例 示例 - resource:action:object # 允许对指定资源执行操作 - user:* # 允许对用户进行所有操作 - *:read # 允许读取所有资源权限格式组成部分含义示例通配符支持资源受保护的资源类型resource, user, order支持*操作允许的操作类型action, create, read支持*实例资源的具体实例object, 1, user1支持* 权限检查方法方法说明返回值isPermitted(String permission)检查用户是否具有指定权限booleanisPermittedAll(String... permissions)检查用户是否具有所有指定权限booleancheckPermission(String permission)检查用户是否具有指定权限失败抛出异常void 代码示例项目代码文件src/main/java/com/shiro/tutorial/PermissionExample.javapackagecom.shiro.tutorial;importorg.apache.shiro.SecurityUtils;importorg.apache.shiro.authc.UsernamePasswordToken;importorg.apache.shiro.mgt.DefaultSecurityManager;importorg.apache.shiro.realm.text.IniRealm;importorg.apache.shiro.subject.Subject;importorg.slf4j.Logger;importorg.slf4j.LoggerFactory;/** * Apache Shiro 权限控制示例类 * 开发思路 * 1. 配置支持权限的Realm和安全管理器 * 2. 实现用户身份认证 * 3. 验证用户细粒度权限控制功能 */publicclassPermissionExample{// 创建日志记录器用于输出程序运行信息privatestaticfinalLoggerlogLoggerFactory.getLogger(PermissionExample.class);/** * 程序入口方法 * 开发过程 * 1. 初始化Shiro安全框架组件加载权限配置 * 2. 进行用户身份认证 * 3. 验证用户权限检查功能 */publicstaticvoidmain(String[]args){// 创建 IniRealm 实例使用专门的权限配置文件shiro-permission.iniIniRealminiRealmnewIniRealm(classpath:shiro-permission.ini);// 创建 SecurityManager 安全管理器实例并传入realmDefaultSecurityManagersecurityManagernewDefaultSecurityManager(iniRealm);// 将 SecurityManager 绑定到 SecurityUtils 工具类SecurityUtils.setSecurityManager(securityManager);// 获取当前执行用户SubjectSubjectcurrentUserSecurityUtils.getSubject();// 判断当前用户是否已经通过认证if(!currentUser.isAuthenticated()){// 如果未认证则创建UsernamePasswordToken令牌UsernamePasswordTokentokennewUsernamePasswordToken(user,password);// 执行用户登录认证currentUser.login(token);// 认证成功后记录用户登录成功的日志信息log.info(用户 {} 登录成功,currentUser.getPrincipal());}// 检查用户是否具有resource:action:object权限if(currentUser.isPermitted(resource:action:object)){log.info(用户有权访问 resource:action:object);}else{log.info(用户无权访问 resource:action:object);}// 检查用户是否具有another:resource:action权限if(currentUser.isPermitted(another:resource:action)){log.info(用户有权访问 another:resource:action);}else{log.info(用户无权访问 another:resource:action);}// 正常退出程序System.exit(0);}} 代码执行逻辑是否创建IniRealm实例创建DefaultSecurityManager实例绑定到SecurityUtils获取Subject是否已认证?跳过认证创建UsernamePasswordToken执行登录记录登录成功日志检查resource:action:object权限检查another:resource:action权限检查是否具有所有权限使用checkPermission方法退出程序 配置文件项目配置文件src/main/resources/shiro-permission.ini# 用户配置格式: 用户名 密码, 角色1, 角色2... [users] # 用户user具有role1和role2两个角色 user password, role1, role2 # 用户admin具有admin角色 admin admin123, admin # 角色权限配置格式: 角色名 权限1, 权限2... [roles] # role1角色具有对resource的action权限作用对象为object role1 resource:action:object # role2角色具有对another的resource权限作用对象为action role2 another:resource:action # admin角色具有所有权限 admin * 学习成果检验✅ 实践任务运行PermissionExample类观察权限检查结果修改配置文件添加更多权限尝试使用通配符权限使用isPermittedAll()方法检查多个权限使用checkPermission()方法检查权限第五章会话管理Session Management 学习目标理解Shiro会话的概念掌握会话操作方法学习会话属性管理了解会话生命周期 会话管理概述Shiro提供了强大的会话管理功能支持Web和非Web环境具有以下特点跨环境支持相同的API在Web和非Web环境下均可使用丰富的会话操作支持会话属性管理、超时设置等会话持久化支持将会话存储到不同的数据源会话验证自动验证会话的有效性 代码示例项目代码文件src/main/java/com/shiro/tutorial/SessionExample.javapackagecom.shiro.tutorial;importorg.apache.shiro.SecurityUtils;importorg.apache.shiro.authc.UsernamePasswordToken;importorg.apache.shiro.mgt.DefaultSecurityManager;importorg.apache.shiro.realm.text.IniRealm;importorg.apache.shiro.session.Session;importorg.apache.shiro.subject.Subject;importorg.slf4j.Logger;importorg.slf4j.LoggerFactory;publicclassSessionExample{privatestaticfinalLoggerlogLoggerFactory.getLogger(SessionExample.class);publicstaticvoidmain(String[]args){// 创建 IniRealm 实例使用专门的会话配置文件shiro-session.iniIniRealminiRealmnewIniRealm(classpath:shiro-session.ini);DefaultSecurityManagersecurityManagernewDefaultSecurityManager(iniRealm);SecurityUtils.setSecurityManager(securityManager);SubjectcurrentUserSecurityUtils.getSubject();// 用户认证if(!currentUser.isAuthenticated()){// 注意这里使用的是shiro-session.ini中配置的用户user1/password1UsernamePasswordTokentokennewUsernamePasswordToken(user1,password1);currentUser.login(token);log.info(用户 {} 登录成功,currentUser.getPrincipal());}// 获取当前用户的会话Session对象SessionsessioncurrentUser.getSession();// 在会话中设置属性存储用户相关信息session.setAttribute(username,user1);session.setAttribute(loginTime,System.currentTimeMillis());// 从会话中获取之前设置的属性值Stringusername(String)session.getAttribute(username);LongloginTime(Long)session.getAttribute(loginTime);// 输出从会话中获取的信息到日志log.info(从会话中获取用户名: {},username);log.info(登录时间: {},loginTime);// 从会话中移除指定属性session.removeAttribute(loginTime);log.info(loginTime 属性已被移除);System.exit(0);}} 代码执行逻辑是否创建IniRealm实例创建DefaultSecurityManager实例绑定到SecurityUtils获取Subject是否已认证?跳过认证创建UsernamePasswordToken执行登录记录登录成功日志获取Session对象设置会话属性username设置会话属性loginTime获取会话属性username获取会话属性loginTime记录会话信息移除会话属性loginTime记录属性移除信息退出程序 配置文件项目配置文件src/main/resources/shiro-session.ini# 用户配置格式: 用户名 密码 [users] user1 password1 学习成果检验✅ 实践任务运行SessionExample类观察会话操作结果尝试在会话中存储和获取更多属性学习会话的生命周期管理第六章密码加密Encryption 学习目标理解密码加密的重要性掌握Shiro加密API的使用学习盐值加密技术了解不同加密算法的特点 密码加密概述密码加密是保护用户数据安全的重要手段Shiro提供了强大的加密支持支持多种加密算法MD5、SHA-1、SHA-256等内置盐值加密支持支持多次迭代加密 代码示例项目代码文件src/main/java/com/shiro/tutorial/EncryptionExample.javapackagecom.shiro.tutorial;importorg.apache.shiro.crypto.hash.SimpleHash;importorg.slf4j.Logger;importorg.slf4j.LoggerFactory;publicclassEncryptionExample{privatestaticfinalLoggerlogLoggerFactory.getLogger(EncryptionExample.class);publicstaticvoidmain(String[]args){// 原始密码StringoriginalPasswordpassword;// 使用MD5算法加密密码Stringmd5HashnewSimpleHash(MD5,originalPassword).toHex();log.info(原始密码: {},originalPassword);log.info(MD5加密后: {},md5Hash);// 使用SHA-256算法加密密码Stringsha256HashnewSimpleHash(SHA-256,originalPassword).toHex();log.info(SHA-256加密后: {},sha256Hash);// 使用盐值加密密码增强安全性StringsaltrandomSalt123;StringsaltedHashnewSimpleHash(SHA-256,originalPassword,salt,1024).toHex();log.info(带盐值SHA-256加密后: {},saltedHash);// 演示密码验证过程StringinputPasswordpassword;StringhashedInputnewSimpleHash(SHA-256,inputPassword,salt,1024).toHex();if(hashedInput.equals(saltedHash)){log.info(密码验证成功);}else{log.info(密码验证失败);}System.exit(0);}} 代码执行逻辑是否是否定义原始密码使用MD5加密使用SHA-256加密使用带盐值的SHA-256加密输出MD5加密结果输出SHA-256加密结果输出带盐值SHA-256加密结果使用正确密码验证验证成功?输出验证成功日志输出验证失败日志使用错误密码验证验证成功?输出错误密码验证成功日志输出错误密码验证失败日志退出程序 学习成果检验✅ 实践任务运行EncryptionExample类观察不同加密算法的结果尝试使用不同的盐值和迭代次数理解盐值加密的重要性第七章自定义Realm 学习目标理解Realm的作用掌握自定义Realm的开发方法学习如何实现认证和授权逻辑了解多Realm配置️ 自定义Realm概述Realm是Shiro与数据源之间的桥梁负责从数据源获取安全数据。自定义Realm允许我们从任意数据源获取数据实现自定义的认证逻辑实现自定义的授权逻辑 代码示例项目代码文件src/main/java/com/shiro/tutorial/CustomRealmExample.javapackagecom.shiro.tutorial;importorg.apache.shiro.SecurityUtils;importorg.apache.shiro.authc.*;importorg.apache.shiro.authz.AuthorizationInfo;importorg.apache.shiro.authz.SimpleAuthorizationInfo;importorg.apache.shiro.mgt.DefaultSecurityManager;importorg.apache.shiro.realm.AuthorizingRealm;importorg.apache.shiro.subject.PrincipalCollection;importorg.apache.shiro.subject.Subject;importorg.slf4j.Logger;importorg.slf4j.LoggerFactory;importjava.util.HashMap;importjava.util.HashSet;importjava.util.Set;publicclassCustomRealmExample{privatestaticfinalLoggerlogLoggerFactory.getLogger(CustomRealmExample.class);publicstaticvoidmain(String[]args){// 创建自定义 Realm 实例UserRealmuserRealmnewUserRealm();// 创建 SecurityManager 安全管理器实例并传入自定义realmDefaultSecurityManagersecurityManagernewDefaultSecurityManager(userRealm);// 将 SecurityManager 绑定到 SecurityUtils 工具类SecurityUtils.setSecurityManager(securityManager);// 获取当前执行用户SubjectSubjectcurrentUserSecurityUtils.getSubject();// 判断当前用户是否已经通过认证if(!currentUser.isAuthenticated()){// 如果未认证则创建UsernamePasswordToken令牌UsernamePasswordTokentokennewUsernamePasswordToken(admin,admin123);try{// 使用令牌进行用户登录认证currentUser.login(token);// 认证成功后记录用户登录成功的日志信息log.info(用户 {} 登录成功,currentUser.getPrincipal());}catch(UnknownAccountExceptionuae){log.error(用户名不存在,uae);}catch(IncorrectCredentialsExceptionice){log.error(密码错误,ice);}catch(AuthenticationExceptionae){log.error(认证失败,ae);}}else{// 如果用户已经通过认证则记录相应日志log.info(用户已认证);}// 验证用户是否有 admin 角色if(currentUser.hasRole(admin)){log.info(用户具有 admin 角色);}else{log.info(用户不具有 admin 角色);}// 验证用户是否有user:delete权限if(currentUser.isPermitted(user:delete)){log.info(用户有删除用户的权限);}else{log.info(用户没有删除用户的权限);}// 验证用户是否有product:create权限if(currentUser.isPermitted(product:create)){log.info(用户有创建产品的权限);}else{log.info(用户没有创建产品的权限);}System.exit(0);}/** * 自定义Realm类用于处理用户认证和授权 */publicstaticclassUserRealmextendsAuthorizingRealm{// 模拟用户数据库privatestaticfinalHashMapString,StringuserDatabasenewHashMap();// 模拟角色数据库privatestaticfinalHashMapString,SetStringroleDatabasenewHashMap();// 模拟权限数据库privatestaticfinalHashMapString,SetStringpermissionDatabasenewHashMap();// 初始化模拟数据static{// 添加用户用户名:密码userDatabase.put(admin,admin123);userDatabase.put(user,user123);// 添加用户角色SetStringadminRolesnewHashSet();adminRoles.add(admin);adminRoles.add(user);roleDatabase.put(admin,adminRoles);SetStringuserRolesnewHashSet();userRoles.add(user);roleDatabase.put(user,userRoles);// 添加角色权限SetStringadminPermissionsnewHashSet();adminPermissions.add(user:*);adminPermissions.add(product:*);permissionDatabase.put(admin,adminPermissions);SetStringuserPermissionsnewHashSet();userPermissions.add(product:view);userPermissions.add(product:create);permissionDatabase.put(user,userPermissions);}/** * 认证方法获取认证信息 */OverrideprotectedAuthenticationInfodoGetAuthenticationInfo(AuthenticationTokenauthToken)throwsAuthenticationException{// 获取用户名Stringusername(String)authToken.getPrincipal();// 从模拟数据库中获取用户密码StringpassworduserDatabase.get(username);// 检查用户是否存在if(passwordnull){thrownewUnknownAccountException(用户不存在);}// 返回认证信息returnnewSimpleAuthenticationInfo(username,password,getName());}/** * 授权方法获取授权信息 */OverrideprotectedAuthorizationInfodoGetAuthorizationInfo(PrincipalCollectionprincipals){// 获取用户名Stringusername(String)principals.getPrimaryPrincipal();// 创建授权信息对象SimpleAuthorizationInfoauthorizationInfonewSimpleAuthorizationInfo();// 添加角色SetStringrolesroleDatabase.get(username);if(roles!null){authorizationInfo.setRoles(roles);}// 添加权限SetStringpermissionspermissionDatabase.get(username);if(permissions!null){authorizationInfo.setStringPermissions(permissions);}returnauthorizationInfo;}}} 代码执行逻辑是否是否是否是否是否创建自定义UserRealm实例创建DefaultSecurityManager实例绑定到SecurityUtils获取Subject是否已认证?跳过认证创建UsernamePasswordToken执行登录登录成功?记录登录成功日志记录认证失败日志检查admin角色角色检查成功?记录角色检查通过日志记录角色检查失败日志检查user:delete权限权限检查成功?记录权限检查通过日志记录权限检查失败日志检查product:create权限权限检查成功?记录权限检查通过日志记录权限检查失败日志退出程序 学习成果检验✅ 实践任务运行CustomRealmExample类观察自定义Realm的认证和授权结果尝试修改模拟数据库中的用户、角色和权限信息学习如何实现更复杂的自定义Realm第八章缓存支持Cache 学习目标理解Shiro缓存的概念和作用掌握Shiro缓存管理器的配置学习如何启用和配置认证缓存学习如何启用和配置授权缓存了解不同缓存管理器的特点 缓存概述Shiro提供了强大的缓存支持可以显著提高系统性能减少数据库访问次数。缓存主要应用于以下场景认证缓存缓存用户的认证信息避免重复查询数据库授权缓存缓存用户的角色和权限信息避免重复查询数据库会话缓存缓存用户会话信息支持分布式会话管理 项目缓存实现项目代码文件src/main/java/com/shiro/tutorial/CacheExample.javapackagecom.shiro.tutorial;importorg.apache.shiro.SecurityUtils;importorg.apache.shiro.authc.UsernamePasswordToken;importorg.apache.shiro.cache.MemoryConstrainedCacheManager;importorg.apache.shiro.mgt.DefaultSecurityManager;importorg.apache.shiro.realm.text.IniRealm;importorg.apache.shiro.subject.Subject;importorg.slf4j.Logger;importorg.slf4j.LoggerFactory;/** * Apache Shiro 缓存支持示例类 * 开发思路 * 1. 配置支持缓存的Realm和安全管理器 * 2. 实现用户身份认证 * 3. 演示Shiro缓存功能的使用 */publicclassCacheExample{// 创建日志记录器用于输出程序运行信息privatestaticfinalLoggerlogLoggerFactory.getLogger(CacheExample.class);/** * 程序入口方法 * 开发过程 * 1. 初始化Shiro安全框架组件配置缓存管理器 * 2. 进行用户身份认证 * 3. 演示缓存功能 */publicstaticvoidmain(String[]args){// 创建 IniRealm 实例使用专门的会话配置文件shiro-session.iniIniRealminiRealmnewIniRealm(classpath:shiro-session.ini);// 启用缓存 - 设置缓存管理器iniRealm.setCacheManager(newMemoryConstrainedCacheManager());// 启用认证缓存iniRealm.setAuthenticationCachingEnabled(true);// 启用授权缓存iniRealm.setAuthorizationCachingEnabled(true);// 创建 SecurityManager 安全管理器实例并传入realmDefaultSecurityManagersecurityManagernewDefaultSecurityManager(iniRealm);// 将 SecurityManager 绑定到 SecurityUtils 工具类SecurityUtils.setSecurityManager(securityManager);// 获取当前执行用户SubjectSubjectcurrentUserSecurityUtils.getSubject();// 判断当前用户是否已经通过认证if(!currentUser.isAuthenticated()){// 如果未认证则创建UsernamePasswordToken令牌UsernamePasswordTokentokennewUsernamePasswordToken(user1,password1);try{// 执行用户登录认证currentUser.login(token);// 认证成功后记录用户登录成功的日志信息log.info(用户 {} 登录成功,currentUser.getPrincipal());}catch(Exceptione){log.error(认证失败,e);}}// 检查用户角色第一次booleanhasRoleFirstcurrentUser.hasRole(admin);log.info(第一次检查用户是否有admin角色: {},hasRoleFirst);// 再次检查用户角色应该从缓存中获取booleanhasRoleSecondcurrentUser.hasRole(admin);log.info(第二次检查用户是否有admin角色: {},hasRoleSecond);// 检查用户权限第一次booleanisPermittedFirstcurrentUser.isPermitted(user:create);log.info(第一次检查用户是否有user:create权限: {},isPermittedFirst);// 再次检查用户权限应该从缓存中获取booleanisPermittedSecondcurrentUser.isPermitted(user:create);log.info(第二次检查用户是否有user:create权限: {},isPermittedSecond);log.info( 缓存说明 );log.info(1. Shiro提供了多种缓存管理器实现:);log.info( - MemoryConstrainedCacheManager: 基于内存的简单缓存管理器);log.info( - EhCacheManager: 基于Ehcache的缓存管理器);log.info( - SpringCacheManager: 基于Spring Cache的缓存管理器);log.info( - RedisCacheManager: 基于Redis的缓存管理器);log.info();log.info(2. 缓存配置要点:);log.info( - 启用认证缓存: setAuthenticationCachingEnabled(true));log.info( - 启用授权缓存: setAuthorizationCachingEnabled(true));log.info( - 设置缓存名称: setAuthenticationCacheName() 和 setAuthorizationCacheName());log.info();log.info(3. 缓存的好处:);log.info( - 减少数据库访问次数);log.info( - 提高认证和授权检查的速度);log.info( - 降低系统负载);// 正常退出程序System.exit(0);}} 代码执行逻辑是否是否创建IniRealm实例配置缓存管理器启用认证缓存启用授权缓存创建DefaultSecurityManager实例绑定到SecurityUtils获取Subject是否已认证?跳过认证创建UsernamePasswordToken执行登录登录成功?记录登录成功日志记录认证失败日志第一次检查admin角色记录第一次角色检查结果第二次检查admin角色记录第二次角色检查结果第一次检查user:create权限记录第一次权限检查结果第二次检查user:create权限记录第二次权限检查结果输出缓存说明退出程序 缓存工作原理是否是否用户请求认证认证缓存命中?直接返回认证结果查询数据库获取认证信息存储到认证缓存返回认证结果用户请求授权授权缓存命中?直接返回授权结果查询数据库获取授权信息存储到授权缓存返回授权结果缓存管理器MemoryConstrainedCacheManagerEhCacheManagerSpringCacheManagerRedisCacheManager 缓存配置要点选择合适的缓存管理器MemoryConstrainedCacheManager基于内存的简单缓存管理器适合开发和测试环境EhCacheManager基于Ehcache的缓存管理器适合单机环境SpringCacheManager与Spring Cache集成适合Spring项目RedisCacheManager基于Redis的缓存管理器适合分布式环境配置缓存参数设置缓存名称设置缓存过期时间设置缓存大小限制配置缓存刷新策略缓存清理手动清理缓存配置自动清理策略监听缓存事件 学习成果检验✅ 实践任务运行CacheExample类观察缓存功能的效果尝试使用不同的缓存管理器修改缓存配置参数观察不同配置的效果实现缓存清理功能学习如何监控缓存使用情况第九章JWT集成 学习目标理解JWT的概念和优势掌握Shiro集成JWT的方法学习JWT令牌的生成和验证了解无状态认证的实现掌握JWTRealm的开发学习JWT工具类的实现 JWT概述JWTJSON Web Token是一种用于在网络应用间传递声明的基于JSON的开放标准无状态服务器不需要存储会话信息适合分布式系统自包含令牌中包含了所有必要的用户信息跨平台支持不同语言和平台安全支持签名和加密可扩展可以自定义声明内容 JWT结构JWT令牌由三部分组成用点.分隔Header包含令牌类型和签名算法Payload包含声明信息如用户名、过期时间等Signature使用密钥对前两部分进行签名用于验证令牌的完整性️ 项目JWT实现架构JwtUtils生成JWT令牌验证JWT令牌提取用户名JwtToken封装JWT令牌实现AuthenticationToken接口JwtRealmdoGetAuthenticationInfodoGetAuthorizationInfovalidateTokengetUserRolesgetUserPermissionsJwtShiroExample初始化JWT Realm生成并验证JWT令牌使用JWT令牌登录验证角色和权限 JWT工具类实现项目代码文件src/main/java/com/shiro/tutorial/jwt/JwtUtils.javapackagecom.shiro.tutorial.jwt;importio.jsonwebtoken.Jwts;importorg.slf4j.Logger;importorg.slf4j.LoggerFactory;importjavax.crypto.SecretKey;importjava.util.Date;/** * JWT工具类 * 用于生成和验证JWT令牌 */publicclassJwtUtils{// 创建日志记录器用于输出程序运行信息privatestaticfinalLoggerlogLoggerFactory.getLogger(JwtUtils.class);// JWT 签名密钥publicstaticfinalSecretKeySECRET_KEYJwts.SIG.HS256.key().build();// 令牌过期时间24小时privatestaticfinallongEXPIRATION_TIME86400000;/** * 生成 JWT 令牌 * param username 用户名 * return JWT 令牌字符串 */publicstaticStringgenerateToken(Stringusername){DatenownewDate();DateexpirationDatenewDate(now.getTime()EXPIRATION_TIME);returnJwts.builder().subject(username).issuedAt(now).expiration(expirationDate).signWith(SECRET_KEY).compact();}/** * 从 JWT 令牌中提取用户名 * param token JWT 令牌 * return 用户名 */publicstaticStringgetUsernameFromToken(Stringtoken){try{returnJwts.parser().verifyWith(SECRET_KEY).build().parseSignedClaims(token).getPayload().getSubject();}catch(Exceptione){log.error(解析 JWT 令牌失败,e);returnnull;}}/** * 验证 JWT 令牌的有效性 * param token JWT 令牌 * return 令牌是否有效 */publicstaticbooleanvalidateToken(Stringtoken){try{Jwts.parser().verifyWith(SECRET_KEY).build().parseSignedClaims(token);returntrue;}catch(Exceptione){log.error(JWT 令牌验证失败,e);returnfalse;}}} JWT令牌实现项目代码文件src/main/java/com/shiro/tutorial/jwt/JwtToken.javapackagecom.shiro.tutorial.jwt;importorg.apache.shiro.authc.AuthenticationToken;/** * JWT令牌类 * 用于封装JWT令牌信息实现Shiro的AuthenticationToken接口 */publicclassJwtTokenimplementsAuthenticationToken{/** * JWT 令牌字符串 */privatefinalStringtoken;/** * 构造函数 * param token JWT 令牌字符串 */publicJwtToken(Stringtoken){this.tokentoken;}/** * 获取用户身份信息 * return JWT 令牌字符串 */OverridepublicObjectgetPrincipal(){returntoken;}/** * 获取用户凭据信息 * return JWT 令牌字符串 */OverridepublicObjectgetCredentials(){returntoken;}} JWT Realm实现项目代码文件src/main/java/com/shiro/tutorial/jwt/JwtRealm.javapackagecom.shiro.tutorial.jwt;importio.jsonwebtoken.*;importorg.apache.shiro.authc.AuthenticationException;importorg.apache.shiro.authc.AuthenticationInfo;importorg.apache.shiro.authc.AuthenticationToken;importorg.apache.shiro.authc.SimpleAuthenticationInfo;importorg.apache.shiro.authz.AuthorizationInfo;importorg.apache.shiro.authz.SimpleAuthorizationInfo;importorg.apache.shiro.realm.AuthorizingRealm;importorg.apache.shiro.subject.PrincipalCollection;importorg.slf4j.Logger;importorg.slf4j.LoggerFactory;importjava.util.HashSet;importjava.util.Set;/** * JWT Realm类 * 用于处理JWT令牌的认证和授权 */publicclassJwtRealmextendsAuthorizingRealm{// 创建日志记录器用于输出程序运行信息privatestaticfinalLoggerlogLoggerFactory.getLogger(JwtRealm.class);/** * 设置 Realm 支持的AuthenticationToken类型 * param token 认证令牌 * return 是否支持该令牌类型 */Overridepublicbooleansupports(AuthenticationTokentoken){returntokeninstanceofJwtToken;}/** * 认证方法获取认证信息 * param authToken 认证令牌 * return 认证信息 * throws AuthenticationException 认证异常 */OverrideprotectedAuthenticationInfodoGetAuthenticationInfo(AuthenticationTokenauthToken)throwsAuthenticationException{log.info(JWT Realm 开始认证...);// 获取 JWT 令牌Stringtoken(String)authToken.getCredentials();// 验证 JWT 令牌if(!validateToken(token)){thrownewAuthenticationException(无效的 JWT 令牌);}// 从 JWT 令牌中获取用户名StringusernamegetUsernameFromToken(token);// 返回认证信息returnnewSimpleAuthenticationInfo(username,token,getName());}/** * 授权方法获取授权信息 * param principals 身份信息 * return 授权信息 */OverrideprotectedAuthorizationInfodoGetAuthorizationInfo(PrincipalCollectionprincipals){log.info(JWT Realm 开始授权...);// 获取用户名Stringusername(String)principals.getPrimaryPrincipal();// 创建授权信息对象SimpleAuthorizationInfoauthorizationInfonewSimpleAuthorizationInfo();// 添加角色模拟数据SetStringrolesgetUserRoles(username);authorizationInfo.setRoles(roles);// 添加权限模拟数据SetStringpermissionsgetUserPermissions(username);authorizationInfo.setStringPermissions(permissions);returnauthorizationInfo;}/** * 从 JWT 令牌中提取用户名 * param token JWT 令牌 * return 用户名 */privateStringgetUsernameFromToken(Stringtoken){try{returnJwts.parser().verifyWith(JwtUtils.SECRET_KEY).build().parseSignedClaims(token).getPayload().getSubject();}catch(JwtExceptione){log.error(解析 JWT 令牌失败,e);returnnull;}}/** * 验证 JWT 令牌的有效性 * param token JWT 令牌 * return 令牌是否有效 */privatebooleanvalidateToken(Stringtoken){try{Jwts.parser().verifyWith(JwtUtils.SECRET_KEY).build().parseSignedClaims(token);returntrue;}catch(JwtExceptione){log.error(JWT 令牌验证失败,e);returnfalse;}}/** * 获取用户角色模拟实现 * param username 用户名 * return 用户角色集合 */privateSetStringgetUserRoles(Stringusername){SetStringrolesnewHashSet();// 模拟用户角色数据if(admin.equals(username)){roles.add(admin);roles.add(user);}elseif(user.equals(username)){roles.add(user);}returnroles;}/** * 获取用户权限模拟实现 * param username 用户名 * return 用户权限集合 */privateSetStringgetUserPermissions(Stringusername){SetStringpermissionsnewHashSet();// 模拟用户权限数据if(admin.equals(username)){permissions.add(user:*);permissions.add(product:*);}elseif(user.equals(username)){permissions.add(product:view);permissions.add(product:create);}returnpermissions;}} JWT集成示例项目代码文件src/main/java/com/shiro/tutorial/jwt/JwtShiroExample.javapackagecom.shiro.tutorial.jwt;importorg.apache.shiro.SecurityUtils;importorg.apache.shiro.mgt.DefaultSecurityManager;importorg.apache.shiro.subject.Subject;importorg.slf4j.Logger;importorg.slf4j.LoggerFactory;/** * Apache Shiro JWT集成示例类 * 开发思路 * 1. 创建JWT工具类用于生成和验证JWT令牌 * 2. 创建JWT Realm处理JWT认证和授权 * 3. 配置安全管理器使用JWT Realm * 4. 演示JWT令牌的生成和验证过程 */publicclassJwtShiroExample{// 创建日志记录器用于输出程序运行信息privatestaticfinalLoggerlogLoggerFactory.getLogger(JwtShiroExample.class);/** * 程序入口方法 * 开发过程 * 1. 初始化Shiro安全框架组件使用JWT Realm * 2. 生成JWT令牌 * 3. 使用JWT令牌进行用户身份认证和授权验证 */publicstaticvoidmain(String[]args){// 创建JWT Realm实例JwtRealmjwtRealmnewJwtRealm();// 创建 SecurityManager 安全管理器实例并传入JWT RealmDefaultSecurityManagersecurityManagernewDefaultSecurityManager(jwtRealm);// 将 SecurityManager 绑定到 SecurityUtils 工具类SecurityUtils.setSecurityManager(securityManager);// 获取当前执行用户SubjectSubjectcurrentUserSecurityUtils.getSubject();// 生成JWT令牌模拟用户登录成功后生成令牌StringjwtTokenJwtUtils.generateToken(admin);log.info(生成的JWT令牌: {},jwtToken);// 验证 JWT 令牌booleanisValidJwtUtils.validateToken(jwtToken);log.info(JWT令牌是否有效: {},isValid);// 从 JWT 令牌中提取用户名StringusernameJwtUtils.getUsernameFromToken(jwtToken);log.info(从JWT令牌中提取的用户名: {},username);// 使用 JWT 令牌进行认证JwtTokentokennewJwtToken(jwtToken);try{// 使用 JWT 令牌进行用户登录认证currentUser.login(token);// 认证成功后记录用户登录成功的日志信息log.info(用户 {} 使用JWT令牌登录成功,currentUser.getPrincipal());}catch(Exceptione){log.error(JWT 令牌认证失败,e);}// 验证用户是否有 admin 角色if(currentUser.hasRole(admin)){log.info(用户具有 admin 角色);}else{log.info(用户不具有 admin 角色);}// 验证用户是否有user:delete权限if(currentUser.isPermitted(user:delete)){log.info(用户有删除用户的权限);}else{log.info(用户没有删除用户的权限);}System.exit(0);}} 代码执行逻辑是否是否是否是否创建JwtRealm实例创建DefaultSecurityManager实例绑定到SecurityUtils获取Subject生成JWT令牌输出JWT令牌验证JWT令牌令牌有效?输出令牌有效日志输出令牌无效日志从令牌中提取用户名输出提取的用户名创建JwtToken对象执行登录登录成功?记录登录成功日志记录认证失败日志检查admin角色角色检查成功?记录角色检查通过日志记录角色检查失败日志检查user:delete权限权限检查成功?记录权限检查通过日志记录权限检查失败日志退出程序 JWT安全最佳实践使用强密钥选择足够长且复杂的密钥定期轮换合理设置过期时间根据业务需求设置适当的过期时间使用HTTPS传输确保JWT令牌在传输过程中不被窃取不要存储敏感信息令牌中只存储必要的非敏感信息实现令牌刷新机制支持令牌过期前的自动刷新添加黑名单机制支持主动吊销令牌使用合适的签名算法根据安全需求选择合适的签名算法 学习成果检验✅ 实践任务运行JwtShiroExample类观察JWT集成的结果学习JWT令牌的生成和验证过程理解无状态认证的优势和实现方法尝试修改JWT过期时间观察不同过期时间的效果尝试添加新的角色和权限到JwtRealm中实现JWT令牌的刷新机制 扩展学习JWT与传统Session的对比理解两种认证方式的优缺点JWT在分布式系统中的应用学习如何在微服务架构中使用JWTJWT加密了解如何对JWT令牌进行加密保护敏感信息JWT扩展声明学习如何自定义JWT声明添加额外的用户信息JWT性能优化了解如何优化JWT的生成和验证性能 总结与进阶 核心知识点回顾认证Authentication验证用户身份确认用户是否为系统合法用户授权Authorization检查用户权限确定用户可以访问哪些资源角色Role权限的集合用于批量分配权限给用户权限Permission对资源的访问许可采用资源:操作:实例格式会话Session管理用户的会话状态支持跨环境使用加密Encryption保护用户密码安全支持多种加密算法Realm连接Shiro与数据源的桥梁负责获取安全数据JWT无状态认证方式适合分布式系统 进阶学习建议深入学习Shiro源码理解Shiro的内部实现机制集成Spring Boot学习如何在Spring Boot项目中使用Shiro分布式会话管理学习如何使用Redis等存储会话多因素认证实现更安全的认证方式权限审计实现权限使用情况的审计日志性能优化学习如何优化Shiro的性能 推荐资源官方文档Apache Shiro DocumentationGitHub仓库apache/shiro中文教程Apache Shiro中文文档示例项目本教程配套的代码示例恭喜你完成了Apache Shiro完整教程的学习通过本教程的学习你已经掌握了Apache Shiro的核心概念和使用方法能够在实际项目中灵活应用Shiro实现安全认证和授权。建议你继续深入学习Shiro的高级特性并在实际项目中应用所学知识不断提升自己的安全开发能力。
版权声明:本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!

网站不收录是什么原因智慧团建网站登录忘记密码

Wan2.2-T2V-5B如何处理空间关系描述?实例演示 你有没有试过让AI生成一段视频,结果画面里的“车从左边开到右边”,可那辆车却像瞬移一样,压根没走直线?或者你说“鸟在云上面飞”,AI却把云堆到了天空底部………

张小明 2025/12/30 20:36:58 网站建设

网站PC关键词怎么做中国机械工程

在当今数字化时代,服务器管理变得越来越复杂,特别是当您需要管理多个服务器和端口转发规则时。Deploy面板应运而生,这是一款专为简化多服务器端口租用管理而设计的强大工具,让您能够轻松应对复杂的网络配置需求。 【免费下载链接】…

张小明 2025/12/30 20:36:56 网站建设

淘客怎样做自己的网站免费自己制作网站方法

Kettle-Manager:企业级数据集成管理的终极解决方案 【免费下载链接】kettle-manager 专门为kettle这款优秀的ETL工具开发的web端管理工具。 项目地址: https://gitcode.com/gh_mirrors/ke/kettle-manager 在数字化转型的浪潮中,数据集成已成为企业…

张小明 2025/12/30 20:36:54 网站建设

杯子网站开发方案天津外贸营销型网站建设

参考文档:正确安装GPU显卡驱动、CUDA、cuDNN的详细教程_cuda驱动-CSDN博客 如何将pytorch的cpu版改成gpu版【实测成功】_torch 2.0.1 修改 cpu cuda-CSDN博客 一、配置使用nvidia-smi 在cmd终端中输入“nvidia-smi ”命令,提示 nvidia-smi 不是内部或…

张小明 2025/12/30 20:36:51 网站建设

快速建站公司怎么样浙江省特种作业人员证书查询

我们今天开始讲原理图的部分,但是我们要讲一个问题,当我们在工作中需要画原理图的时候,我们是先要画原理图库的,就是起码你的库里得有这个元器件才能有原理图,那我们今天为什么先讲原理图呢?因为其实原理图…

张小明 2025/12/30 20:36:49 网站建设

长春城乡建设部网站首页用一个矿泉水瓶子做手工

还在为DiT模型推理卡顿、显存占用过高而烦恼吗?今天分享一套实测有效的INT8量化方案,让你轻松实现推理速度显著提升,显存占用减半!读完这篇文章,你将掌握从零开始的完整量化流程,避开所有常见问题。 【免费…

张小明 2025/12/30 20:36:47 网站建设