Shiro 总结
1.基本概念
(1)Subject(主体):即当前操作”用户”。
(2)SecurityManager(安全管理器):一定要包含域 realm,如果有缓存和会话和 rememberMe 功
能选项,即加入 cacheManager,SessionManager,和 rememberMeManager
(3)Realm(域):相当于数据源,主要两个方法:一是根据令牌获取用户的真实信息,二是查询
出用户的权限信息。
(4)SessionManager(会话管理器):用于管理会话
(5)sessionDao(用于会话持久化):将会话的 sessionid 和 session 存入到数据库中。
(6)cacheManager(缓存管理器):给予 shiro 缓存支持
2.验证和授权过程和 realm 的作用
(1)验证
A)概念:principals(身份):能代表身份的信息,用户名,邮箱等等。
credentials(凭证):证明/凭证,密码等。
B)过程:
1).从安全管理器中获得主体 Sebjuct
使用 SecurityUtils 的 getSubject()方法获得主体
2).创建一个 UsernamePasswordToken 令牌令牌参数:username,password
3).使用 subject 的登录 login 方法内部验证过程是:
a.从 realm 域中 doGetAuthenticationInfo 方法,该方法的参数携带了 token
令牌用户信息,根据令牌信息拿到 username,根据 username 调用业务查找,
找 出 真 实 正 确 的 用 户 信 息 给 simpleAuthenticationInfo 对 象 ( 包 含 了
username,password,salt)并返回。Salt 很可能是 username+salt 的形式。
b.调用指定的匹配器进行匹配,匹配器可以自己定义也可以使用原有的匹
配器,在匹配器的 doCredentialsMatch 方法中进行验证,该方法中有的两
个参数,一个是 authenticationToken:携带了用户填写的信息,另一个是
authenticationInfo:携带的是 realm 给的真实正确的用户信息。两者比对是
否验证成功
4).判断主体 subject 是否验证成功 Subject 的 isAuthenticated 表示是否验证成功
Subject 的 isRememberMe 表示是否是”记住我”
(2)授权 Subject 验证成功后执行 realm 中的 doGetAuthorizationInfo 方法,该方法的参数是
PrincipalCollection,表示的是身份,根据这个身份调用相应的业务查询出用户对应的角色和
权限,赋值给 authorizationInfo 并返回。
过程中涉及到的几个重要对象:
1):authenticationToken:携带的是用户填写的信息拥有的方法:token.getPrincipal()获取用
户身份(用户名),token.getCredentials()获取用户凭证(密码)
2):simpleAuthenticationInfo:携带的是正确的用户信息
3):simpleAuthorizationInfo:携带的是授权的角色信息和权限信息
3.加密方式和 JSP 标签
(1)MD5 加盐迭代两次:
Realsalt:username+salt
加密语句:String newpassword=new SimpleHash(“MD5”, user.getPassword(),
ByteSource.Util.bytes(user.getRealSalt()),2).toHex();
把明文密码根据 MD5 算法,加入 username+salt 盐,迭代两次转换成 16 进制而成。
匹配器中的加密方式要跟生成暗文时的方式一致,否则匹配不成功。
(2)常用的 JSP 标签首先要导入 shiro 的 JSP 标签库:
<%@taglib prefix="shiro" uri="http://shiro.apache.org/tags" %>
A.guest:访问用户标签,即游客也能显示;user 表示已经身份验证且”记住我”登录
B.authenticated:判断是否验证成功(不包括”记住我”);notAuthenticated:自动登录,
没有通过 subject.login()方法验证
C.Principal:用来显示用户身份信息
D.hasRole,hasAnyRoles,lacksRole,hasPermission,lacksPermission 等等。
4.拦截器结构:
整个拦截器使用的类的结构,从 filter 接口开始,子类分别添加一些功能。
1).NameableFilter:表示给拦截器取名,在组装拦截器链时根据名字找出相应的拦截器实
例。
2).OncePerRequestFilter:用于多次执行拦截器,一次请求走一次拦截器链,如果想让某
一个拦截器失效,使其 enabled=false
3).shiroFilter:是整个拦截器链的入口
4).AdviceFilter:提供了 AOP 风格的一些方法
preHandle 方法表示在拦截器链之前执行,如果返回 true 则继续拦截器链
postHandle 方法表示在拦截器链之后执行,可用来更新最后更改时间等
afterCompletion 方法表示最终执行,不管是否有异常,可用来清理资源
5).PathMatchingFilter:提供了基于 Ant 风格的请求路径匹配功能和拦截器参数解析功能。
pathsMatch(String path,ServletRequest request)方法:切割匹配请求路径
例如:roles[admin,user]指令,就可在该方法中匹配
boolean onPreHandle(ServletRequest
mappedValue) throws Exception
request, ServletResponse response, Object
在 preHandle 方法中 pathsMatch 匹配上一个路径后,会调用 onPreHandle 方法并将
请求路径绑定参数给 mappedValue,默认返回 true。
6).AccessControlFilter:提供了控制访问的功能,允许访问和拒绝访问。
isAccessAllowed:表示是否允许访问
onAccessDenied:表示访问被拒接时是否已经被处理过,如果返回的是 true,则说明
还要继续处理,如果返回的是 false,说明已经处理过,直接跳出整个拦截器链。
该拦截器还提供了重定向到登录页面等方法。
7).拦截器链对容器的 filter 链进行了代理,先执行自己的拦截器链,后执行容器的。
DefaultFilterChainManager:用来维护 url 和拦截器链的关系。
其中会默认添加 DefaultFilter 枚举类中的所有拦截器类型:anon,authc,logout,user 等
8).自定义拦截器(扩展拦截器的功能):
继承需要扩展的拦截器:例如
A.继承 OncePerRequestFilter 该拦截器,重写 doFilterInternal 方法
B.继承 AdviceFilter ,重写 preHandle 等方法
C.继承 PathMatchingFilter,重写 onPreHandle 方法。
D.继承 AccessControlFilter,重写 isAccessAllowed 方法和 onAccessDenied 方法。
基于表单的拦截器可以使用 FormAuthenticationFilter 自带的拦截器
9)..默认拦截器:
authc 和 user 的区别:authc 是基于表单的拦截器,只能通过登录验证。而用 user
时,登录验证和”记住我”功能都可以通过。Authc 可用于敏感页面,比如订单详情等。
其他包括 logout,anon 等。
5.会话管理
(1)验证登录之后,给予 session,根据 session 的生存时间或者值来控制会话,代替容器原有
的会话机制,jsessionid:jsessionid 用来找出每一个用户对应的 session,一般存放在 内
存 cookie 中,所以在关闭窗口后,会销毁。
(2)会话监听器:
1 是接 SessionListener 接口:
onStart():会话开始,onExpiration():会话过期,onStop():会话停止或退出。
2 是继承 SessionListenerApapter 类,重写的方法一样。
(3)会话的持久化:
A.结构图:
B.持久化过程中比较重要的几个方法:
1)生成会话 id:
Serializable sessionId=generateSessionId(session);
该方法是自定义 sessionDao 的父类方法,底层是用 UUID 生成的
2)分配 session
assignSessionId(session,seeionId)
该方法将 sessioId 付给 session
3)判断 session 是否过期或停止
session instanceof ValidatingSession &&!((ValidatingSession)session).isValid()
(4)会话验证:
会话验证调度器,用于定期的检验会话是否过期,如果过期就停止会话。出于
性能考虑,一般情况下都是获取会话时验证是否过期。在 web 应用中,使用
SessionValidationScheduler 会话验证调度器定时检验。
6.缓存机制
通过 ehcache.xml 文件配置需要进行缓存的信息,例如授权的信息(authorizationCache),
验证的信息(authenticationCache),会话信息(shiro-activeSessionCache),或者在匹配时记录输
错密码的次数(passwordRetryCache),或者在限制同时在线是使用的(shiro-kickout-session)
例子:
(1)在用户登录成功后缓存相应的验证信息(AuthenticationInfo),修改密码之后,需要清空
缓存信息,所以要在 realm 中添加清空缓存的方法 clearCachedAuthenticationInfo。
(2)在用户验证登录时,自定义匹配器(RetryLimitHashedCredentialsMatcher)用来判断
用户输入密码的错误次数,将用户名和错误次数以键值对的形式存储到缓存中。
用到的一个类:AtomicInteger。是控制并发操作的整型,记录错误次数
7.集成 Spring
(1)在 pom.xml 中的依赖(例如)
关键依赖:shiro-core,shiro-web,shiro-ehcache,shiro-quartz,shiro-spring 等等
(2)在 web.xml 中的配置
除了配置 Spring 的 DispatcherServlet,还需配置 shiro 过滤器
(3)sping 中的配置
A.会话部分
(1)会话 id 生成器(使用 uuid 生成)
(2)会话持久化 sessionDAO(包含会话 id 生成器,session 缓存的名字)
(3)会话验证调度器(包含会话验证的调度时间,会话管理器)
(4)会话 cookie 模板(包含 cookie 名字,最大存活时间等)
(5)会话管理器(包含全局过期时间,cookie 模板,验证调度器,seesionDAO)
可使用的类型:
a):DefaultSessionManager:默认的实现,用于 javaSE
b):ServletContainerSessionManager:用于 web 环境,使用 servlet 会话
c):DefaultWebSessionManager:代替第二种,代替 servlet 会话
B.主体部分
(1)Realm(包括业务层,匹配器)
(2)securityManager(包括 realm,sessionManager,CacheManager)
(3)
(3)匹配器(包括 cacheManager,加密算法,迭代次数等)
C.缓存部分
配置 CacheManager,指向 ehcache.xml(配置缓存内容)
Ehcache.xml 中:
java.io.tmpdir 默认临时工作路径,还可以是 user.home(用户主目录),user.dir
(用户当前工作目录)
name:缓存名称
maxElementsInMemory:最大个数
eternal:是否永久有效,如果 true,timeout 将不起作用
timeToIdleSeconds:非永久有效状态下设置,失效前可闲置时间。默认 0
timeToLiveSeconds:非永久有效状态下设置,失效前存活时间。默认 0
overflowToDisk:当内存中对象数量达到最大个数时,如果为 false,则不会写到
磁盘中。
D.过滤器部分(包括安全管理器, 拦截器部分,拦截器链)
8.RememberMe
记住我功能
Spring 中的配置:
rememberMeCookie 模板(跟 cookie 模板类似)
rememberMeManager(包括加密方式)
9.功能实例
a) 并发人数的控制(不同浏览器中登录同一账号)
自定义一个拦截器继承 AccessControlFilter,重写 isAccessAllowed 和 onAccessDeied,
拦 截 器 中 的 属 性 : maxsession ( 最 大 的 连 接 数 ) ,kickoutUrl( 踢 出 的 地