一.是什么?
Apache Shiro是Java的一个安全框架。Shiro可以帮助我们完成:认证、授权、加密、会话管理、与Web集成、缓存等。
从外部看:应用代码直接交互的对象是Subject,也就是说Shiro的对外API核心就是Subject,Shiro不提供维护用户/权限,而是通过Realm让开发人员自己注入。
从内部看:通过Securty Manage管理外部请求的认证认证、授权、加密、会话管理、缓存等。对应组件是authenticator,Authorizer,session manager(自定义的sessionDao),cache manage
二.框架流程介绍
- 容器的创建:通过EnvironmentLoaderListener监听,在容器启动时创建 WebEnvironment 对象,并由该对象来读取 Shiro 配置文件,创建WebSecurityManager 与FilterChainResolver 对象。
- 执行拦截器:因为Shiro代理了Filter,先执行Shiro的拦截器。ShiroFilter实现Filter接口的init(),它是整个程序的入口。(详细内容见源码分析)。执行完Shiro拦截器后执行其他拦截器,之后放行到WebSecurityManager进行会话的管理。
- SecurityManager的各组件通过与subject交互进行认证,授权等管理
三.subject介绍**
- 定义:当前正与软件进行交互的任何东西,你可以把 Subject 看成是 Shiro 的"User"概念。
- 获取:Subject user=SecurityUtils.getSubject()(当前正在执行的 Subject), 它获取的 Subject 是基于关联了当前线程或传入请求的用户数据的。
-
3.用途:
- 获取sesion :user .getSession(); (它不需要一个 HTTP 环境,任何客户端技术现在能够共享会话数据)
- .对角色和权限的检查:
- 是否登录:user.isAuthenticated()
- 是否有特定角色与操作权限:
user.hasRole("teacher")
user.isPermitted("teacher:save")
user.isPermitted("teacher:save:权限码") - 登录:
- 退出:user.logou()
四.SecurityManager组件介绍
1.Authorizer:
- 定义:操作授权认证组件,通过配置 Realm 实现或jsp标签,常用于角色授权
public class NormalRealm extends AuthorizingRealm{
@Resource
private AuthorityPermissionService permissionService;
@Resource
private AuthorityUsersService authorityUsersService;
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo();//创建Shiro权限数据对象
Integer userId = Integer.valueOf(principalCollection.toString());//获取当前用户ID
AuthorityUsers users = this.authorityUsersService.findById(userId);
if (users != null) {
if (users.getAdministrator() == 1) {
//如果是超级管理员,赋予所有权限
authorizationInfo.addStringPermission("*");
}
}
return authorizationInfo;
}
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
return null;
}
}
2. Authenticator(认证器)
- 定义:对用户的身份验证(登录)尝试负责的组件
public class NormalRealm extends AuthorizingRealm {
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
return null;
}
//认证
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
UsernamePasswordToken usernamePasswordToken = (UsernamePasswordToken) token;
Object principal = usernamePasswordToken.getPrincipal();
Object credentials = usernamePasswordToken.getCredentials();
SimpleAuthenticationInfo info = new SimpleAuthenticationInfo(principal, credentials, getName());
return info;
}
}
3. SessionManager(会话管理器)
- 定义:SessionManager是用来管理Session的组件,包括:创建,删除,inactivity(失效)及验证
- Shiro提供了三个默认实现,我们常用DefaultWebSessionManager自定义管理
* DefaultSessionManager:DefaultSecurityManager使用的默认实现,用于JavaSE环境;
* ServletContainerSessionManager:用于Web环境,其直接使用Servlet容器的会话;
* DefaultWebSessionManager:用于Web环境的实现,可以替代2,自己维护着会话,直接废弃了Servlet容器的会话管理。
-
结构图
- 常用实现功能
- 监听session状态,实现过程在类4中
public class sessionLister implements SessionListener {
@Override
public void onStart(Session session) {
}
@Override
public void onStop(Session session) {
}
@Override
public void onExpiration(Session session) {
}
}
@Bean
public SessionManager sessionManager(RedisSessionDAO sessionDAO) {
sessionManager.setSessionListeners( new sessionLister() );
return sessionManager;
}
- Session持久化,自定义sessionDAO组件
sessionDAO:属性sessionDAO,自定义SessionDAO实现AbstractSessionDAO,包含增删改查方便,可以将session持久化到redis,数据库中。但如果你不打算实现你自己的SessionDAO,那么强烈地建议你为Shiro 的SessionManagerment 启用EHCache Manager 支持,将会在内存中保存会话。
- Session持久化,自定义sessionDAO组件
@Component
public class RedisSessionDAO extends AbstractSessionDAO {
@Resource(name = "redisTemplate")
private ValueOperations<Serializable, Session> valueOperations;
@Override
public void update(Session session) throws UnknownSessionException {
this.saveSession(session);
}
@Override
public void delete(Session session) {
if (session == null || session.getId() == null) {
logger.error("session or session id is null");
return;
}
valueOperations.getOperations().delete(session.getId());
}
//用来统计当前活动的session
@Override
public Collection<Session> getActiveSessions() {
return sessions;
}
@Override
protected Serializable doCreate(Session session) {
return sessionId;
}
@Override
protected Session doReadSession(Serializable sessionId) {
return s;
}
}
@Bean
public SessionManager sessionManager(RedisSessionDAO sessionDAO) {
sessionManager.setSessionDAO(sessionDAO);
return sessionManager;
}
- 创建会话Cookie的模板(参照SimpleCookie)
@Bean
public SessionManager sessionManager(SimpleCookie simpleCookie) {
sessionManager.sessionIdCookie(sessionDAO);
return sessionManager;
}
4.缓存管理器
- CacheManager 实例会自动地直接传送到SessionDAO。然后当SessionManager 要求EnterpriseCacheSessionDAO 去持久化一个Session 时,默认它使用一个EHCache 支持的Cache实现去存储Session 数据,若配置其他缓存实现,不需配置,主要是缓存到本地。