开州快速建网站,wordpress怎么做产品列表页,apache网站拒绝访问,外面网站怎么做的文章目录一、Shiro 核心功能二、Shiro 架构2.1 三层架构2.2 核心组件#xff08;SecurityManager 内部#xff09;三、核心流程详解3.1 认证流程#xff08;登录#xff09;流程步骤#xff1a;认证流程序列图#xff1a;3.2 授权流程#xff08;权限校验#xff09;流…
文章目录一、Shiro 核心功能二、Shiro 架构2.1 三层架构2.2 核心组件SecurityManager 内部三、核心流程详解3.1 认证流程登录流程步骤认证流程序列图3.2 授权流程权限校验流程步骤授权流程序列图3.3 会话管理1. 会话管理核心组件2. 会话管理流程3. 关键特性3.4 加密1. 核心加密组件2. 密码加密与验证流程3. 关于哈希和盐值的补充说明3.5 其他核心功能1. 缓存Caching2. rememberMe记住我3. 并发登录控制四、Shiro 核心组件详解4.1 Subject4.2 SecurityManager4.3 Realm五、Shiro 与 Web 集成核心配置web.xmlURL 权限配置shiro.ini六、同类型产品分析主流方案对比Shiro vs Spring Security一、Shiro 核心功能
Shiro 的核心功能可以概括为 “认证、授权、会话管理、加密”此外还提供了缓存、RememberMe 等辅助功能。
认证Authentication验证用户身份“你是谁”例如登录时校验用户名和密码。授权Authorization验证用户权限“你能做什么”例如判断用户是否有权限访问某个接口或按钮。会话管理Session Management管理用户会话即使在非 Web 环境中也能使用支持会话过期、会话存储等。加密Cryptography提供安全的加密算法如 MD5、SHA和密码哈希功能保护敏感数据。其他功能缓存提升权限校验性能、RememberMe记住登录状态、Web 集成、集群会话等。
二、Shiro 架构
Shiro 采用分层架构从外部到内部分为 “Subject - SecurityManager - Realms” 三层每层职责明确且内部包含多个核心组件协同工作。
2.1 三层架构 Subject对外的“用户”抽象可以是用户、进程等所有操作都通过 Subject 触发如登录、权限校验。SecurityManagerShiro 的核心负责协调内部组件完成安全操作如认证、授权是 Shiro 的“大脑”。Realms连接应用与数据源的桥梁用于获取用户信息用户名/密码和权限信息角色/权限Shiro 通过 Realms 验证身份和权限。
2.2 核心组件SecurityManager 内部
SecurityManager 内部包含多个组件分工处理不同的安全功能 Authenticator负责认证流程如校验用户名密码默认实现为 ModularRealmAuthenticator支持多 Realm 认证。Authorizer负责授权流程如校验用户是否有某权限默认实现为 ModularRealmAuthorizer。SessionManager管理用户会话不依赖 Web 容器如 Tomcat支持在非 Web 环境如 Swing 应用中使用。CacheManager缓存用户信息、权限数据等减少重复查询数据源的开销默认支持 EhCache、Redis 等。Cryptography提供加密工具类如 SimpleHash支持 MD5、SHA 等哈希算法避免明文存储密码。
SecurityManager 内部维护了一个或多个 Realm 实例。 SecurityManager 下管理的认证器、授权器会直接与 Realms 交互其他组件如 SessionManager、CacheManager 等不会直接访问 Realms。
三、核心流程详解
3.1 认证流程登录
认证流程是验证用户身份的过程核心是校验“用户提供的凭证如密码”与“数据源中的凭证”是否一致。
流程步骤
用户通过 Subject 提交认证请求如输入用户名密码。Subject 将请求委托给 SecurityManager。SecurityManager 委托 Authenticator 处理认证。Authenticator 通过 Realm 从数据源获取用户信息如数据库中的密码。Authenticator 比对用户提交的凭证与数据源中的凭证返回认证结果。
认证流程序列图
#mermaid-svg-tQeTt9n660e3MeAt {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-tQeTt9n660e3MeAt .error-icon{fill:#552222;}#mermaid-svg-tQeTt9n660e3MeAt .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-tQeTt9n660e3MeAt .edge-thickness-normal{stroke-width:2px;}#mermaid-svg-tQeTt9n660e3MeAt .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-tQeTt9n660e3MeAt .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-tQeTt9n660e3MeAt .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-tQeTt9n660e3MeAt .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-tQeTt9n660e3MeAt .marker{fill:#333333;stroke:#333333;}#mermaid-svg-tQeTt9n660e3MeAt .marker.cross{stroke:#333333;}#mermaid-svg-tQeTt9n660e3MeAt svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-tQeTt9n660e3MeAt .actor{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-tQeTt9n660e3MeAt text.actortspan{fill:black;stroke:none;}#mermaid-svg-tQeTt9n660e3MeAt .actor-line{stroke:grey;}#mermaid-svg-tQeTt9n660e3MeAt .messageLine0{stroke-width:1.5;stroke-dasharray:none;stroke:#333;}#mermaid-svg-tQeTt9n660e3MeAt .messageLine1{stroke-width:1.5;stroke-dasharray:2,2;stroke:#333;}#mermaid-svg-tQeTt9n660e3MeAt #arrowhead path{fill:#333;stroke:#333;}#mermaid-svg-tQeTt9n660e3MeAt .sequenceNumber{fill:white;}#mermaid-svg-tQeTt9n660e3MeAt #sequencenumber{fill:#333;}#mermaid-svg-tQeTt9n660e3MeAt #crosshead path{fill:#333;stroke:#333;}#mermaid-svg-tQeTt9n660e3MeAt .messageText{fill:#333;stroke:#333;}#mermaid-svg-tQeTt9n660e3MeAt .labelBox{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-tQeTt9n660e3MeAt .labelText,#mermaid-svg-tQeTt9n660e3MeAt .labelTexttspan{fill:black;stroke:none;}#mermaid-svg-tQeTt9n660e3MeAt .loopText,#mermaid-svg-tQeTt9n660e3MeAt .loopTexttspan{fill:black;stroke:none;}#mermaid-svg-tQeTt9n660e3MeAt .loopLine{stroke-width:2px;stroke-dasharray:2,2;stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);}#mermaid-svg-tQeTt9n660e3MeAt .note{stroke:#aaaa33;fill:#fff5ad;}#mermaid-svg-tQeTt9n660e3MeAt .noteText,#mermaid-svg-tQeTt9n660e3MeAt .noteTexttspan{fill:black;stroke:none;}#mermaid-svg-tQeTt9n660e3MeAt .activation0{fill:#f4f4f4;stroke:#666;}#mermaid-svg-tQeTt9n660e3MeAt .activation1{fill:#f4f4f4;stroke:#666;}#mermaid-svg-tQeTt9n660e3MeAt .activation2{fill:#f4f4f4;stroke:#666;}#mermaid-svg-tQeTt9n660e3MeAt .actorPopupMenu{position:absolute;}#mermaid-svg-tQeTt9n660e3MeAt .actorPopupMenuPanel{position:absolute;fill:#ECECFF;box-shadow:0px 8px 16px 0px rgba(0,0,0,0.2);filter:drop-shadow(3px 5px 2px rgb(0 0 0 / 0.4));}#mermaid-svg-tQeTt9n660e3MeAt .actor-man line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-tQeTt9n660e3MeAt .actor-man circle,#mermaid-svg-tQeTt9n660e3MeAt line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;stroke-width:2px;}#mermaid-svg-tQeTt9n660e3MeAt :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;}UserSubjectSecurityManagerAuthenticatorRealm数据源DB/文件提交认证用户名/密码委托认证执行认证获取用户信息查询用户数据密码返回用户数据返回用户信息含凭证比对凭证如密码返回认证结果成功/失败返回结果提示登录结果UserSubjectSecurityManagerAuthenticatorRealm数据源DB/文件3.2 授权流程权限校验
授权流程是验证用户是否有权限执行某个操作的过程核心是检查“用户拥有的权限”是否包含“操作所需的权限”。
流程步骤
用户通过 Subject 发起权限校验请求如访问某接口。Subject 将请求委托给 SecurityManager。SecurityManager 委托 Authorizer 处理授权。Authorizer 通过 Realm 从数据源获取用户的权限信息角色/权限。Authorizer 校验用户权限是否满足操作需求返回授权结果。
授权流程序列图
#mermaid-svg-93oMmbBBkFnuPtyh {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-93oMmbBBkFnuPtyh .error-icon{fill:#552222;}#mermaid-svg-93oMmbBBkFnuPtyh .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-93oMmbBBkFnuPtyh .edge-thickness-normal{stroke-width:2px;}#mermaid-svg-93oMmbBBkFnuPtyh .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-93oMmbBBkFnuPtyh .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-93oMmbBBkFnuPtyh .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-93oMmbBBkFnuPtyh .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-93oMmbBBkFnuPtyh .marker{fill:#333333;stroke:#333333;}#mermaid-svg-93oMmbBBkFnuPtyh .marker.cross{stroke:#333333;}#mermaid-svg-93oMmbBBkFnuPtyh svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-93oMmbBBkFnuPtyh .actor{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-93oMmbBBkFnuPtyh text.actortspan{fill:black;stroke:none;}#mermaid-svg-93oMmbBBkFnuPtyh .actor-line{stroke:grey;}#mermaid-svg-93oMmbBBkFnuPtyh .messageLine0{stroke-width:1.5;stroke-dasharray:none;stroke:#333;}#mermaid-svg-93oMmbBBkFnuPtyh .messageLine1{stroke-width:1.5;stroke-dasharray:2,2;stroke:#333;}#mermaid-svg-93oMmbBBkFnuPtyh #arrowhead path{fill:#333;stroke:#333;}#mermaid-svg-93oMmbBBkFnuPtyh .sequenceNumber{fill:white;}#mermaid-svg-93oMmbBBkFnuPtyh #sequencenumber{fill:#333;}#mermaid-svg-93oMmbBBkFnuPtyh #crosshead path{fill:#333;stroke:#333;}#mermaid-svg-93oMmbBBkFnuPtyh .messageText{fill:#333;stroke:#333;}#mermaid-svg-93oMmbBBkFnuPtyh .labelBox{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-93oMmbBBkFnuPtyh .labelText,#mermaid-svg-93oMmbBBkFnuPtyh .labelTexttspan{fill:black;stroke:none;}#mermaid-svg-93oMmbBBkFnuPtyh .loopText,#mermaid-svg-93oMmbBBkFnuPtyh .loopTexttspan{fill:black;stroke:none;}#mermaid-svg-93oMmbBBkFnuPtyh .loopLine{stroke-width:2px;stroke-dasharray:2,2;stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);}#mermaid-svg-93oMmbBBkFnuPtyh .note{stroke:#aaaa33;fill:#fff5ad;}#mermaid-svg-93oMmbBBkFnuPtyh .noteText,#mermaid-svg-93oMmbBBkFnuPtyh .noteTexttspan{fill:black;stroke:none;}#mermaid-svg-93oMmbBBkFnuPtyh .activation0{fill:#f4f4f4;stroke:#666;}#mermaid-svg-93oMmbBBkFnuPtyh .activation1{fill:#f4f4f4;stroke:#666;}#mermaid-svg-93oMmbBBkFnuPtyh .activation2{fill:#f4f4f4;stroke:#666;}#mermaid-svg-93oMmbBBkFnuPtyh .actorPopupMenu{position:absolute;}#mermaid-svg-93oMmbBBkFnuPtyh .actorPopupMenuPanel{position:absolute;fill:#ECECFF;box-shadow:0px 8px 16px 0px rgba(0,0,0,0.2);filter:drop-shadow(3px 5px 2px rgb(0 0 0 / 0.4));}#mermaid-svg-93oMmbBBkFnuPtyh .actor-man line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-93oMmbBBkFnuPtyh .actor-man circle,#mermaid-svg-93oMmbBBkFnuPtyh line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;stroke-width:2px;}#mermaid-svg-93oMmbBBkFnuPtyh :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;}UserSubjectSecurityManagerAuthorizerRealm数据源DB/文件触发权限校验如访问接口委托授权校验执行授权获取用户权限角色/权限查询权限数据返回权限数据返回用户权限校验权限是否包含所需权限返回授权结果允许/拒绝返回结果允许操作/拒绝访问UserSubjectSecurityManagerAuthorizerRealm数据源DB/文件3.3 会话管理
Shiro 的会话管理是其核心功能之一支持跨环境Web/非Web的会话统一管理无需依赖容器如Tomcat的会话机制且提供丰富的会话控制能力。
1. 会话管理核心组件
#mermaid-svg-i0fU7HoQwXT4YOE4 {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-i0fU7HoQwXT4YOE4 .error-icon{fill:#552222;}#mermaid-svg-i0fU7HoQwXT4YOE4 .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-i0fU7HoQwXT4YOE4 .edge-thickness-normal{stroke-width:2px;}#mermaid-svg-i0fU7HoQwXT4YOE4 .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-i0fU7HoQwXT4YOE4 .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-i0fU7HoQwXT4YOE4 .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-i0fU7HoQwXT4YOE4 .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-i0fU7HoQwXT4YOE4 .marker{fill:#333333;stroke:#333333;}#mermaid-svg-i0fU7HoQwXT4YOE4 .marker.cross{stroke:#333333;}#mermaid-svg-i0fU7HoQwXT4YOE4 svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-i0fU7HoQwXT4YOE4 .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-i0fU7HoQwXT4YOE4 .cluster-label text{fill:#333;}#mermaid-svg-i0fU7HoQwXT4YOE4 .cluster-label span{color:#333;}#mermaid-svg-i0fU7HoQwXT4YOE4 .label text,#mermaid-svg-i0fU7HoQwXT4YOE4 span{fill:#333;color:#333;}#mermaid-svg-i0fU7HoQwXT4YOE4 .node rect,#mermaid-svg-i0fU7HoQwXT4YOE4 .node circle,#mermaid-svg-i0fU7HoQwXT4YOE4 .node ellipse,#mermaid-svg-i0fU7HoQwXT4YOE4 .node polygon,#mermaid-svg-i0fU7HoQwXT4YOE4 .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-i0fU7HoQwXT4YOE4 .node .label{text-align:center;}#mermaid-svg-i0fU7HoQwXT4YOE4 .node.clickable{cursor:pointer;}#mermaid-svg-i0fU7HoQwXT4YOE4 .arrowheadPath{fill:#333333;}#mermaid-svg-i0fU7HoQwXT4YOE4 .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-i0fU7HoQwXT4YOE4 .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-i0fU7HoQwXT4YOE4 .edgeLabel{background-color:#e8e8e8;text-align:center;}#mermaid-svg-i0fU7HoQwXT4YOE4 .edgeLabel rect{opacity:0.5;background-color:#e8e8e8;fill:#e8e8e8;}#mermaid-svg-i0fU7HoQwXT4YOE4 .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-i0fU7HoQwXT4YOE4 .cluster text{fill:#333;}#mermaid-svg-i0fU7HoQwXT4YOE4 .cluster span{color:#333;}#mermaid-svg-i0fU7HoQwXT4YOE4 div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-i0fU7HoQwXT4YOE4 :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;}SecurityManagerSessionManager 会话管理器SessionDAO 会话持久化SessionListener 会话监听器SessionValidationScheduler 会话验证调度器SessionManager管理所有会话的生命周期创建、读取、更新、删除默认实现为 DefaultSessionManager非Web环境和 ServletContainerSessionManagerWeb环境依赖容器会话推荐自定义 DefaultWebSessionManager 实现独立管理。SessionDAO负责会话的持久化如内存、数据库、Redis等常用实现 MemorySessionDAO默认内存存储适合开发环境。EnterpriseCacheSessionDAO缓存存储结合EhCache/Redis。自定义DAO集成Redis实现分布式会话解决集群会话共享问题。 SessionListener监听会话创建、过期、停止等事件如记录用户登录日志。SessionValidationScheduler定期验证会话有效性清理过期会话默认每30分钟执行一次。
2. 会话管理流程
#mermaid-svg-eaeJ8dE22l3B3vFV {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-eaeJ8dE22l3B3vFV .error-icon{fill:#552222;}#mermaid-svg-eaeJ8dE22l3B3vFV .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-eaeJ8dE22l3B3vFV .edge-thickness-normal{stroke-width:2px;}#mermaid-svg-eaeJ8dE22l3B3vFV .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-eaeJ8dE22l3B3vFV .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-eaeJ8dE22l3B3vFV .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-eaeJ8dE22l3B3vFV .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-eaeJ8dE22l3B3vFV .marker{fill:#333333;stroke:#333333;}#mermaid-svg-eaeJ8dE22l3B3vFV .marker.cross{stroke:#333333;}#mermaid-svg-eaeJ8dE22l3B3vFV svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-eaeJ8dE22l3B3vFV .actor{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-eaeJ8dE22l3B3vFV text.actortspan{fill:black;stroke:none;}#mermaid-svg-eaeJ8dE22l3B3vFV .actor-line{stroke:grey;}#mermaid-svg-eaeJ8dE22l3B3vFV .messageLine0{stroke-width:1.5;stroke-dasharray:none;stroke:#333;}#mermaid-svg-eaeJ8dE22l3B3vFV .messageLine1{stroke-width:1.5;stroke-dasharray:2,2;stroke:#333;}#mermaid-svg-eaeJ8dE22l3B3vFV #arrowhead path{fill:#333;stroke:#333;}#mermaid-svg-eaeJ8dE22l3B3vFV .sequenceNumber{fill:white;}#mermaid-svg-eaeJ8dE22l3B3vFV #sequencenumber{fill:#333;}#mermaid-svg-eaeJ8dE22l3B3vFV #crosshead path{fill:#333;stroke:#333;}#mermaid-svg-eaeJ8dE22l3B3vFV .messageText{fill:#333;stroke:#333;}#mermaid-svg-eaeJ8dE22l3B3vFV .labelBox{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-eaeJ8dE22l3B3vFV .labelText,#mermaid-svg-eaeJ8dE22l3B3vFV .labelTexttspan{fill:black;stroke:none;}#mermaid-svg-eaeJ8dE22l3B3vFV .loopText,#mermaid-svg-eaeJ8dE22l3B3vFV .loopTexttspan{fill:black;stroke:none;}#mermaid-svg-eaeJ8dE22l3B3vFV .loopLine{stroke-width:2px;stroke-dasharray:2,2;stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);}#mermaid-svg-eaeJ8dE22l3B3vFV .note{stroke:#aaaa33;fill:#fff5ad;}#mermaid-svg-eaeJ8dE22l3B3vFV .noteText,#mermaid-svg-eaeJ8dE22l3B3vFV .noteTexttspan{fill:black;stroke:none;}#mermaid-svg-eaeJ8dE22l3B3vFV .activation0{fill:#f4f4f4;stroke:#666;}#mermaid-svg-eaeJ8dE22l3B3vFV .activation1{fill:#f4f4f4;stroke:#666;}#mermaid-svg-eaeJ8dE22l3B3vFV .activation2{fill:#f4f4f4;stroke:#666;}#mermaid-svg-eaeJ8dE22l3B3vFV .actorPopupMenu{position:absolute;}#mermaid-svg-eaeJ8dE22l3B3vFV .actorPopupMenuPanel{position:absolute;fill:#ECECFF;box-shadow:0px 8px 16px 0px rgba(0,0,0,0.2);filter:drop-shadow(3px 5px 2px rgb(0 0 0 / 0.4));}#mermaid-svg-eaeJ8dE22l3B3vFV .actor-man line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-eaeJ8dE22l3B3vFV .actor-man circle,#mermaid-svg-eaeJ8dE22l3B3vFV line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;stroke-width:2px;}#mermaid-svg-eaeJ8dE22l3B3vFV :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;}用户SubjectSecurityManagerSessionManagerSessionDAO操作登录/请求获取会话创建/获取Session持久化Session如Redis返回Session返回Session返回Session操作响应定期触发SessionValidationScheduler清理过期会话用户SubjectSecurityManagerSessionManagerSessionDAO3. 关键特性
会话标识Session ID自动生成唯一ID可通过 session.getId() 获取常用于跟踪用户会话。会话属性支持存储自定义属性如 session.setAttribute(user, userInfo)实现用户信息跨请求共享。过期控制可设置全局过期时间如30分钟无操作失效或单个会话过期时间session.setTimeout(3600000)。分布式支持通过自定义 SessionDAO 集成Redis实现多服务器间会话共享解决集群环境下登录状态同步问题。
3.4 加密
Shiro 提供简化的加密工具封装了常见加密算法避免直接操作复杂的Java加密API常用于密码加密存储。
1. 核心加密组件
HashService提供哈希计算如MD5、SHA-256SimpleHash 是常用实现需指定算法、原始数据、盐值、哈希次数。盐值Salt随机生成的字符串与密码混合后哈希防止彩虹表破解如 salt new SecureRandomNumberGenerator().nextBytes()。CredentialsMatcher验证用户提交的凭证如密码与存储的哈希值是否匹配如 HashedCredentialsMatcher。
2. 密码加密与验证流程
#mermaid-svg-xRD7NK4KoPjKwpCg {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-xRD7NK4KoPjKwpCg .error-icon{fill:#552222;}#mermaid-svg-xRD7NK4KoPjKwpCg .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-xRD7NK4KoPjKwpCg .edge-thickness-normal{stroke-width:2px;}#mermaid-svg-xRD7NK4KoPjKwpCg .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-xRD7NK4KoPjKwpCg .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-xRD7NK4KoPjKwpCg .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-xRD7NK4KoPjKwpCg .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-xRD7NK4KoPjKwpCg .marker{fill:#333333;stroke:#333333;}#mermaid-svg-xRD7NK4KoPjKwpCg .marker.cross{stroke:#333333;}#mermaid-svg-xRD7NK4KoPjKwpCg svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-xRD7NK4KoPjKwpCg .actor{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-xRD7NK4KoPjKwpCg text.actortspan{fill:black;stroke:none;}#mermaid-svg-xRD7NK4KoPjKwpCg .actor-line{stroke:grey;}#mermaid-svg-xRD7NK4KoPjKwpCg .messageLine0{stroke-width:1.5;stroke-dasharray:none;stroke:#333;}#mermaid-svg-xRD7NK4KoPjKwpCg .messageLine1{stroke-width:1.5;stroke-dasharray:2,2;stroke:#333;}#mermaid-svg-xRD7NK4KoPjKwpCg #arrowhead path{fill:#333;stroke:#333;}#mermaid-svg-xRD7NK4KoPjKwpCg .sequenceNumber{fill:white;}#mermaid-svg-xRD7NK4KoPjKwpCg #sequencenumber{fill:#333;}#mermaid-svg-xRD7NK4KoPjKwpCg #crosshead path{fill:#333;stroke:#333;}#mermaid-svg-xRD7NK4KoPjKwpCg .messageText{fill:#333;stroke:#333;}#mermaid-svg-xRD7NK4KoPjKwpCg .labelBox{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-xRD7NK4KoPjKwpCg .labelText,#mermaid-svg-xRD7NK4KoPjKwpCg .labelTexttspan{fill:black;stroke:none;}#mermaid-svg-xRD7NK4KoPjKwpCg .loopText,#mermaid-svg-xRD7NK4KoPjKwpCg .loopTexttspan{fill:black;stroke:none;}#mermaid-svg-xRD7NK4KoPjKwpCg .loopLine{stroke-width:2px;stroke-dasharray:2,2;stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);}#mermaid-svg-xRD7NK4KoPjKwpCg .note{stroke:#aaaa33;fill:#fff5ad;}#mermaid-svg-xRD7NK4KoPjKwpCg .noteText,#mermaid-svg-xRD7NK4KoPjKwpCg .noteTexttspan{fill:black;stroke:none;}#mermaid-svg-xRD7NK4KoPjKwpCg .activation0{fill:#f4f4f4;stroke:#666;}#mermaid-svg-xRD7NK4KoPjKwpCg .activation1{fill:#f4f4f4;stroke:#666;}#mermaid-svg-xRD7NK4KoPjKwpCg .activation2{fill:#f4f4f4;stroke:#666;}#mermaid-svg-xRD7NK4KoPjKwpCg .actorPopupMenu{position:absolute;}#mermaid-svg-xRD7NK4KoPjKwpCg .actorPopupMenuPanel{position:absolute;fill:#ECECFF;box-shadow:0px 8px 16px 0px rgba(0,0,0,0.2);filter:drop-shadow(3px 5px 2px rgb(0 0 0 / 0.4));}#mermaid-svg-xRD7NK4KoPjKwpCg .actor-man line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-xRD7NK4KoPjKwpCg .actor-man circle,#mermaid-svg-xRD7NK4KoPjKwpCg line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;stroke-width:2px;}#mermaid-svg-xRD7NK4KoPjKwpCg :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;}用户注册/登录系统SimpleHashHashedCredentialsMatcher注册阶段提交明文密码如123456生成盐值Salt 哈希计算算法SHA-256盐值随机字符串迭代1024次存储哈希值 盐值到数据库登录阶段提交明文密码如123456从数据库获取存储的哈希值 盐值用相同盐值和算法哈希输入密码对比输入哈希值与存储哈希值匹配结果成功/失败登录结果用户注册/登录系统SimpleHashHashedCredentialsMatcher3. 关于哈希和盐值的补充说明
在Shiro等安全框架中哈希Hash 和盐值Salt 是保护密码的核心技术用于将明文密码转换为不可逆的密文同时抵御常见的破解手段。下面通过原理拆解和流程示例清晰说明它们的作用 哈希Hash将密码单向转换为密文 哈希算法如MD5、SHA-256、Shiro中的SimpleHash是一种单向加密函数它能将任意长度的输入如明文密码转换为固定长度的输出哈希值即密文且无法从哈希值反推回明文。 哈希的核心作用 不可逆性 例如明文123456通过SHA-256哈希后可能得到8d969eef6ecad3c29a3a629280e686cf0c3f5d5a86aff3ca12020c923adc6c92但无法从这个哈希值反算出123456。这意味着即使数据库泄露攻击者也无法直接获取明文密码。固定长度输出 无论输入是1个字符还是1000个字符哈希值长度固定如SHA-256始终输出64个字符避免密码长度泄露。雪崩效应 输入的微小变化如密码从123456改为123457会导致哈希值完全不同进一步增强安全性。 盐值Salt解决相同密码哈希值相同的漏洞 哈希算法有一个问题相同的明文会生成完全相同的哈希值。例如两个用户都用123456作为密码它们的哈希值完全一样。这会导致两个风险 攻击者可通过彩虹表预计算的常见密码哈希值字典快速匹配出明文一旦一个用户密码被破解所有使用相同密码的用户都会暴露。 盐值的作用给每个密码添加一个随机唯一的字符串盐值再进行哈希确保即使明文相同最终的哈希值也不同。 盐值的特性 随机性每个用户的盐值独立生成不可预测唯一性通常与用户账号绑定如存储在用户表中确保同一用户的盐值固定公开性盐值不需要保密可随哈希值一起存储因为破解难度不在盐值本身而在加盐后的哈希计算。 为什么哈希盐值能有效防破解 抵御彩虹表攻击 彩虹表是预计算的明文-哈希值对应表但加盐后相同明文的哈希值完全不同攻击者需要为每个可能的盐值生成彩虹表计算量呈指数级增长几乎不可能实现。防止批量破解 即使两个用户密码相同由于盐值不同哈希值也不同破解一个用户的密码不会影响其他用户。增加暴力破解难度 暴力破解逐个尝试明文并计算哈希的效率极低尤其是配合哈希迭代次数如Shiro的hashIterations重复多次哈希计算可进一步增加破解时间。
3.5 其他核心功能
1. 缓存Caching
作用缓存用户权限信息如角色、权限减少数据库查询提升性能。核心组件 CacheManager管理缓存默认集成EhCache可替换为RedisCacheManager。AuthorizingRealm通过 doGetAuthorizationInfo 加载权限时自动缓存默认缓存时间由缓存管理器配置。 使用场景用户登录后权限信息被缓存后续授权操作直接从缓存获取直至缓存过期或用户权限更新。
2. rememberMe记住我
功能用户勾选“记住我”后关闭浏览器再打开无需重新登录即可访问非敏感资源。实现原理 登录成功后Shiro生成加密的 rememberMe Cookie包含用户标识存储在客户端。下次访问时Shiro读取Cookie并自动登录但 subject.isAuthenticated() 为 falsesubject.isRemembered() 为 true。 安全控制敏感操作如支付需强制要求用户重新认证subject.isAuthenticated() true。
3. 并发登录控制
功能限制同一用户同时登录的设备数量如只允许一个设备在线。实现方式 自定义 SessionListener登录时检查该用户的活跃会话数量。超过限制时强制踢出旧会话oldSession.stop()。
四、Shiro 核心组件详解
4.1 Subject
定义代表当前“用户”可以是真实用户、进程、服务等是开发者与 Shiro 交互的入口。常用方法 login(AuthenticationToken token)登录提交认证。isAuthenticated()判断是否已认证登录成功。hasRole(String role)判断是否拥有某个角色。checkPermission(String permission)校验是否拥有某个权限无权限时抛异常。getSession()获取当前会话。
4.2 SecurityManager
定义Shiro 的核心管理器协调所有组件认证、授权、会话等开发者需先初始化并配置它。初始化示例通过 Ini 配置文件// 读取 Shiro 配置文件
FactorySecurityManager factory new IniSecurityManagerFactory(classpath:shiro.ini);
SecurityManager securityManager factory.getInstance();
// 设置全局 SecurityManager
SecurityUtils.setSecurityManager(securityManager);4.3 Realm 定义连接应用与数据源的桥梁负责提供用户信息认证和权限信息授权。 常见类型 IniRealm从 ini 配置文件读取用户/权限数据适合简单场景。JdbcRealm从数据库读取数据需配置 SQL 语句。自定义 Realm继承 AuthorizingRealm重写认证和授权方法适合复杂业务。 自定义 Realm 示例 public class MyRealm extends AuthorizingRealm {// 授权获取用户权限Overrideprotected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {String username (String) principals.getPrimaryPrincipal();// 从数据库查询用户权限示例SetString permissions new HashSet();permissions.add(user:query);SimpleAuthorizationInfo info new SimpleAuthorizationInfo();info.setStringPermissions(permissions);return info;}// 认证获取用户凭证Overrideprotected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {String username (String) token.getPrincipal();// 从数据库查询密码示例String password 123456; // 实际应从 DB 读取return new SimpleAuthenticationInfo(username, password, getName());}
}五、Shiro 与 Web 集成
在 Web 应用中Shiro 通过 Filter 拦截请求实现 URL 级别的权限控制。
核心配置web.xml
!-- Shiro 过滤器 --
filterfilter-nameshiroFilter/filter-namefilter-classorg.apache.shiro.web.servlet.ShiroFilter/filter-class
/filter
filter-mappingfilter-nameshiroFilter/filter-nameurl-pattern/*/url-pattern
/filter-mappingURL 权限配置shiro.ini
[urls]
/login anon # 登录页允许匿名访问
/logout logout # 退出登录
/user/** authc, perms[user:manage] # /user/** 路径需认证且拥有 user:manage 权限
/admin/** authc, roles[admin] # /admin/** 路径需认证且拥有 admin 角色六、同类型产品分析
在Java生态中主流的安全框架以 Apache Shiro 和 Spring Security 为主此外还有针对特定场景的解决方案如Keycloak、Pac4j等。选择框架时需结合项目规模、技术栈、安全需求复杂度等因素。
主流方案对比Shiro vs Spring Security
两者是最常用的企业级安全框架核心功能覆盖认证、授权、加密等但设计理念和适用场景差异显著。
对比维度Apache ShiroSpring Security设计理念简洁、易用强调“开箱即用”API直观易懂功能全面强调“深度集成Spring生态”灵活性强核心功能认证、授权、会话管理、加密、缓存集成认证、授权、OAuth2.0/OpenID Connect、SSO、LDAP等功能更全易用性学习曲线平缓配置简单XML/注解均可文档清晰学习曲线较陡配置复杂依赖Spring生态知识集成性与Spring、Java EE、Servlet、JAX-RS等均可集成不绑定特定框架深度绑定Spring生态Spring Boot/Cloud无缝集成非Spring项目集成较麻烦会话管理内置独立会话管理不依赖Servlet容器支持分布式会话早期依赖Servlet容器会话需配合Spring Session实现分布式扩展能力扩展点明确如Realm、Filter适合简单扩展扩展点极多如SecurityContext、AuthenticationProvider适合复杂场景定制适用场景中小型应用、快速开发、多框架集成、非Spring项目大型企业应用、Spring生态项目、复杂安全需求如SSO、OAuth2社区活跃度社区稳定更新频率中等2023年发布1.12.0版本社区活跃更新频繁依赖Spring版本迭代
Shiro是“简单场景的最优解”以低学习成本满足基础安全需求Spring Security是“复杂场景的全能选手”适合深度集成Spring生态的大型项目。选型时不必纠结“功能多少”而应聚焦“项目实际需求”和“团队技术栈匹配度”——合适的才是最好的。