技术开发 频道

安全框架:让Apache Shiro保护你的应用

  会话管理

  在安全框架领域,Apache Shiro提供了一些独特的东西:可在任何应用或架构层一致地使用Session API。即,Shiro为任何应用提供了一个会话编程范式 - 从小型后台独立应用到大型集群Web应用。这意味着,那些希望使用会话的应用开发者,不必被迫使用Servlet或EJB容器了。或者,如果正在使用这些容器,开发者现在也可以选择使用在任何层统一一致的会话API,取代Servlet或EJB机制。

  但Shiro会话最重要的一个好处或许就是它们是独立于容器的。这具有微妙但非常强大的影响。例如,让我们考虑一下会话集群。对集群会话来讲,支持容错和故障转移有多少种容器特定的方式?Tomcat的方式与Jetty的不同,而Jetty又和Websphere不一样,等等。但通过Shiro会话,你可以获得一个容器无关的集群解决方案。Shiro的架构允许可插拔的会话数据存储,如企业缓存、关系数据库、NoSQL系统等。这意味着,只要配置会话集群一次,它就会以相同的方式工作,跟部署环境无关 - Tomcat、Jetty、JEE服务器或者独立应用。不管如何部署应用,毋须重新配置应用。

  Shiro会话的另一好处就是,如果需要,会话数据可以跨客户端技术进行共享。例如,Swing桌面客户端在需要时可以参与相同的Web应用会话中 - 如果最终用户同时使用这两种应用,这样的功能会很有用。那你如何在任何环境中访问Subject的会话呢?请看下面的示例,里面使用了Subject的两个方法。

  清单10. Subject的会话

Session session = subject.getSession();
Session session
= subject.getSession(boolean create);

  如你所见,这些方法在概念上等同于HttpServletRequest API。第一个方法会返回Subject的现有会话,或者如果还没有会话,它会创建一个新的并将之返回。第二个方法接受一个布尔参数,这个参数用于判定会话不存在时是否创建新会话。一旦获得Shiro的会话,你几乎可以像使用HttpSession一样使用它。Shiro团队觉得对于Java开发者,HttpSession API用起来太舒服了,所以我们保留了它的很多感觉。当然,最大的不同在于,你可以在任何应用中使用Shiro会话,不仅限于Web应用。清单11中显示了这种相似性。

  清单11. 会话的方法

Session session = subject.getSession();
session.getAttribute(
"key", someValue);
Date start
= session.getStartTimestamp();
Date timestamp
= session.getLastAccessTime();
session.setTimeout(millis); ...

  加密

  加密是隐藏或混淆数据以避免被偷窥的过程。在加密方面,Shiro的目标是简化并让JDK的加密支持可用。

  清楚一点很重要,一般情况下,加密不是特定于Subject的,所以它是Shiro API的一部分,但并不特定于Subject。你可以在任何地方使用Shiro的加密支持,甚至在不使用Subject的情况下。对于加密支持,Shiro真正关注的两个领域是加密哈希(又名消息摘要)和加密密码。下面我们来看看这两个方面的详细描述。

  哈希

  如果你曾使用过JDK的MessageDigest类,你会立刻意识到它的使用有点麻烦。MessageDigest类有一个笨拙的基于工厂的静态方法API,它不是面向对象的,并且你被迫去捕获那些永远都不必捕获的Checked Exceptions。如果需要输出十六进制编码或Base64编码的消息摘要,你只有靠自己 - 对上述两种编码,没有标准的JDK支持它们。Shiro用一种干净而直观的哈希API解决了上述问题。

  打个比方,考虑比较常见的情况,使用MD5哈希一个文件,并确定该哈希的十六进制值。被称为‘校验和’,这在提供文件下载时常用到 - 用户可以对下载文件执行自己的MD5哈希。如果它们匹配,用户完全可以认定文件在传输过程中没有被篡改。

  不使用Shiro,你需要如下步骤才能完成上述内容:

  1、将文件转换成字节数组。JDK中没有干这事的,故而你需要创建一个辅助方法用于打开FileInputStream,使用字节缓存区,并抛出相关的IOExceptions,等等。

  2、使用MessageDigest类对字节数组进行哈希,处理相关异常,如清单12所示。

  3、将哈希后的字节数组编码成十六进制字符。JDK中还是没有干这事的,你依旧需要创建另外一个辅助方法,有可能在你的实现中会使用位操作和位移动。

1
相关文章