Shiro系统性介绍
Shiro是一个使用简单但是功能又强大的Java安全框架,它提供了认证、授权、会话管理等主要功能。
Shiro使用过程中有两个顶级配置对象 SecurityManager
和 ShiroFilterFactoryBean
。 其他配置对象都是这两类对象的延伸。
一、 术语介绍
它有几个重要的概念。
1. Subject
Subject
在 Shiro
中是一个核心概念。它对于Shiro来讲就是一个用户的概念,这个用户可以是登录人也可以是其他访问的服务器等等。
之所以没有叫User,是因为其他很多框架都有这个概念了,防止冲突和混淆。
2. Principals
是一个 Subject
的标识属性,是一个能代表 Subject
的属性,可以是登录名、手机号等等
3. Realms
Shiro
框架中的 DAO
角色,负责从后台数据库获取对象数据。比如从数据库中获取用户信息、权限信息等等。
二、 认证过程(Authenticate)
认证过程主要分为三步:
- 收集Subject的Principals和credentials信息
比如登录名和密码 - 将收集到的信息提交给认证系统
- 经过认证,如果成功则返回用户的详细信息,如果失败则拒绝访问
1. 收集信息
收集到的信息以 token
的形式存在。
最简单和最常用的收集方式就是通过用户名和密码来完成。 UsernamePasswordToken
是一个封装好的用户名密码token对象
UsernamePasswordToken token = new UsernamePasswordToken( username, password );
2. 提交token信息进行认证
认证系统通过Realms来获取后台数据并进行认证
//With most of Shiro, you'll always want to make sure you're working with the currently
//executing user, referred to as the subject
Subject currentUser = SecurityUtils.getSubject();
//Authenticate the subject by passing
//the user name and password token
//UsernamePasswordToken token = new UsernamePasswordToken( username, password );
//into the login method
currentUser.login(token);
首先,需要获取一个代表当前用户的对象 SecurityUtils.getSubject()
。没有认证前身份是匿名用户(anonymous),并且没有标识信息与其关联。
然后,通过 currentUser.login(token);
进行认证,如果认证通过了会把当前用户信息关联到上步获取到的 Subject
上。
3. 处理认证结果
认证结果可能成功也可能失败,如果失败了则直接拒绝访问。如果成功了则从后台查询用户信息和权限信息并关联到 Subject
上
登录失败异常情况:
- UnknownAccountException
- IncorrectCredentialsException
- LockedAccountException
- ExcessiveAttemptsException
- AuthenticationException
等等
三、 SecurityManager
顶级配置对象。SecurityManager
安全管理器是Shiro系统的核心框架内容接口。这也代表了Shiro的能力内容
- 他本身提供了三个方法
- login 登录
- logout 登出
- createSubject 创建Subject
- 继承Authenticator(验证器)
- authenticate 对给定Token进行验证的方法
- 继承Authorizer(访问控制器)
- isPermitted
- checkPermission
- hasRole
- checkRole
- 继承SessionManager(会话管理)
- start
- getSession
public interface SecurityManager extends Authenticator, Authorizer, SessionManager {
Subject login(Subject subject, AuthenticationToken authenticationToken) throws AuthenticationException;
void logout(Subject subject);
Subject createSubject(SubjectContext context);
}
public interface Authenticator {
public AuthenticationInfo authenticate(AuthenticationToken authenticationToken) throws AuthenticationException;
}
public interface Authorizer {
boolean isPermitted(PrincipalCollection principals, String permission);
boolean isPermitted(PrincipalCollection subjectPrincipal, Permission permission);
boolean[] isPermitted(PrincipalCollection subjectPrincipal, String... permissions);
boolean[] isPermitted(PrincipalCollection subjectPrincipal, List<Permission> permissions);
boolean isPermittedAll(PrincipalCollection subjectPrincipal, String... permissions);
boolean isPermittedAll(PrincipalCollection subjectPrincipal, Collection<Permission> permissions);
void checkPermission(PrincipalCollection subjectPrincipal, String permission) throws AuthorizationException;
void checkPermission(PrincipalCollection subjectPrincipal, Permission permission) throws AuthorizationException;
void checkPermissions(PrincipalCollection subjectPrincipal, String... permissions) throws AuthorizationException;
void checkPermissions(PrincipalCollection subjectPrincipal, Collection<Permission> permissions) throws AuthorizationException;
boolean hasRole(PrincipalCollection subjectPrincipal, String roleIdentifier);
boolean[] hasRoles(PrincipalCollection subjectPrincipal, List<String> roleIdentifiers);
boolean hasAllRoles(PrincipalCollection subjectPrincipal, Collection<String> roleIdentifiers);
void checkRole(PrincipalCollection subjectPrincipal, String roleIdentifier) throws AuthorizationException;
void checkRoles(PrincipalCollection subjectPrincipal, Collection<String> roleIdentifiers) throws AuthorizationException;
void checkRoles(PrincipalCollection subjectPrincipal, String... roleIdentifiers) throws AuthorizationException;
}
public interface SessionManager {
Session start(SessionContext context);
Session getSession(SessionKey key) throws SessionException;
}
默认实现
SecurityManager
提供了默认实现类 DefaultWebSecurityManager
。我们通常利用这个默认实现来完成Shiro的功能,它也给出了相关方法来设置具体的对象。
构造函数依赖:
- Realm: 创建是需要给定一个Realm的实现类,来完成后台数据的读取
1. Realm
一个Realm接口有下面几个基本的方法:
- getName 当前Realm对象的名称,是一个标识
- supports 单签Realm对象是否支持指定类型的token
- getAuthenticationInfo 验证token
public interface Realm {
String getName();
boolean supports(AuthenticationToken token);
AuthenticationInfo getAuthenticationInfo(AuthenticationToken token) throws AuthenticationException;
}
不过在实际使用过程中会使用它的某个子实现,是在基本方法的基础上扩展了若干功能,比如cache的能力、访问控制的能力、角色解析、权限解析等能力。我们根据实际需求实现不同能力层级的对象即可。
比如 AuthorizingRealm
就是一个常用的实现子类
公开方法:
- public void setSessionManager(SessionManager sessionManager)
2. SessionManager
一个完整的企业级Session管理框架,有如下特点
- POJO/J2SE based (IoC friendly)
在Shiro中一切都是面向接口和POJO实现的。这就意味着你可以很方便的定义其中的某些对象以及扩展这些对象 - Easy Custom Session Storage
容易定制的Session存储机制。因为Shiro中的对象是基于Pojo,所以这些对象可以很方便的存储在各种类型的数据存储容器中。比如文件系统、MemCache等内存系统、关系型数据库等等 - Container-Independent Clustering
方便定制会话集群, like Ehcache + Terracotta, Coherence, GigaSpaces等等 - Heterogeneous Client Access
支持各种客户端访问,比如web用户、手机端用户、服务器用户等等,都可以很方便的访问同一个Session - Event Listeners
运行监听会话过程中的各个生命周期 - Host Address Retention
主机地址存储,Session是保留会话创建这的IP和hostname的,因此可以方便的进行相关业务扩展 - Inactivity/Expiration Support
支持会话过期 - Transparent Web Use
支持 Servlet 2.5的会话系统,你可以基于现有的Session使用Shiro的Session管理 - Can be used for SSO
可以用于SSO。
2.1配置
SessionManager
有一个默认的实现类 DefaultWebSessionManager
,可以通过这个类配置相关的行为
公开方法:
- setSessionIdCookieEnabled 是否启用Cookie
- setSessionIdCookie 设置Cookie对象
- Cookie
- void setName(String name);
- void setValue(String value);
- void setComment(String comment);
- void setDomain(String domain);
- void setMaxAge(int maxAge);
- void setPath(String path);
- void setSecure(boolean secure);
- void setVersion(int version);
- boolean isHttpOnly();
- Cookie
- 继承DefaultSessionManager
- sessionDAO: 构造参数,session的存储方式对象
- setSessionDAO
- setSessionFactory
- setCacheManager
- 继承AbstractValidatingSessionManager
- setSessionValidationSchedulerEnabled 是否启用定时Session失效
- setSessionValidationScheduler 设置失效策略对象
- setSessionValidationInterval 设置失效时间
- 继承AbstractNativeSessionManager
- setSessionListeners 设置Session事件监听器
- setEventBus 设置事件总线
- setTimeout(SessionKey key, long maxIdleTimeInMillis) 设置指定Session失效时间
- setAttribute(SessionKey sessionKey, Object attributeKey, Object value) 设置session属性
- 继承AbstractSessionManager
- setGlobalSessionTimeout 设置全局失效时间
- 继承NativeSessionManager
- getTimeout(SessionKey key)
- getLastAccessTime(SessionKey key)
- 等等
2.2 使用Session
Subject currentUser = SecurityUtils.getSubject();
Session session = currentUser.getSession();
session.setAttribute( "someKey", someValue);
在获取Session时,如果Subject已经关联了一个Session那么直接返回,如果没有管理则根据参数觉得新建一个Session还是返回null
五、ShiroFilterFactoryBean
Shiro过滤器,顶级配置对象。用来配置指定url的拦截器,登录成功地址等等
公开方法:
- setSecurityManager 设置并关联安全管理框架对象
- setLoginUrl 设置登录界面地址,访问无权限是会跳转该地址
- setSuccessUrl 设置登录成功跳转地址
- setUnauthorizedUrl 设置无权限访问跳转地址
- setFilters(Map<String, Filter> filters) 设置filter名称和filter的对应关系Map
- setFilterChainDefinitionMap 设置请求路径和对应filte的名称的Map对象
- setFilterChainDefinitions 设置请求路径和对应filte的名称
- setGlobalFilters 设置全局请求Filter,每个请求都会执行