什么是shiro?
借用官方的话
Apache Shiro是一种功能强大且易于使用的Java安全框架,可执行身份验证,授权,加密和会话管理,可用于保护任何应用程序的安全-从命令行应用程序,移动应用程序到最大的Web和企业应用程序。
Shiro提供了用于执行以下方面的应用程序安全性API(我将其称为应用程序安全性的4个基石):
- 身份验证-证明用户身份,通常称为用户“登录”。
- 授权-访问控制
- 密码学-保护或隐藏数据以防窥视
- 会话管理-每个用户的时间敏感状态
Shiro还支持一些辅助功能,例如Web应用程序安全性,单元测试和多线程支持,但它们的存在是为了加强上述四个主要方面。
现在使用比较多的安全权限框架还有spring家族的Spring Security,与Spring Security 相比 shiro可能没有 Spring Security 做的功能强大,但是在实际工作时 可能并不需要那么复杂的东西,所以使用小而简单的Shiro 就足够了。
Apache Shiro的优点
自2003年以来,框架环境发生了很大变化,因此今天仍然有充分的理由使用Shiro。实际上有很多原因。Apache Shiro是:
- 易于使用 -易于使用是该项目的最终目标。应用程序安全性可能非常令人困惑和沮丧,并被视为“必要的邪恶”。如果您使它易于使用,以使新手程序员可以开始使用它,那么就不必再痛苦了。
- 全面 -Apache Shiro声称没有其他具有范围广度的安全框架,因此它很可能是满足安全需求的“一站式服务”。
- 灵活 -Apache Shiro可以在任何应用程序环境中工作。尽管它可以在Web,EJB和IoC环境中运行,但并不需要它们。Shiro也不要求任何规范,甚至没有很多依赖性。
- 具有Web功能 -Apache Shiro具有出色的Web应用程序支持,允许您基于应用程序URL和Web协议(例如REST)创建灵活的安全策略,同时还提供一组JSP库来控制页面输出。
- 可插拔 -Shiro干净的API和设计模式使它易于与许多其他框架和应用程序集成。您会看到Shiro与Spring,Grails,Wicket,Tapestry,Mule,Apache Camel,Vaadin等框架无缝集成。
- 支持 -Apache Shiro是Apache Software Foundation(Apache软件基金会)的一部分,该组织被证明以其社区的最大利益行事。项目开发和用户群体友好的公民随时可以提供帮助。如果需要,像Katasoft这样的商业公司也可以提供专业的支持和服务。
简而言之,就是轻量级,小巧方便,易于使用,能与众多框架无缝集成。
shiro使用
shiro的验证流程
认证流程
在执行调用subject.login(token)方法后,会把subject以及token都传进去
(subject是从环境中取出的,也就是说subject是可以代表当前用户所处的上下文环境,也即是说可以拿到当前环境的realm的真实数据);程序会先判断账号,再判断密码。
示例:与spring无缝集成
第一步导入相关shiro框架jar包,或引入shiro依赖
第二步配置spring配置文件
-
把这个filter交给Spring管理,通过ShiroFilterFactoryBean来创建这个ShiroFilter。里面可配置(anon,logout,authc)等多个过滤器。
-
配置好了过滤器,再不妨想想在JavaSE中我们是怎么进行登录认证的?
我们先是进行安全管理器的设置,告知当前环境用的是什么管理器,所以我们也需要在spring中配置安全管理器。上面讲到,通过源码分析发现自定义数据源是在创建securityManager实例对象时加载的,所以在spring配置
securityManager的时候,我们要告知安全管理器是用哪个数据源。配置property -
过滤中执行认证操作
过滤功能有了,认证功能也有了此时我们就是需要在过滤的时候进行认证操作,也就是结合这个两个功能,这是只需要将filter和securityManager配置关联即可
<!--注意:名字必须要和web.xml中配置的名字一致-->
<!-- 定义ShiroFilter -->
<bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
<property name="securityManager" ref="securityManager"/>
<property name="loginUrl" value="/login.html"/>
<property name="filterChainDefinitions">
<value>
/js/**=anon
/bootstrap-3.3.7-dist/**=anon
/jQuery/**=anon
/images/**=anon
/css/**=anon
/style/**=anon
/logout.do=logout
/**=authc
</value>
</property>
<property name="filters">
<map>
<entry key="authc" value-ref="myCRMFormFilter"/>
</map>
</property>
</bean>
<!-- 配置安全管理器SecurityManager 在web环境下使用默认web安全管理器-->
<bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
<property name="realm" ref="myWebRealm"/>
</bean>
授权操作
//授权
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
//创建一个空的AuthorizationInfo
SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
//拿到当前用户
Employee employee = (Employee)principalCollection.getPrimaryPrincipal();
//判断是否是超级管理员
if(employee.getAdmin()){
//给管理员设置用户信息,并且可以查询所有权限
info.addRole("admin");
info.addStringPermission("*:*");
return info;
}else{
//从数据库中查到所对应的角色和权限
List<String> roles = employeeService.getRolesByEmployeeId(employee.getId());
Set<String> permissions = employeeService.getPermissionsByEmployeeId(employee.getId());
info.addRoles(roles);
info.addStringPermissions(permissions);
return info;
}
}
就像我们之前做RBAC的一样,既然要有权限控制,那么资源所对应的权限是我们规定的。
- 加载权限
加载权限也是将Controller中贴有注解(@RequiresPermissions)的方法扫描出来存进数据库中,同样也是通过注入的方式拿到Spring容器对象不同点在于:
-
使用Shiro时,使用容器对象的getBeansWithAnnotation()获得的controller是可以包括贴有@Controller注解的类的子类的 (这里的意思是说,Shrio会自动将贴有标签的Controller类动态生成相应的代理类,而@Controller这个注解是没有继承的,但是SpringMVC还是能查找到,并且如果有子类只会找子类而不会找其父类) 然后我们要判断这些字节码对象是否是属于cglib的代理类 (
AopUtils.isCglibProxy(controller)
) -
再用这些判断后的字节码对象获得其父类字节码(
controller.getClass().getSuperclass()
)(@RequiresPermissions标签不继承)找到贴有这些注解的方法,获取其方法体上的注解字节码然后拿到内容,存进数据库中 - 取出权限并存入作用域中
使用Shiro可以很方便的做到这一步,
就像上面说的,只需要通过principalCollection.getPrimaryPrincipal()拿到当前身份信息,也就是认证过的用户,然后把权限从数据库查到,丢到info即可与原来RBAC的不同在于
RBAC需要是用RequestContextHolder.getRequestAttributes()
方法拿到session,然后再丢进session,这样其实很麻烦。
总的来说
Shiro是先进行认证,认证通过后再
进行授权,什么时候校验权限?访问方法的时候,代理类增强的方法会去检验。
MD5加密
在认证的时候会用到MD5加密,因为存进数据库的密码是通过加密的,而用户登录表单传过来的密码也要相同规则加密才行,这时我们在数据源中只将盐丢进info里面,让shiro后续进行加密即可,那么实行什么方式的加密是我们配置的,在shiro.xml中配置,然后配置给自定义中的setCredentialsMatcher
方法
<!--配置凭证匹配器,并将其设置给realm(通过注入的方式)-->
<bean class="org.apache.shiro.authc.credential.HashedCredentialsMatcher">
<property name="hashAlgorithmName" value="md5"/>
</bean>
在使用shiro验证权限时,因为是shiro自动生成的动态代理类,使用的AoP织入,所以我们要加上AoP的配置(事务时已经加过了),又因为在功能加强中要知道当前的安全管理器,才能获取到数据源等信息,所以我们需要指明数据源
<!--配置权限AoP织入增强功能-->
<bean class="org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor">
<property name="securityManager" ref="securityManager"/>
</bean>
缓存管理器
使用shiro自带的缓存管理器,这时权限和角色信息(shrio只负责这两块,所以也只缓存这两块,不需另外指明)缓存到内存中,这样就不会刷新页面访问同样的资源时还要执行数据源中的授权方法,这样就不用再发SQL了
<!-- 缓存管理器开始 -->
<bean id="cacheManager" class="org.apache.shiro.cache.ehcache.EhCacheManager">
<property name="cacheManager" ref="ehCacheManager"/>
</bean>
<bean id="ehCacheManager" class ="org.springframework.cache.ehcache.EhCacheManagerFactoryBean">
<property name="configLocation" value="classpath:shiro-ehcache.xml" />
<property name="shared" value="true"/>
</bean>
以上就是关于shiro的基本介绍与使用