02-shiro

五、Permissions 
规则:资源标识符:操作:对象实例 ID 即对哪个资源的哪个 实例可以进行什么操作. 其默认支持通配符权限字符串,: 表 示资源/操作/实例的分割;, 表示操作的分割,* 表示任意资 源/操作/实例。 
多层次管理: 
– 例如:user:query、user:edit 
– 冒号是一个特殊字符,它用来分隔权限字符串的下一部件:第一部分 是权限被操作的领域(打印机),第二部分是被执行的操作。 
– 多个值:每个部件能够保护多个值。因此,除了授予用户 user:query 和 user:edit 权限外,也可以简单地授予他们一个:user:query, edit 。
– 还可以用 * 号代替所有的值,如:user:* , 也可以写:*:query,表示某个用户在所有的领域都有 query 的权限。

Shiro 的 Permissions
实例级访问控制 – 这种情况通常会使用三个部件:域、操作、被付诸实 施的实例。如:user:edit:manager 
– 也可以使用通配符来定义,如:user:edit:*、user:*:*、 user:*:manager 
– 部分省略通配符:缺少的部件意味着用户可以访问所 有与之匹配的值,比如:user:edit 等价于 user:edit :*、 user 等价于 user:*:* 
– 注意:通配符只能从字符串的结尾处省略部件,也就 是说 user:edit 并不等价于 user:*:edit

授权流程

授权流程
流程如下: 
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。

Shiro 标签
Shiro 提供了 JSTL 标签用于在 JSP 页面进行权限控制,如根据登录用户显示相应的页面按钮。 
guest 标签:用户没有身份验证时显示相应信息,即游客访问信息:

 user 标签:用户已经经过认证/记住我登录后显示相应的信息。


authenticated 标签:用户已经身份验证通过,即 Subject.login登录成功,不是记住我登录的。

notAuthenticated 标签:用户未进行身份验证,即没有调 用Subject.login进行登录,包括记住我自动登录的也属于未进行身份验证。

pincipal 标签:显示用户身份信息,默认调用 Subject.getPrincipal() 获取,即 Primary Principal。

hasRole 标签:如果当前 Subject 有角色将显示 body 体内 容:

hasAnyRoles 标签:如果当前Subject有任意一个 角色(或的关系)将显示body体内容。

lacksRole:如果当前 Subject 没有角色将显 示 body 体内容

hasPermission:如果当前 Subject 有权限 将显示 body 体内容。

lacksPermission:如果当前Subject没有权 限将显示body体内容。


权限注解 
@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(即设置通用数据)、验证码验证、在线 用户信息的保存等。

六、会话管理
概述
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 保存缓存的会话。

配置示例

配置示例

<ehcache>

    <!-- Sets the path to the directory where cache .data files are created.

         If the path is a Java System Property it is replaced by
         its value in the running VM.

         The following properties are translated:
         user.home - User's home directory
         user.dir - User's current working directory
         java.io.tmpdir - Default temp file path -->
    <diskStore path="java.io.tmpdir"/>
    
    <cache name="authorizationCache"
           eternal="false"
           timeToIdleSeconds="3600"
           timeToLiveSeconds="0"
           overflowToDisk="false"
           statistics="true">
    </cache>

    <cache name="authenticationCache"
           eternal="false"
           timeToIdleSeconds="3600"
           timeToLiveSeconds="0"
           overflowToDisk="false"
           statistics="true">
    </cache>

    <cache name="shiro-activeSessionCache"
           eternal="false"
           timeToIdleSeconds="3600"
           timeToLiveSeconds="0"
           overflowToDisk="false"
           statistics="true">
    </cache>

    <!--Default Cache configuration. These will applied to caches programmatically created through
        the CacheManager.

        The following attributes are required for defaultCache:

        maxInMemory       - Sets the maximum number of objects that will be created in memory
        eternal           - Sets whether elements are eternal. If eternal,  timeouts are ignored and the element
                            is never expired.
        timeToIdleSeconds - Sets the time to idle for an element before it expires. Is only used
                            if the element is not eternal. Idle time is now - last accessed time
        timeToLiveSeconds - Sets the time to live for an element before it expires. Is only used
                            if the element is not eternal. TTL is now - creation time
        overflowToDisk    - Sets whether elements can overflow to disk when the in-memory cache
                            has reached the maxInMemory limit.

        -->
    <defaultCache
        maxElementsInMemory="10000"
        eternal="false"
        timeToIdleSeconds="120"
        timeToLiveSeconds="120"
        overflowToDisk="true"
        />

    <!--Predefined caches.  Add your cache configuration settings here.
        If you do not have a configuration for your cache a WARNING will be issued when the
        CacheManager starts

        The following attributes are required for defaultCache:

        name              - Sets the name of the cache. This is used to identify the cache. It must be unique.
        maxInMemory       - Sets the maximum number of objects that will be created in memory
        eternal           - Sets whether elements are eternal. If eternal,  timeouts are ignored and the element
                            is never expired.
        timeToIdleSeconds - Sets the time to idle for an element before it expires. Is only used
                            if the element is not eternal. Idle time is now - last accessed time
        timeToLiveSeconds - Sets the time to live for an element before it expires. Is only used
                            if the element is not eternal. TTL is now - creation time
        overflowToDisk    - Sets whether elements can overflow to disk when the in-memory cache
                            has reached the maxInMemory limit.

        -->

    <!-- Sample cache named sampleCache1
        This cache contains a maximum in memory of 10000 elements, and will expire
        an element if it is idle for more than 5 minutes and lives for more than
        10 minutes.

        If there are more than 10000 elements it will overflow to the
        disk cache, which in this configuration will go to wherever java.io.tmp is
        defined on your system. On a standard Linux system this will be /tmp"
        -->
    <cache name="sampleCache1"
        maxElementsInMemory="10000"
        eternal="false"
        timeToIdleSeconds="300"
        timeToLiveSeconds="600"
        overflowToDisk="true"
        />

    <!-- Sample cache named sampleCache2
        This cache contains 1000 elements. Elements will always be held in memory.
        They are not expired. -->
    <cache name="sampleCache2"
        maxElementsInMemory="1000"
        eternal="true"
        timeToIdleSeconds="0"
        timeToLiveSeconds="0"
        overflowToDisk="false"
        /> -->

    <!-- Place configuration for your caches following -->

</ehcache>
ehcache.xml

数据表

create table sessions ( 
id varchar(200), 
session varchar(2000), 
constraint pk_sessions primary key(id) 
) charset=utf8 ENGINE=InnoDB;

Session Dao

SerializableUtils

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

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

七、缓存
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,查询时会先查缓存,如果找不到才查数据库。

八、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); 方法


posted @ 2019-04-23 00:50  payn  阅读(192)  评论(0)    收藏  举报