先来张图:
这是一张shiro的功能图:
- Authentication: 身份认证/登录,验证用户是否拥有相应的身份
- Authorization: 授权/权限验证,验证某个已认证的用户是否拥有某个权限,包括验证用户是否拥有某个角色,或拥有某个操作权限
- Session Management: 会话管理,shiro拥有自己的session(不需要web环境下就能使用)
- Cryptography: 加密
- Web Support: web支持,针对web应用提供一些功能
- Caching: 缓存
- Concurrency: shiro支持多线程应用的并发验证,即在一个线程中开启另一个线程,能把权限自动传播过去
- Testing: 测试支持
- Run As: 允许一个用户假装成为另一个用户(如果允许)的省份进行访问
- Remember Me: 记住用户身份
再来一张图:
- Subject: 与应用交互的用户,Subject在shiro中是一个接口,定义了很多认证授权的方法,外部程序通过Subject进行认证授权,而Subject通过SecurityManager进行认证授权
注意: Subject只是一个门面,SecurityManager才是实际的执行者 - SecurityManager: 安全管理器,所有与安全有关的操作都会与SecurityManager交互,且管理着所有的Subject,是shiro的核心,负责与shiro其他组件进行交互,如通过Authenticator进行认证,通过Authorizer进行授权,通过SessionManager进行会话管理等
补充: SecurityManager是一个接口,继承了Authenticator,Authorizer,SessionManager三个接口 - Realm: Shiro从Realm获取安全数据(如用户,角色,权限);也就是说SecurityManager要验证用户身份或操作权限,需要从Realm获取相应数据来判断(用户是否能登录,是否拥有什么权限等)
注意: realm也是由SecurityManager控制
再来一张图:
- Subject: 与应用交互的用户
- SecurityManager: 相当于SpringMVC中的DispatcherServlet,所有具体的交互都由SecurityManager控制;它管理着所有的Subject,且负责进行认证,授权,会话和缓存的管理
- Authenticator: 认证器, 对用户身份进行验证;Authenticator是一个接口,shiro提供ModularRealmAuthenticator实现类,也可以自定义
- Authorizer: 授权器,决定用户是否有权限进行某种操作,控制着用户能访问应用中的哪些功能
- Realm: 安全实体数据源,可以有1个或多个
- SessionManager: 管理session的生命周期(可以实现单点登录)
- CacheManager: 缓存管理器
- Cryptography: 密码管理模块
认证流程
- 创建token令牌,token中有用户提交的认证信息即帐号和密码
- 执行Subject.login(token),最终由SecurityManager通过Authenticator进行认证
- Authenticator通过实现类ModularRealmAuthenticator调用Realm从数据源(如数据库)获得的真实账号和密码
- Realm通过token中的账号去数据源(数据库)中查找该账号,如果找不到,则给ModularRealmAuthenticator返回null,如果找到则匹配密码,密码相同则认证成功
补充: 认证失败后抛出的一些异常:
- UnknownAccountException 帐号不存在
- IncorrectCredentialsException 密码错误
- DisabledAccountException 帐号被禁用
- LockedAccountException 帐号被锁定
- ExcessiveAttemptsException 登录失败次数过多
- ExpiredCredentialsException 凭证过期
自定义Realm
shiro自带的Realm接口,CachingRealm负责缓存处理,AuthenticationRealm负责认证,AuthorizingRealm负责授权等,但是通常情况下,正确的用户信息都是从数据库中取出,所以需要自定义realm,通常自定义的realm继承AuthorizingRealm,认证是重写doGetAuthenticationInfo(AuthenticationToken token)方法,授权是重写doGetAuthorizationInfo(PrincipalCollection principals)方法