• 【Apache Shiro】超详细笔记-2:授权、会话、缓存、RememberMe


    前言:本文为自己的学习笔记,现在分享出来,学习自视频教程:https://www.bilibili.com/video/BV1YW411M7S3/?vd_source=c065096d42cce8d2c3be93dd0f80d434

    1 授权

    概念

    • 授权,也叫访问控制,即在应用中控制谁访问哪些资源(如访问页面/编辑数据/页面操作等)。在授权中需了解的几个关键对象:主体(Subject)、资源(Resource)、权限(Permission)、角色(Role)。
    • 主体(Subject):访问应用的用户,在 Shiro 中使用 Subject 代表该用户。用户只有授权后才允许访问相应的资源。
    • 资源(Resource):在应用中用户可以访问的 URL,比如访问 JSP 页面、查看/编辑某些数据、访问某个业务方法、打印文本等等都是资源。用户只要授权后才能访问。
    • 权限(Permission):安全策略中的原子授权单位,通过权限我们可以表示在应用中用户有没有操作某个资源的权力。即权限表示在应用中用户能不能访问某个资源,如:访问用
    户列表页面查看/新增/修改/删除用户数据(即很多时候都是CRUD(增查改删)式权限控制)等。权限代表了用户有没有操作某个资源的权利,即反映在某个资源上的操作允不允
    许。
    • Shiro 支持粗粒度权限(如用户模块的所有权限)和细粒度权限(操作某个用户的权限,即实例级别的)
    • 角色(Role):权限的集合,一般情况下会赋予用户角色而不是权限,即这样用户可以拥有一组权限,赋予权限时比较方便。典型的如:项目经理、技术总监、CTO、开发工程师等都是角色,不同的角色拥有一组不同的权限

    授权方式

    Shiro 支持三种方式的授权:
    – 编程式:通过写if/else 授权代码块完成
    – 注解式:通过在执行的Java方法上放置相应的注解完成,没有权限将抛出相
    应的异常
    – JSP/GSP 标签:在JSP/GSP 页面通过相应的标签完成
    在这里插入图片描述

    授权流程

    在这里插入图片描述
    • 1、首先调用 Subject.isPermitted*/hasRole* 接口,其会委托给SecurityManager,而 SecurityManager 接着会委托给 Authorizer;
    • 2、Authorizer是真正的授权者,如果调用如isPermitted(“user:view”),其首先会通过
    • PermissionResolver 把字符串转换成相应的 Permission 实例;
    • 3、在进行授权之前,其会调用相应的 Realm 获取 Subject 相应的角色/权限用于匹配传入的角色/权限;
    • 4、Authorizer 会判断 Realm 的角色/权限是否和传入的匹配,如果有多个Realm,会委托给 ModularRealmAuthorizer 进行循环判断,如果匹配如 isPermitted*/hasRole* 会返回true,否则返回false表示授权失败。

    ModularRealmAuthorizer

    ModularRealmAuthorizer 进行多 Realm 匹配流程:
    – 1、首先检查相应的 Realm 是否实现了实现了Authorizer;
    – 2、如果实现了 Authorizer,那么接着调用其相应的isPermitted*/hasRole* 接口进行匹配;
    – 3、如果有一个Realm匹配那么将返回 true,否则返回 false。

    权限注解

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

    自定义拦截器

    通过自定义拦截器可以扩展功能,例如:动态url-角色/权限访问控制的实现、根据 Subject 身份信息获取用户信息绑定到 Request(即设置通用数据)、验证码验证、在线用户信息的保存等

    2 会话管理

    概述

    Shiro 提供了完整的企业级会话管理功能,不依赖于底层容器(如web容器tomcat),不管 JavaSE 还是 JavaEE 环境都可以使用,提供了会话管理、会话事件监听、会话存储/持久化、容器无关的集群、失效/过期支持、对Web 的透明支持、SSO 单点登录的支持等特性。

    会话相关的 API

    • Subject.getSession():即可获取会话;其等价于Subject.getSession(true),即如果当前没有创建 Session 对象会创建一个;Subject.getSession(false),如果当前没有创建 Session 则返回null
    • session.getId():获取当前会话的唯一标识
    • session.getHost():获取当前Subject的主机地址
    • session.getTimeout() & session.setTimeout(毫秒):获取/设置当前Session的过期时间
    • session.getStartTimestamp() & session.getLastAccessTime():获取会话的启动时间及最后访问时间;如果是 JavaSE 应用需要自己定期调用 session.touch() 去更新最后访问时间;如果是 Web 应用,每次进入 ShiroFilter 都会自动调用session.touch() 来更新最后访问时间。
    • session.touch() & session.stop():更新会话最后访问时间及销毁会话;当Subject.logout()时会自动调用 stop 方法来销毁会话。如果在web中,调用 HttpSession. invalidate() 也会自动调用Shiro Session.stop 方法进行销毁Shiro 的会话
    • session.setAttribute(key, val) & session.getAttribute(key) & session.removeAttribute(key):设置/获取/删除会话属性;在整个会话范围内都可以对这些属性进行操作

    会话监听器

    在这里插入图片描述

    SessionDao

    • AbstractSessionDAO 提供了 SessionDAO 的基础实现,如生成会话ID等
    • CachingSessionDAO 提供了对开发者透明的会话缓存的功能,需要设置相应的 CacheManager
    • MemorySessionDAO 直接在内存中进行会话维护
    • EnterpriseCacheSessionDAO 提供了缓存功能的会话维护,默认情况下使用 MapCache 实现,内部使用ConcurrentHashMap 保存缓存的会话。
    在这里插入图片描述
    在这里插入图片描述

    会话验证

    • Shiro 提供了会话验证调度器,用于定期的验证会话是否已过期,如果过期将停止会话
    • 出于性能考虑,一般情况下都是获取会话时来验证会话是否过期并停止会话的;但是如在 web 环境中,如果用户不主动退出是不知道会话是否过期的,因此需要定期的检测会话是否过期,Shiro 提供了会话验证调度器SessionValidationScheduler
    • Shiro 也提供了使用Quartz会话验证调度器:QuartzSessionValidationScheduler

    3 缓存

    CacheManagerAware

    Shiro 内部相应的组件(DefaultSecurityManager)会自动检测相应的对象(如Realm)是否实现了CacheManagerAware 并自动注入相应的CacheManager。

    Realm 缓存

    • Shiro 提供了 CachingRealm,其实现了CacheManagerAware 接口,提供了缓存的一些基础实现;
    • AuthenticatingRealm 及 AuthorizingRealm 也分别提供了对AuthenticationInfo 和 AuthorizationInfo 信息的缓存。

    Session 缓存

    • 如 SecurityManager 实现了 SessionSecurityManager,其会判断 SessionManager 是否实现了CacheManagerAware 接口,如果实现了会把CacheManager 设置给它。
    • SessionManager 也会判断相应的 SessionDAO(如继承自CachingSessionDAO)是否实现了CacheManagerAware,如果实现了会把 CacheManager设置给它
    • 设置了缓存的 SessionManager,查询时会先查缓存,如果找不到才查数据库

    4 RememberMe

    概述

    Shiro 提供了记住我(RememberMe)的功能,比如访问如淘宝等一些网站时,关闭了浏览器,下次再打开时还是能记住你是谁,

    下次访问时无需再登录即可访问,基本流程如下:
    • 1、首先在登录页面选中 RememberMe 然后登录成功;如果是浏览器登录,一般会把 RememberMe 的Cookie 写到客户端并保存下来;
    • 2、关闭浏览器再重新打开;会发现浏览器还是记住你的;
    • 3、访问一般的网页服务器端还是知道你是谁,且能正常访问;
    • 4、但是比如我们访问淘宝时,如果要查看我的订单或进行支付时,此时还是需要再进行身份认证的,以确保当前用户还是你。

    认证和记住我

    • subject.isAuthenticated() 表示用户进行了身份验证登录的,即使有 Subject.login 进行了登录;
    • subject.isRemembered():表示用户是通过记住我登录的,此时可能并不是真正的你(如你的朋友使用你的电脑,或者你的cookie 被窃取)在访问的
    • 两者二选一,即 subject.isAuthenticated()==true,则subject.isRemembered()==false;反之一样。

    建议

    • 访问一般网页:如个人在主页之类的,我们使用user 拦截器即可,user 拦截器只要用户登录(isRemembered() || isAuthenticated())过即可访问成功;
    • 访问特殊网页:如我的订单,提交订单页面,我们使用authc 拦截器即可,authc 拦截器会判断用户是否是通过Subject.login(isAuthenticated()==true)登录的,如果是才放行,否则会跳转到登录页面叫你重新登录。

    实现

    如果要自己做RememeberMe,需要在登录之前这样创建Token:

    UsernamePasswordToken(用户名,密码,是否记住我),且调用UsernamePasswordToken 的:token.setRememberMe(true); 方法

    在这里插入图片描述

  • 相关阅读:
    free pascal 调用 C#程序读 Freeplane.mm文件,生成测试用例.csv文件
    如何写测试方案
    子序列宽度之和
    通过TPT的FUSION平台实现联合测试
    Spring Bean循环依赖问题及解决
    【机器学习】(基础篇二) —— 监督学习和无监督学习
    直流无刷电机开发应用
    18. 四数之和
    python内置函数+lambda函数
    YOLOv5 烟叶病害检测系统优化教程
  • 原文地址:https://blog.csdn.net/m0_46360532/article/details/127609107