七、集成Shiro之Shiro标签(.jsp和.ftl)
7.1.JSP的Shiro标签
在JSP中使用Shiro标签比较简单,我们只需要注意用法即可.下面我就把所以Shiro标签放在下面了,各位看官自行查考:
<shiro:guest> 游客访问 <a href = "login.jsp"></a> </shiro:guest> user 标签:用户已经通过认证\记住我 登录后显示响应的内容 <shiro:user> 欢迎[<shiro:principal/>]登录 <a href = "logout">退出</a> </shiro:user> authenticated标签:用户身份验证通过,即 Subjec.login 登录成功 不是记住我登录的 <shiro:authenticted> 用户[<shiro:principal/>] 已身份验证通过 </shiro:authenticted> notAuthenticated标签:用户未进行身份验证,即没有调用Subject.login进行登录,包括"记住我"也属于未进行身份验证 <shiro:notAuthenticated> 未身份验证(包括"记住我") </shiro:notAuthenticated> principal 标签:显示用户身份信息,默认调用 Subjec.getPrincipal()获取,即Primary Principal <shiro:principal property = "username"/> hasRole标签:如果当前Subject有角色将显示body体内的内容 <shiro:hashRole name = "admin"> 用户[<shiro:principal/>]拥有角色admin </shiro:hashRole> hasAnyRoles标签:如果Subject有任意一个角色(或的关系)将显示body体里的内容 <shiro:hasAnyRoles name = "admin,user"> 用户[<shiro:pricipal/>]拥有角色admin 或者 user </shiro:hasAnyRoles> lacksRole:如果当前 Subjec没有角色将显示body体内的内容 <shiro:lacksRole name = "admin"> 用户[<shiro:pricipal/>]没有角色admin </shiro:lacksRole> hashPermission:如果当前Subject有权限将显示body体内容 <shiro:hashPermission name = "user:create"> 用户[<shiro:pricipal/>] 拥有权限user:create </shiro:hashPermission> lacksPermission:如果当前Subject没有权限将显示body体内容 <shiro:lacksPermission name = "org:create"> 用户[<shiro:pricipal/>] 没有权限org:create </shiro:lacksPermission>
7.2.Freemark的Shiro标签
1.在SpringBoot里面并不是直接支持JSP文件的,然后我就在项目中使用了Freemark,但是Shiro标签并不能直接支持.ftl文件,所以我们需要先引入一个Maven依赖:
<dependency> <groupId>net.mingsoft</groupId> <artifactId>shiro-freemarker-tags</artifactId> <version>0.1</version> </dependency>
2.然后,我们写一个名为ShiroTagsFreeMarkerCfg配置类来对Freemark使用Shiro标签进行配置.当然了,要确定配置类能被正确注入到Bean中,代码如下所示:
import com.jagregory.shiro.freemarker.ShiroTags; import freemarker.template.TemplateModelException; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; import org.springframework.web.servlet.view.freemarker.FreeMarkerConfigurer; import javax.annotation.PostConstruct; @Component public class ShiroTagsFreeMarkerCfg { @Autowired private FreeMarkerConfigurer freeMarkerConfigurer; @PostConstruct public void setSharedVariable() throws TemplateModelException { freeMarkerConfigurer.getConfiguration().setSharedVariable("shiro", new ShiroTags()); } }
3.配置类搞好之后,我们就可以在.ftl文件中使用Shiro的权限标签了,标签格式如下所示:
<@shiro.guest> 游客访问 <a href = "login.jsp"></a> </@shiro.guest> user 标签:用户已经通过认证\记住我 登录后显示响应的内容 <@shiro.user> 欢迎[<@shiro.principal/>]登录,<a href="/logout.html">退出</a> </@shiro.user> authenticated标签:用户身份验证通过,即 Subjec.login 登录成功 不是记住我登录的 <@shiro.authenticated> 用户[<@shiro.principal/>]已身份验证通过 </@shiro.authenticated> notAuthenticated标签:用户未进行身份验证,即没有调用Subject.login进行登录,包括"记住我"也属于未进行身份验证 <@shiro.notAuthenticated> 当前身份未认证(包括记住我登录的) </@shiro.notAuthenticated> principal 标签:显示用户身份信息,默认调用 Subjec.getPrincipal()获取,即Primary Principal <@shiro.principal property="username"/> hasRole标签:如果当前Subject有角色将显示body体内的内容 <@shiro.hasRole name="admin"> 用户[<@shiro.principal/>]拥有角色admin<br/> </@shiro.hasRole> hasAnyRoles标签:如果Subject有任意一个角色(或的关系)将显示body体里的内容 <@shiro.hasAnyRoles name="admin,user,member"> 用户[<@shiro.principal/>]拥有角色admin或user或member<br/> </@shiro.hasAnyRoles> lacksRole:如果当前 Subjec没有角色将显示body体内的内容 <@shiro.lacksRole name="admin"> 用户[<@shiro.principal/>]不拥有admin角色 </@shiro.lacksRole> hashPermission:如果当前Subject有权限将显示body体内容 <@shiro.hasPermission name="user:add"> 用户[<@shiro.principal/>]拥有user:add权限 </@shiro.hasPermission> lacksPermission:如果当前Subject没有权限将显示body体内容 <@shiro.lacksPermission name="user:add"> 用户[<@shiro.principal/>]不拥有user:add权限 </@shiro.lacksPermission>
八、会话管理
会话管理器管理着应用中所有 Subject 的会话的创建、维护、删除、失效、验证等工作。是Shiro 的核心组件,顶层组件 SecurityManager 直接继承了 SessionManager,且提供了SessionsSecurityManager 实 现 直 接 把 会 话 管 理 委 托 给 相 应 的 SessionManager ,DefaultSecurityManager 及 DefaultWebSecurityManager 默认 SecurityManager 都继承了SessionsSecurityManager。
8.1.会话相关API
①Subject.getSession()获取会话,等价于Subject.getSession(true),即如果当前没有创建session对象会创建一个;Subject.getSession(false),如果当前没有创建session对象则返回null。
②Subject.getSession(true)
③session.getId()获取当前会话的唯一标识。
④session.getHost()获取当前会话的主机地址。
⑤session.getTimeout() & session.setTimeout(毫秒)设置/获取当前Session的过期时间。
⑥session.getStartTimestamp() & session.getLastAccessTime()获取会话的启动时间及最后访问时间;如果是J2SE环境需要自己定期调用session.touch()去更新最后访问时间;如果是Web环境,每次进入ShiroFilter都会自动调用session.touch()来更新最后访问时间。
⑦session.touch() & session.stop()更新会话最后访问时间以及销毁会话;Subject.logout()会自动调用session.stop()。在Web应用中,调用HttpSession.invalidate()也会自动调用session.stop()来销毁shiro的话。
⑧session.setAttribute(key,val) & session.getAttribute(key) & session.removeAttribute(key)设置/获取/删除 会话属性。
8.2.会话监听器(SessionListener接口)
①onStart(Session)
监听会话创建事件
②onStop(Session)
监听会话销毁事件
③onExpiration(Session)
监听会话过期事件
8.3.SessionDao(会话持久化、提供CRUD操作)
①AbstractSessionDAO 提供了 SessionDAO 的基础实现,如生成会话ID等。
②CachingSessionDAO 提供了对开发者透明的会话缓存的功能,需要设置相应的 CacheManager。
③MemorySessionDAO 直接在内存中进行会话维护。
④EnterpriseCacheSessionDAO 提供了缓存功能的会话维护,默认情况下使用 MapCache 实现,内部使用 ConcurrentHashMap 保存缓存的会话。
tips:在实际开发中,如果要用到SessionDAO组件,可以自定义类实现自EnterpriseCacheSessionDAO类,为其注入sessionIdGenerator属性,如果用到缓存的话还可以注入一个缓存的名字。最后将这个SesionDAO组件注入给SessionManager(会话管理器),最后将SessionManager配置给SecurityManager。下图是一个完整的配置细节。
8.4.会话验证
①Shiro提供了会话验证调度器,用于定期的验证会话是否已过期,如果过期将停止会话。
②出于性能考虑,一般情况下都是获取会话的同时来验证会话是否过期并停止会话的;但是如果在Web环境中,如果用户不主动退出是不知道会话是否过期的,因此需要定义的检测会话是否过期,Shiro提供了会话验证调度器来定期检查会话是否过期,SessionValidationScheduler 。
③Shrio也提供了使用Quartz会话验证调度器 QuartzSessionValidationScheduler 。
九、缓存
方法一:
在securityManager配置中添加cacheManager配置项,会注入到realm中。
方法二:在realm中配置。
realm本身实现了CacheManagerAware接口
public interface CacheManagerAware { /** * Sets the available CacheManager instance on this component. * * @param cacheManager the CacheManager instance to set on this component. */ void setCacheManager(CacheManager cacheManager); }
securityManager不只会帮realm注入cacheManager,还会帮sessionManager注入cacheManager
<bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager"> <property name="cacheManager" ref="redisCacheManager" /> <property name="realm" ref="myRealm" /> <property name="sessionManager" ref="sessionManager"/> </bean>
这样的话,realm和sessionManager就不用再配缓存
9.1. 集中式缓存
基于Redis的集中式缓存方案:https://github.com/alexxiyang/shiro-redis
基于Memcached的集中式缓存方案:https://github.com/mythfish/shiro-memcached
基于Ehcache集群模式的存放方案:添加链接描述
9.2. 本地缓存
本地缓存的实现有几种方式
(1)直接存放到JVM堆内存
(2)使用NIO存放在堆外内存,自定义实现或者借助于第三方缓存组件。
不论是采用集中式缓存还是使用本地缓存,shiro的权限数据本身都是直接存放在本地的,不同的是缓存标志的存放位置。采用本地缓存方案是,我们将缓存标志也存放在本地,这样就避免了查询缓存标志的网络请求,能更进一步提升缓存效率。
十、shiro修仙进阶
本篇对于shiro的学习到这就结束了 如果有不全或者不足的地方