Shiro入门学习五
2017-11-29 19:32
337 查看
与Web集成
前面的学习都是在JavaSE下,Shiro提供了与Web集成的支持,其通过一ShiroFilter入口来拦截需要安全控制的URL,然后进行相应的控制,ShiroFilter 类似于如 Strut2/SpringMVC 这种 web 框架的前端控制器,其是安全控制的入口点,其负责读取配置(如 ini 配置文件),然后判断 URL 是否需要登录 / 权限等工作。servlet环境配置
一. shiro1.1及以前版本配置方式
<filter> <filter-name>iniShiroFilter</filter-name> <filter-class>org.apache.shiro.web.servlet.IniShiroFilter</filter-class> <init-param> <param-name>configPath</param-name> <param-value>classpath:shiro.ini</param-value> </init-param> </filter> <filter-mapping> <filter-name>iniShiroFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping>
使用IniShiroFilter作为Shiro安全控制的入口,通过url-pattern指定需要安全的URL;
通过 configPath 指定 ini 配置文件位置,默认是先从 /WEB-INF/shiro.ini 加载,如果没有就默认加载 classpath:shiro.ini;
也可以通过如下方式直接内嵌 ini 配置文件内容到 web.xml。
<init-param> <param-name>config</param-name> <param-value> ini配置文件贴在这 </param-value> </init-param>
二. shiro1.2及以后版本配置方式
shiro1.2开始引入了Environment/WebEnvironment概念,即由它们的实现提供相应的 SecurityManager 及其相应的依赖。ShiroFilter 会自动找到 Environment 然后获取相应的依赖。与spring配置很像<!--通过EnvironmentLoaderListener来创建相应的WebEnvironment并自动绑定到 ServletContext, 默认使用 IniWebEnvironment 实现--> <listener> <listener-class>org.apache.shiro.web.env.EnvironmentLoaderListener</listener-class> </listener> <!--通过配置修改默认实现及其加载的配置文件位置--> <context-param> <param-name>shiroEnviromentClass</param-name> <param-value>org.apache.shiro.web.env.IniWebEnvironment</param-value> </context-param> <context-param> <param-name>shiroConfigLocations</param-name> <param-value>classpath:shiro.ini</param-value> </context-param> <!--shiroFilter--> <filter> <filter-name>shiroFilter</filter-name> <filter-class>org.apache.shiro.web.servlet.ShiroFilter</filter-class> </filter> <filter-mapping> <filter-name>shiroFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping>
web INI 配置
ini 配置部分和之前的相比将多出对 urls 部分的配置。[main] #默认是/login.jsp authc.loginUrl=/login roles.unauthorizedUrl=/unauthorized perms.unauthorizedUrl=/unauthorized logout.redirectUrl=/login [users] zhang=123,admin wang=123 [roles] admin=user:*,menu:* [urls] /login=anon /unauthorized=anon /static/**=anon /authenticated=authc /role=authc,roles[admin] /permission=authc,perms["user:create"]
authc.loginUrl:登录URL
roles.unauthorizedUrl:角色未授权重定向URL
perms.unauthorizedUrl:权限未授权重定向URL
logout.redirectUrl:登出时重定向URL
anon:org.apache.shiro.web.filter.authc.AnonymousFilter拦截器表示可以匿名访问
authc:org.apache.shiro.web.filter.authc.FormAuthenticationFilter拦截器表示需要身份认证通过后才能访问
roles[admin]:org.apache.shiro.web.filter.authz.RolesAuthorizationFilter拦截器表示需要有admin角色授权才能访问
perms[“user:create”]:org.apache.shiro.web.filter.authz.PermissionsAuthorizationFilter拦截器表示需要user:create权限才能访问
url 模式匹配顺序
url 模式匹配顺序是按照在配置中的声明顺序匹配,即从头开始使用第一个匹配的 url 模式对应的拦截器链。在实际项目中比如支付时如果没有登录将跳转到登录页面,登录成功后再跳回到支付页面;对于这种功能大家可以在登录时把当前请求保存下来,然后登录成功后再重定向到该请求即可。Shiro内置了登录(身份验证)的实现:基于表单的和基于Basic的验证,其通过拦截器实现。
基于Basic的拦截器身份验证
[main] authcBasic.applicationName=please login [users] zhang=123,admin [urls] /list=authcBasic,roles[admin]
authcBasic 是 org.apache.shiro.web.filter.authc.BasicHttpAuthenticationFilter 类型的实例,其用于实现基于 Basic 的身份验证;applicationName 用于弹出的登录框提示信息。
基于表单的拦截器身份验证
[main] authc.loginUrl=/formfilterlogin authc.usernameParam=username authc.passwordParam=password authc.successUrl=/ authc.failureKeyAttribute=shiroLoginFailure [urls] /list=authc,roles[admin]
authc 是 org.apache.shiro.web.filter.authc.FormAuthenticationFilter 类型的实例,其用于实现基于表单的身份验证。usernameParam指定登录表单提交的用户名参数名;passwordParam 指定登录表单提交的密码参数名;successUrl 指定登录成功后重定向的默认地址(默认是 “/”)(如果有上一个地址会自动重定向到该地址);failureKeyAttribute 指定登录失败时的 request 属性 key(默认 shiroLoginFailure);这样可以在登录表单得到该错误 key 显示相应的错误消息;
Shiro jsp标签
Shiro 提供了 JSTL 标签用于在 JSP/GSP 页面进行权限控制,如根据登录用户显示相应的页面按钮。导入标签库
<%@ taglib prefix="shiro" uri="http://shiro.apache.org/tags" %>
标签库定义在 shiro jar 包下的 META-INF/shiro.tld 中定义。
<!-- 用户没有登录时显示 --> <shiro:guest> 欢迎游客访问,<a href="/login.jsp">登录</a> </shiro:guest> <!-- 用户通过身份验证/记住我登录时显示 --> <shiro:user> 欢迎[<shiro:principal/>]登录,<a href="shiro/logout">点击退出</a><br/> </shiro:user> <!-- 用户通过身份验证时显示 --> <shiro:authenticated> 用户[<shiro:principal/>]已身份验证通过<br/> </shiro:authenticated> <!-- 用户通过记住我登录时显示 --> <shiro:notAuthenticated> 未身份验证(包括记住我) </shiro:notAuthenticated> <!-- 拥有admin角色时显示 --> <shiro:hasRole name="admin"> 用户[<shiro:principal/>]拥有角色admin<br/> </shiro:hasRole> <!-- 拥有任意一角色时显示 --> <shiro:hasAnyRoles name="admin,user"> 用户[<shiro:principal/>]拥有角色admin或user<br/> </shiro:hasAnyRoles> <!-- 没有guest角色时显示 --> <shiro:lacksRole name="guest"> 用户[<shiro:principal/>]没有角色guest<br/> </shiro:lacksRole> <!-- 拥有user:create权限时显示 --> <shiro:hasPermission name="user:create"> 用户[<shiro:principal/>]拥有权限user:create<br/> </shiro:hasPermission> <!-- 没有org:create权限时显示 --> <shiro:lacksPermission name="org:create"> 用户[<shiro:principal/>]没有权限org:create<br/> </shiro:lacksPermission> <!--默认调用 Subject.getPrincipal() 获取,即 Primary Principal --> <shiro:principal/> <!-- 相当于 Subject.getPrincipals().oneByType(String.class) --> <shiro:principal type="java.lang.String"/> <!-- 相当于 ((User)Subject.getPrincipals()).getUsername() --> <shiro:principal property="username"/>
会话管理
Shiro 提供了完整的企业级会话管理功能,不依赖于底层容器(如 web 容器 tomcat),不管 JavaSE 还是 JavaEE 环境都可以使用,提供了会话管理、会话事件监听、会话存储 / 持久化、容器无关的集群、失效 / 过期支持、对 Web 的透明支持、SSO 单点登录的支持等特性。即直接使用 Shiro 的会话管理可以直接替换如 Web 容器的会话管理。SessionAPI
//获取主体 Subject subject = SecurityUtils.getSubject(); //获取Session Session session = subject.getSession(); //获取当前会话的唯一标识 session.getId(); //获取当前Subject的主机地址 session.getHost(); //设置/获取当前Session过期时间 session.setTimeout(100); session.getTimeout(); //获取会话的启动时间及最后访问时间,JavaSE自己定期调用session.touch更新最后访问时间 session.getStartTimestamp(); session.getLastAccessTime(); //更新会话最后访问时间及销毁会话 session.touch(); session.stop(); //设置/获取/删除会话属性及获取属性Key的集合 session.setAttribute("key", "value"); session.getAttribute(""); session.removeAttribute("key"); session.getAttributeKeys();
会话管理器
Shiro提供了三种默认实现:
DefaultSessionManager:DefaultSecurityManager 使用的默认实现,用于 JavaSE 环境;
ServletContainerSessionManager:DefaultWebSecurityManager 使用的默认实现,用于 Web 环境,其直接使用 Servlet 容器的会话;
DefaultWebSessionManager:用于 Web 环境的实现,可以替代 ServletContainerSessionManager,自己维护着会话,直接废弃了 Servlet 容器的会话管理。
INI配置:
[main] #JavaSE环境下 sessionManager=org.apache.shiro.session.mgt.DefaultSessionManager securityManager.sessionManager=$sessionManager #JavaWeb环境下 sessionManager=org.apache.shiro.web.session.mgt.DefaultWebSessionManager sessionIdCookie=org.apache.shiro.web.servlet.SimpleCookie sessionIdCookie.name=sid \#sessionIdCookie.domain= \#sessionIdCookie.path= sessionIdCookie.maxAge=1800 sessionIdCookie.httpOnly=true sessionManager.sessionIdCookie=$sessionIdCookie sessionManager.sessionIdCookieEnabled=true sessionManager.globalSessionTimeout=1800000 securityManager.sessionManager=$sessionManager securityManager.sessionManager=$sessionManager
sessionIdCookie 是 sessionManager 创建会话 Cookie 的模板:
sessionIdCookie.name:设置 Cookie 名字,默认为 JSESSIONID;
sessionIdCookie.domain:设置 Cookie 的域名,默认空,即当前访问的域名;
sessionIdCookie.path:设置 Cookie 的路径,默认空,即存储在域名根下;
sessionIdCookie.maxAge:设置 Cookie 的过期时间,秒为单位,默认 - 1 表示关闭浏览器时过期 Cookie;
sessionIdCookie.httpOnly:如果设置为 true,则客户端不会暴露给客户端脚本代码,使用 HttpOnly cookie 有助于减少某些类型的跨站点脚本攻击;此特性需要实现了 Servlet 2.5 MR6 及以上版本的规范的 Servlet容器支持;
sessionManager.sessionIdCookieEnabled:是否启用 / 禁用 Session Id Cookie,默认是启用的;如果禁用后将不会设置 Session Id Cookie,即默认使用了 Servlet 容器的JSESSIONID,且通过 URL 重写(URL 中的 “;JSESSIONID=id” 部分)保存 Session Id;
sessionManager.globalSessionTimeout:设置会话的全局过期时间。
对于使用ServletContainerSessionManager进行会话管理,Session的超时依赖于底层Servlet容器的超时时间,可以在web.xml中配置
<session-config> <!--30分钟超时--> <session-timeout>30</session-timeout> </session-config>
会话监听器
会话监听器用于监听会话的创建、过期及停止事件,有二种方式:实现SessionListener接口
package com.shiro.listener; public class MySessionListener1 implements SessionListener { @Override public void onStart(Session session) {//会话创建时触发 System.out.println("会话创建:" + session.getId()); } @Override public void onExpiration(Session session) {//会话过期时触发 System.out.println("会话过期:" + session.getId()); } @Override public void onStop(Session session) {//退出/会话过期时触发 System.out.println("会话停止:" + session.getId()); } }
如果只想监听某一个事件,可以继承SessionListenerAdapter,重写其中的某一个方法。
public class MySessionListener2 extends SessionListenerAdapter { @Override public void onStart(Session session) { System.out.println("会话创建:" + session.getId()); } }
在INI配置文件中配置
sessionListener1=com.shiro.listener.MySessionListener1 sessionListener2=com.shiro.listener.MySessionListener2 SessionManager.sessionListeners=$sessionListener1,$sessionListener2
会话存储/持久化
Shiro 提供 SessionDAO 用于会话的 CRUD,即 DAO(Data Access Object)模式实现:AbstractSessionDAO 提供了 SessionDAO 的基础实现,如生成会话 ID 等;CachingSessionDAO 提供了对开发者透明的会话缓存的功能,只需要设置相应的 CacheManager 即可;MemorySessionDAO 直接在内存中进行会话维护;而 EnterpriseCacheSessionDAO 提供了缓存功能的会话维护,默认情况下使用 MapCache 实现,内部使用 ConcurrentHashMap 保存缓存的会话。
使用EhCache缓存进行会话存储
sessionDAO=org.apache.shiro.session.mgt.eis.EnterpriseCacheSessionDAO #设置Session缓存名字,默认就是shiro-activeSessionCache sessionDAO.activeSessionsCacheName=shiro-activeSessionCache #设置生成会话ID,默认是JavaUuidSessionIdGenerator,使用java.util.UUID生成 sessionIdGenerator=org.apache.shiro.session.mgt.eis.JavaUuidSessionIdGenerator sessionDAO.sessionIdGenerator=$sessionIdGenerator sessionManager.sessionDAO=$sessionDAO #缓存管理器 cacheManager=org.apache.shiro.cache.ehcache.EhCacheManager #设置ehcache的配置文件 cacheManager.cacheManagerConfigFile=classpath:ehcache.xml #SecurityManager的cacheManager会自动设置到实现了CacheManagerAware接口的相应对象 securityManager.cacheManager=$cacheManager
ehcache.xml
<cache name="shiro-activeSessionCache" maxEntriesLocalHeap="10000" overflowToDisk="false" eternal="false" diskPersistent="false" timeToLiveSeconds="0" timeToIdleSeconds="0" statistics="true"/>
org.apache.shiro.session.mgt.eis.AbstractSessionDAO中实现了SessionID的实现。
//生成SessionID的方法 protected Serializable generateSessionId(Session session) { if (this.sessionIdGenerator == null) { String msg = "sessionIdGenerator attribute has not been configured."; throw new IllegalStateException(msg); } return this.sessionIdGenerator.generateId(session); } //将生成的sessionID放入Session中 protected void assignSessionId(Session session, Serializable sessionId) { ((SimpleSession) session).setId(sessionId); }
会话验证
Shiro 提供了会话验证调度器,用于定期的验证会话是否已过期,如果过期将停止会话;出于性能考虑,一般情况下都是获取会话时来验证会话是否过期并停止会话的;但是如在 web 环境中,如果用户不主动退出是不知道会话是否过期的,因此需要定期的检测会话是否过期,Shiro 提供了会话验证调度器 SessionValidationScheduler 来做这件事情。sessionValidationScheduler=org.apache.shiro.session.mgt.ExecutorServiceSessionValidationScheduler sessionValidationScheduler.interval = 3600000 sessionValidationScheduler.sessionManager=$sessionManager sessionManager.globalSessionTimeout=1800000 sessionManager.sessionValidationSchedulerEnabled=true sessionManager.sessionValidationScheduler=$sessionValidationScheduler
sessionValidationScheduler:会话验证调度器,sessionManager 默认就是使用
ExecutorServiceSessionValidationScheduler,其使用 JDK 的
ScheduledExecutorService 进行定期调度并验证会话是否过期;
sessionValidationScheduler.interval:设置调度时间间隔,单位毫秒,默认就是 1 小时;
sessionValidationScheduler.sessionManager:设置会话验证调度器进行会话验证时的会话管理器;
sessionManager.globalSessionTimeout:设置全局会话超时时间,默认 30 分钟,即如果 30分钟内没有访问会话将过期;
sessionManager.sessionValidationSchedulerEnabled:是否开启会话验证器,默认是开启的;
sessionManager.sessionValidationScheduler:设置会话验证调度器,默认就是使用
ExecutorServiceSessionValidationScheduler。
缓存机制
Shiro 提供了类似于 Spring 的 Cache 抽象,即 Shiro 本身不实现 Cache,但是对 Cache 进行了又抽象,方便更换不同的底层 Cache 实现。Shiro提供了Cache和CacheManager接口,还提供了CacheManagerAware用于注入CacheManager,Shiro内部响应的组件(DefaultSecurityManager)会自动检测相应的对象(如Realm、SessionManager、SessionDAO)是否实现了CacheManagerAware并自动注入相应的CacheManager。Realm缓存
Shiro 提供了 CachingRealm,其实现了 CacheManagerAware 接口,提供了缓存的一些基础实现;另外 AuthenticatingRealm 及 AuthorizingRealm 分别提供了对 AuthenticationInfo 和 AuthorizationInfo 信息的缓存。
INI配置
userRealm=com.shiro.realm.UserRealm #启用缓存,默认false userRealm.cachingEnabled=true #启用身份验证缓存,缓存名为authenticationCache userRealm.authenticationCachingEnabled=true userRealm.authenticationCacheName=authenticationCache #启用授权缓存,缓存名为authorizationCache userRealm.authorizationCachingEnabled=true userRealm.authorizationCacheName=authorizationCache securityManager.realms=$userRealm cacheManager=org.apache.shiro.cache.ehcache.EhCacheManager cacheManager.cacheManagerConfigFile=classpath:shiro-ehcache.xml securityManager.cacheManager=$cacheManager
相关文章推荐
- shiro入门学习
- Shiro入门学习一
- Shiro系列学习 -- 入门篇
- Shiro学习总结(二)--Shiro的入门小例子
- 4000 Shiro入门学习二
- 权限学习--Shiro入门学习
- 18.03.09,web学习第七十天,bos第十天,shiro框架入门
- shiro入门学习四
- Shiro入门学习三
- apache shiro学习笔记--02(入门案例)
- Shiro入门学习六
- Shiro入门学习三
- Shiro 学习记录 Shiro 入门程序
- java安全框架-Shiro学习笔记(一)-入门小案例
- shiro学习(一)---认证入门程序
- Shiro入门学习二
- Shiro入门学习四
- Shiro入门学习一
- Apache Shiro 学习记录1
- ASP.NET缓存学习入门---数据缓存