apache shiro_Apache Shiro的应用程序安全性

apache shiro

使用Apache Shiro的更新

将Apache Shiro和Java EE 7配对-了解如何在JavaEE7应用程序中使用Shiro以及如何在Web应用程序中使用Shiro。 下载免费的gudeide。

尝试保护应用程序安全时,您感到沮丧吗? 您是否认为现有的Java安全解决方案难以使用,只会使您进一步困惑? 本文介绍了Apache Shiro (一种Java安全框架),它为应用程序安全提供了一种简单但功能强大的方法。 它解释了Apache Shiro的项目目标,体系结构理念以及如何使用Shiro来保护自己的应用程序。

什么是Apache Shiro?

Apache Shiro(发音为“ shee-roh”,日语为“ castle”)是一种功能强大且易于使用的Java安全框架,它执行身份验证,授权,加密和会话管理,可用于保护任何应用程序的安全-从命令行应用程序,移动应用程序到最大的Web和企业应用程序。

Shiro提供了应用程序安全性API来执行以下方面(我喜欢将它们称为应用程序安全性的4个基石):

  • 身份验证-证明用户身份,通常称为用户“登录”。
  • 授权-访问控制
  • 密码学-保护或隐藏数据以防窥视
  • 会话管理-每个用户的时间敏感状态

Shiro还支持一些辅助功能,例如Web应用程序安全性,单元测试和多线程支持,但它们的存在是为了加强上述四个主要方面。

为什么创建Apache Shiro?

为了使框架真正为其生存提供充分的理由,并因此成为您使用它的理由,它应满足其他替代方案无法满足的需求。 要了解这一点,我们需要查看Shiro的历史以及创建它时的替代方法。

在2008年加入Apache Software Foundation之前,Shiro已有5年的历史,以前被称为JSecurity项目,该项目始于2003年初。2003年,Java应用程序开发人员的通用安全替代品并不多-我们很漂亮Java身份验证和授权服务(也称为JAAS)非常困难。 JAAS有很多缺点-尽管其身份验证功能尚可忍受,但授权方面却令人困惑且难以使用。 此外,JAAS与虚拟机级别的安全问题紧密相关,例如,确定是否应允许在JVM中加载类。 作为应用程序开发人员,我更关心应用程序最终用户可以做什么,而不是我的代码可以在JVM中做什么。

由于我当时使用的应用程序,我还需要访问一个干净的,与容器无关的会话机制。 当时游戏中唯一的会话选择是需要使用Web容器的HttpSessions或需要EJB容器的EBJ 2.1状态会话Bean。 我需要可以与容器分离的东西,可以在我选择的任何环境中使用。

最后,还有密码学的问题。 有时候我们都需要保持数据安全,但是除非您是加密专家,否则很难理解Java密码体系结构。 该API充满了受检查的异常,使用起来很麻烦。 我希望有一个更干净的即用型解决方案,可以根据需要轻松地加密和解密数据。

因此,从2003年初的安全形势来看,您可以很快意识到,没有什么可以在一个统一的框架中满足所有这些要求的。 因此,JSecurity和后来的Apache 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 FoundationApache软件基金会 )的一部分,该组织被证明以其社区的最大利益为出发点。 项目开发和用户群体友好的公民随时可以提供帮助。 如果需要,像Katasoft这样的商业公司也可以提供专业的支持和服务。

谁在使用Shiro?

Shiro及其前身JSecurity已在各种规模和行业的公司的项目中使用了多年。 自成为Apache Software Foundation顶级项目以来,网站访问量和采用率一直在显着增长。 许多开源社区也在使用Shiro,例如Spring,Grails,Wicket,Tapestry,Tynamo,Mule和Vaadin,仅举几例。

主要社交网络之一的Katasoft,Sonatype,MuleSoft等商业公司以及多家纽约商业银行都使用Shiro来保护其商业软件和网站。

核心概念:主题,SecurityManager和领域

既然我们已经介绍了Shiro的优点,那么让我们直接进入它的API,以便您可以体会到它。 Shiro的体系结构具有三个主要概念-主题,安全管理器和领域。

学科

在保护应用程序安全时,可能要问自己最相关的问题是:“当前用户是谁?” 或“是否允许当前用户执行X”? 在编写代码或设计用户界面时,我们通常会问自己以下问题:应用程序通常基于用户案例构建,并且您希望基于每个用户来表示(并保护)功能。 因此,我们考虑应用程序安全性的最自然的方法是基于当前用户。 Shiro的API在其主题概念中从根本上代表了这种思维方式。

主题 ”一词是一个安全术语,基本上表示“当前正在执行的用户”。 它只是不被称为“用户”,因为“用户”一词通常与人类相关联。 在安全的世界,术语“主题”可以指一个人,也是一个第三方进程,守护进程帐户,或任何类似。 它仅表示“当前正在与软件交互的事物”。 但是对于大多数意图和目的,您可以将其视为Shiro的“用户”概念。 您可以在代码中的任何位置轻松获取Shiro Subject,如下面的清单1所示。

清单 1 取得主题

import org.apache.shiro.subject.Subject;
import org.apache.shiro.SecurityUtils;
...
Subject currentUser = SecurityUtils.getSubject();

获取主题后,您可以立即访问当前用户想要使用Shiro进行的所有操作的90%,例如登录,注销,访问他们的会话,执行授权检查等等-但稍后会介绍更多。 这里的关键是Shiro的API在很大程度上是直观的,因为它反映了开发人员在“每用户”安全控制中进行思考的自然趋势。 在代码中的任意位置访问主题也很容易,从而可以在需要的地方进行安全操作。

安全管理器

主题的“幕后”对应对象是SecurityManager。 主题代表当前用户的安全操作,而SecurityManager管理所有用户的安全操作。 它是Shiro体系结构的核心,并充当一种“伞”对象,引用了许多内部嵌套的安全组件,这些安全组件构成了一个对象图。 但是,一旦配置了SecurityManager及其内部对象图,通常就不理会它,应用程序开发人员几乎将所有时间都花在Subject API上。

那么如何设置SecurityManager? 好吧,这取决于您的应用程序环境。 例如,Web应用程序通常将在web.xml中指定Shiro Servlet过滤器,这将设置SecurityManager实例。 如果您运行的是独立应用程序,则需要以其他方式对其进行配置。 但是有许多配置选项。

每个应用程序几乎总是有一个SecurityManager实例。 它本质上是一个应用程序单例(尽管不必是静态单例)。 像Shiro中的几乎所有内容一样,默认的SecurityManager实现是POJO ,并且可以使用任何与POJO兼容的配置机制-常规Java代码,Spring XML,YAML,.properties和.ini文件等进行配置。基本上,任何能够实例化的东西可以使用类和与JavaBeans兼容的调用方法。

为此,Shiro通过基于文本的INI配置提供了默认的“共母”解决方案。 INI易于阅读,易于使用,并且几乎不需要依赖项。 您还将看到,通过简单地了解对象图导航,可以有效地使用INI来配置简单的对象图,例如SecurityManager。 请注意,Shiro还支持Spring XML配置和其他替代方案,但我们将在此处介绍INI。

下面的清单2中的示例显示了基于INI配置Shiro的最简单示例。

清单2.使用INI配置Shiro

[main]
cm = org.apache.shiro.authc.credential.HashedCredentialsMatcher
cm.hashAlgorithm = SHA-512
cm.hashIterations = 1024
# Base64 encoding (less text):
cm.storedCredentialsHexEncoded = false

iniRealm.credentialsMatcher = $ cm

[使用者]
jdoe = TWFuIGlzIGRpc3Rpbmd1aXNoZWQsIG5vdCBvbmx5IGJpcyByZWFzb2
铁匠= IHNpbmd1bGFyIHBhc3Npb24gZnJvbSBvdGhlciBhbXNoZWQsIG5vdCB

在清单2中,我们看到了用于配置SecurityManager实例的INI配置示例。 INI分为两个部分:[main]和[users]。

[main]部分是配置SecurityManager对象和/或SecurityManager使用的任何对象(如领域)的地方。 在此示例中,我们看到两个对象被配置:

  1. cm对象,它是Shiro的HashedCredentialsMatcher类的实例。 如您所见,cm实例的各种属性是通过“嵌套点”语法配置的,该语法由清单3所示的IniSecurityManagerFactory用来表示对象图导航和属性设置。
  2. iniRealm对象,是SecurityManager用来表示以INI格式定义的用户帐户的组件。

在[用户]部分中,您可以指定用户帐户的静态列表-适用于简单的应用程序或测试时。

出于本简介的目的,理解每一部分的复杂性并不重要,而是要了解INI配置是配置Shiro的一种简单方法。 有关INI配置的更多详细信息,请参阅Shiro的文档

清单3.加载shiro.ini配置文件

import org.apache.shiro.SecurityUtils;
import org.apache.shiro.config.IniSecurityManagerFactory;
import org.apache.shiro.mgt.SecurityManager;
import org.apache.shiro.util.Factory;

...

// 1。 加载INI配置
Factory <SecurityManager>工厂=
新的IniSecurityManagerFactory(“ classpath:shiro.ini”);

// 2。 创建SecurityManager
SecurityManager securityManager = factory.getInstance();

// 3。 使其可访问
SecurityUtils.setSecurityManager(securityManager);

在清单3中,在这个简单的示例中,我们看到了一个三步过程:

  1. 加载将配置SecurityManager及其组成组件的INI配置。
  2. 根据配置创建SecurityManager实例(使用代表工厂方法设计模式的 Shiro的Factory概念)。
  3. 使SecurityManager单例可被应用程序访问。 在这个简单的示例中,我们将其设置为VM静态单例,但这通常不是必需的-您的应用程序配置机制可以确定是否需要使用静态内存。

境界

Shiro的第三个也是最后一个核心概念是领域 。 领域充当Shiro与应用程序的安全数据之间的“桥梁”或“连接器”。 也就是说,当需要真正与安全性相关的数据(例如用户帐户)进行交互以执行身份验证(登录)和授权(访问控制)时,Shiro会从为应用程序配置的一个或多个Realms中查找其中的许多内容。

从这个意义上说,领域本质上是特定于安全性的DAO :它封装了数据源的连接详细信息,并根据需要使关联数据可用于Shiro。 在配置Shiro时,您必须至少指定一个领域用于身份验证和/或授权。 可以配置多个Realm,但至少需要一个。

Shiro提供了开箱即用的领域,可以连接到许多安全数据源(又名目录),例如LDAP,关系数据库(JDBC),文本配置源(例如INI和属性文件)等。 如果默认的Realms不能满足您的需求,那么您可以插入自己的Realm实现以表示自定义数据源。 下面的清单4是配置Shiro(通过INI)以将LDAP目录用作应用程序的领域之一的示例。

清单4.连接到LDAP用户数据存储区的示例领域配置代码段

[main]
ldapRealm = org.apache.shiro.realm.ldap.JndiLdapRealm
ldapRealm.userDnTemplate = uid={0},ou=users,dc=mycompany,dc=com
ldapRealm.contextFactory.url = ldap://ldapHost:389
ldapRealm.contextFactory.authenticationMechanism = DIGEST-MD5

既然我们已经了解了如何设置基本的Shiro环境,那么让我们讨论一下,作为开发人员,您将如何使用该框架。

认证方式

身份验证是验证用户身份的过程。 也就是说,当用户通过应用程序进行身份验证时,他们在证明自己实际上就是他们所说的身份。 有时也称为“登录”。 这通常是一个三步过程。

  1. 收集用户的标识信息(称为主体 )和支持身份的凭证 (称为凭据)
  2. 将主体和凭据提交到系统。
  3. 如果提交的凭据与系统对该用户身份(本金)的期望匹配,则认为该用户已通过身份验证。 如果不匹配,则不认为用户已通过身份验证。

每个人都熟悉的此过程的一个常见示例是用户名/密码组合。 当大多数用户登录软件应用程序时,通常会提供其用户名(主体)和支持密码(凭据)。 如果存储在系统中的密码(或密码表示形式)与用户指定的密码匹配,则认为它们已通过身份验证。

Shiro以简单直观的方式支持相同的工作流程。 如前所述,Shiro具有以主题为中心的API-在运行时,您与Shiro所做的几乎所有事情都可以通过与当前正在执行的Subject进行交互来实现。 因此,要登录主题,您只需调用其登录方法,并传递一个AuthenticationToken实例,该实例代表提交的主体和凭据(在本例中为用户名和密码)。 此示例在下面的清单5中显示。

清单5.主题登录

//1. Acquire submitted principals and credentials:
AuthenticationToken token =
new UsernamePasswordToken(username, password);

// 2。 获取当前主题:
主题currentUser = SecurityUtils.getSubject();

// 3。 登录:
currentUser.login(token);

如您所见,Shiro的API轻松反映了通用的工作流程。 您将继续把这种简单性作为主题操作的所有主题。 调用登录方法时,SecurityManager将接收AuthenticationToken并将其分派到一个或多个配置的领域,以允许每个领域根据需要执行身份验证检查。 每个领域都可以根据需要对提交的AuthenticationToken做出React。 但是,如果登录尝试失败会怎样? 如果用户指定了错误的密码怎么办? 您可以通过对Shiro的运行时AuthenticationException做出React来处理故障,如清单6所示。

清单6.处理失败的登录

//3. Login:
try {
    currentUser.login(token);
} catch (IncorrectCredentialsException ice) { …
} catch (LockedAccountException lae) { …
}
…
catch (AuthenticationException ae) {…
}

您可以选择捕获AuthenticationException子类之一并进行具体React,或者以一般方式处理任何AuthenticationException(例如,向用户显示通用的“用户名或密码错误”消息)。 选择取决于您,具体取决于您的应用程序需求。

主题成功登录后,它们被认为已通过身份验证,通常您允许他们使用您的应用程序。 但是,仅仅因为用户证明了自己的身份并不意味着他们可以在应用程序中做任何想做的事情。 这就引出了下一个问题:“我如何控制允许用户执行或不执行的操作?” 确定允许用户执行的操作称为授权 。 接下来,我们将介绍Shiro如何启用授权。

授权书

授权本质上是访问控制-控制用户可以在应用程序中访问的内容(例如资源,网页等)。大多数用户通过使用角色和权限等概念来执行访问控制。 也就是说,通常根据分配给他们的角色和/或权限,允许用户执行某项操作或不执行某项操作。 然后,您的应用程序可以根据对这些角色和权限的检查来控制公开哪些功能。 如您所料,主题API使您可以非常轻松地执行角色和权限检查。 例如,清单7中的代码片段显示了如何检查Subject是否已分配了特定角色。

清单7.角色检查

if ( subject.hasRole(“administrator”) ) {
    //show the ‘Create User’ button
} else {
    //grey-out the button?
}

如您所见,您的应用程序可以基于访问控制检查启用或禁用功能。

权限检查是执行授权的另一种方法。 如上例所示,检查角色存在一个重大缺陷:您不能在运行时添加或删除角色。 您的代码使用角色名称进行了硬编码,因此,如果更改了角色名称和/或配置,则代码将被破坏! 如果您需要能够在运行时更改角色的含义,或者根据需要添加或删除角色,则必须依赖其他内容。

为此,Shiro支持其权限概念。 权限是对功能的原始说明,例如“开门”,“创建博客条目”,“删除'jsmith'用户”等。通过使权限反映应用程序的原始功能,您只需要更改权限即可。检查何时更改应用程序的功能。 反过来,您可以在运行时根据需要向角色或用户分配权限。

作为一个示例,如下面的清单8所示,我们可以重写之前的角色检查,而使用权限检查。

清单8.权限检查

if ( subject.isPermitted(“user:create”) ) {
    //show the ‘Create User’ button
} else {
    //grey-out the button?
}

这样,分配了“ user:create”权限的任何角色或用户都可以单击“创建用户”按钮,并且这些角色和分配甚至可以在运行时更改,从而为您提供了非常灵活的安全模型。

“ user:create”字符串是遵循某些解析约定的权限字符串的示例。 Shiro的WildcardPermission支持此约定。 尽管不在本文介绍的范围之内,但是您会发现WildcardPermission在创建安全策略时可以非常灵活,甚至支持实例级访问控制之类的功能。

清单9.实例级权限检查

if ( subject.isPermitted(“user:delete:jsmith”) ) {
    //delete the ‘jsmith’ user
} else {
    //don’t delete ‘jsmith’
}

此示例表明,如果需要,您甚至可以控制到细粒度的实例级别,以访问单个资源。 如果愿意,您甚至可以发明自己的权限语法。 有关更多信息,请参见Shiro权限文档。 最后,与身份验证一样,上述调用最终也进入了SecurityManager,后者将咨询一个或多个Realms来做出访问控制决策。 这使领域可以根据需要响应身份验证和授权操作。

因此,这是Shiro授权功能的简要概述。 尽管大多数安全框架都停止了身份验证和授权,但Shiro提供了更多功能。 接下来,我们将讨论Shiro的高级会话管理功能。

会话管理

Apache Shiro在安全框架领域提供了一些独特的功能:可在任何应用程序和任何体系结构层中使用的一致的Session API。 也就是说,Shiro为任何应用程序启用了会话编程范例-从小型守护程序独立应用程序到最大的群集Web应用程序。 这意味着希望使用会话的应用程序开发人员不再需要,则不再需要使用Servlet或EJB容器。 或者,如果使用这些容器,开发人员现在可以选择在任何层中使用统一且一致的会话API,而不是使用servlet或EJB特定的机制。

但是Shiro会话的最重要好处之一就是它们独立于容器。 这具有微妙但极其强大的含义。 例如,让我们考虑会话群集。 有多少种特定于容器的方式可以对会话进行群集以实现容错和故障转移? Tomcat与Jetty的功能不同,而Jetty与Websphere的功能不同。但是,通过Shiro会话,您可以获得独立于容器的集群解决方案。 Shiro的体系结构允许可插入的Session数据存储,例如企业缓存,关系数据库,NoSQL系统等等。 这意味着您只需配置一次会话集群,无论部署环境如何(Tomcat,Jetty,JEE Server或独立应用程序),它都将以相同的方式工作。 无需根据部署应用程序的方式重新配置应用程序。

Shiro会话的另一个好处是,如果需要,会话数据可以在客户端技术之间共享。 例如,如果需要,Swing桌面客户端可以参与相同的Web应用程序会话-如果最终用户同时使用这两者,则很有用。 那么,您如何在任何环境中访问主题的会话? 如下面的示例所示,有两种Subject方法。

清单10.主题的会话

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

如您所见,这些方法在概念上与HttpServletRequest API相同。 第一种方法将返回主题的现有会话,或者如果没有,则将创建一个新的会话并返回它。 第二种方法接受一个布尔参数,该参数确定是否将创建一个新的会话(如果尚不存在)。 一旦获得了主题的会话,就可以几乎像HttpSession一样使用它。 Shiro团队认为HttpSession API最适合Java开发人员,因此我们保留了大部分感觉。 当然,最大的区别是您可以在任何应用程序中使用Shiro Sessions,而不仅仅是Web应用程序。 清单11显示了这种熟悉程度。

清单11.会话方法

Session session = subject.getSession();

session.getAttribute(“ key”,someValue);
开始日期= session.getStartTimestamp();
日期时间戳= session.getLastAccessTime();
session.setTimeout(millis);
...

密码学

密码术是隐藏或混淆数据的过程,因此窥探眼睛无法理解它。 Shiro的密码学目标是简化JDK的密码学并使之可用。

重要的是要注意,密码通常不是特定于主题的,因此Shiro API的一个领域不是特定于主题的。 即使未使用“主题”,也可以在任何地方使用Shiro的加密支持。 Shiro真正侧重于其加密支持的两个领域是加密哈希(又名消息摘要)和加密密码领域。 让我们更详细地看看这两个。

散列

如果使用了JDK的MessageDigest类,您很快就会意识到使用它有点麻烦。 它具有笨拙的基于静态方法的基于工厂的API,而不是面向对象的API,因此您不得不捕获可能永远不需要捕获的已检查异常。 如果需要十六进制编码或Base64编码的消息摘要输出,则由您自己决定-两者均不提供标准的JDK支持。 Shiro通过干净直观的哈希API解决了这些问题。

例如,让我们考虑MD5散列文件并确定该散列的十六进制值的相对常见的情况。 称为“校验和”,在提供文件下载时经常使用它-用户可以对下载的文件执行自己的MD5哈希,并断言其校验和与下载站点上的校验和匹配。 如果它们匹配,则用户可以充分假设文件在传输过程中未被篡改。

没有 Shiro的情况下,您可以尝试以下操作:

  1. 将文件转换为字节数组。 JDK中没有任何东西可以帮助您解决此问题,因此您需要创建一个帮助程序方法,该方法可打开FileInputStream ,使用字节缓冲区并抛出适当的IOExceptions等。
  2. 使用MessageDigest类对字节数组进行哈希处理,以处理适当的异常,如下面的清单12所示。
  3. 将散列字节数组编码为十六进制字符。 JDK中也没有任何东西可以帮助完成此任务,因此您将需要创建另一个帮助器方法,并且可能在实现中使用按位运算和移位。

清单12. JDK的MessageDigest

try {
    MessageDigest md = MessageDigest.getInstance("MD5");
    md.digest(bytes);
    byte[] hashed = md.digest();
} catch (NoSuchAlgorithmException e) {
    e.printStackTrace();
}

对于如此简单且相对常见的事情,这是大量的工作。 现在,这就是使用 Shiro进行完全相同的操作的方法。

String hex = new Md5Hash(myFile).toHex();

使用Shiro简化所有工作时,了解正在发生的事情非常简单和容易。 SHA-512哈希和密码的Base64编码也很容易。

String encodedPassword =
    new Sha512Hash(password, salt, count).toBase64();

您会看到Shiro在很大程度上简化了哈希和编码,从而在此过程中节省了一些理智。

密码

密码是可以使用密钥可逆地转换数据的密码算法。 我们使用它们来保护数据安全,尤其是在传输或存储数据时,尤其是在数据容易被撬开的时候。

如果您曾经使用过JDK密码API,尤其是javax.crypto.Cipher类,那么您就会知道,它是驯服极其复杂的野兽。 对于初学者,每种可能的Cipher配置始终由javax.crypto.Cipher的实例表示。 需要做公钥/私钥加密吗? 您使用密码。 是否需要使用分组密码进行流操作? 您使用密码。 是否需要创建AES 256位密码来保护数据? 您使用密码。 你明白了。

以及如何创建所需的Cipher实例? 您创建了一个复杂的,不直观的,用令牌分隔的密码选项字符串,称为“转换字符串”,并将该字符串传递给Cipher.getInstance静态工厂方法。 使用这种密码选项字符串方法,没有类型安全性来确保您使用的是有效选项。 这也暗含意味着没有JavaDoc可以帮助您了解相关选项。 而且,即使您知道配置正确,也需要处理经过检查的异常,以防String的格式错误。 如您所见,使用JDK Ciphers是一项非常繁琐的任务。 这些技术很久以前曾经是Java API的标准,但是时代已经改变,我们希望有一种更简单的方法。

Shiro试图通过引入其CipherService API来简化整个密码算法的概念。 大多数开发人员在保护数据时都希望使用CipherService:一种简单,无状态,线程安全的API,可以在一个方法调用中完整地加密或解密数据。 您所需要做的就是提供密钥,然后可以根据需要加密或解密。 例如,可以使用256位AES加密,如下面的清单13所示。

清单13. Apache Shiro的Encryption API

AesCipherService cipherService = new AesCipherService();
cipherService.setKeySize(256);

//创建一个测试密钥:
byte [] testKey = cipherService.generateNewKey();

//加密文件的字节:
byte []加密=
cipherService.encrypt(fileBytes,testKey);

与JDK的Cipher API相比,Shiro示例更简单:

  • 您可以直接实例化CipherService-没有奇怪或令人困惑的工厂方法。
  • 密码配置选项表示为与JavaBeans兼容的getter和setter-没有奇怪且难以理解的“转换字符串”。
  • 加密和解密在单个方法调用中执行。
  • 没有强制检查的异常。 如果需要,请捕获Shiro的CryptoException。

Shiro的CipherService API还有其他好处,例如既可以支持基于字节数组的加密/解密(称为“块”操作),又可以支持基于流的加密/解密(例如,对音频或视频进行加密)。

Java密码术不必很痛苦。 Shiro的密码学支持旨在简化您保护数据安全的工作。

网路支援

最后但并非最不重要的一点,我们将简要介绍Shiro的网络支持。 Shiro随附了强大的Web支持模块,以帮助保护Web应用程序。 为Web应用程序设置Shiro很简单。 唯一需要做的就是在web.xml中定义Shiro Servlet过滤器。 清单14显示了此代码。

清单14. web.xml中的ShiroFilter

<filter>
    <filter-name>ShiroFilter</filter-name>
    <filter-class>
        org.apache.shiro.web.servlet.IniShiroFilter
    </filter-class>
    <!-- no init-param means load the INI config
        from classpath:shiro.ini --> 
</filter>

<过滤器映射>
<filter-name> ShiroFilter </ filter-name>
<url-pattern> / * </ url-pattern>
</ filter-mapping>

该过滤器可以读取上述的shiro.ini配置,因此无论部署环境如何,您都可以获得一致的配置体验。 配置完成后,Shiro过滤器将过滤每个请求,并确保在请求期间可访问特定于请求的主题。 并且因为它过滤了每个请求,所以您可以执行特定于安全性的逻辑,以确保仅允许满足特定条件的请求通过。

URL特定的过滤器链

Shiro通过其创新的URL过滤器链接功能支持特定于安全性的过滤器规则。 它允许您为任何匹配的URL模式指定临时过滤器链。 这意味着您在使用Shiro的过滤机制执行安全规则(或规则组合)方面具有很大的灵活性-比仅在web.xml中定义过滤器要强得多。 清单15显示了Shiro INI中的配置代码段。

清单15.特定于路径的过滤器链

[urls]
/assets/** = anon
/user/signup = anon
/user/** = user
/rpc/rest/** = perms[rpc:invoke], authc
/** = authc

如您所见,Web应用程序有一个[urls] INI部分。 对于每一行,等号左侧的值代表上下文相关的Web应用程序路径。 右边的值定义了一个Filter链-要对给定路径执行的Servlet过滤器的列表,以逗号分隔。 每个过滤器都是一个普通的Servlet过滤器,但是您在上面看到的过滤器名称(匿名,用户,权限,身份验证)是Shiro提供的与安全相关的特殊过滤器。 您可以混合使用这些安全过滤器,以创建非常自定义的安全体验。 您还可以指定任何其他现有的Servlet过滤器。

与使用web.xml(定义一个过滤器块,然后定义一个分离的过滤器模式块)相比,这要好多少? 使用Shiro的方法,可以更轻松地准确查看针对给定匹配路径执行的过滤器链。 如果需要,您可以在web.xml中仅定义Shiro过滤器,并在shiro.ini中定义所有其他过滤器和过滤器链,以使过滤器链定义机制比web.xml更加简洁明了。 即使您没有使用Shiro的任何安全功能,仅此一项小小的便利都可以使Shiro值得使用。

JSP标签库

Shiro还提供了一个JSP标记库,该库使您可以基于当前Subject的状态来控制JSP页面的输出。 一个有用的常见示例是在用户登录后显示“ Hello <用户名>”文本。 但是,如果它们是匿名的,则可能需要显示其他内容,例如“ Hello! 立即注册!” 代替。 清单16显示了如何使用Shiro的JSP标记支持这一点。

清单16. JSP Taglib示例

<%@ taglib prefix="shiro"
    uri="http://shiro.apache.org/tags" %>
...
<p>Hello
<shiro:user>
    <!-- shiro:principal prints out the Subject’s main
        principal - in this case, a username: -->
    <shiro:principal/>!
</shiro:user>
<shiro:guest>
    <!-- not logged in - considered a guest. Show
        the register link: -->
    ! <a href=”register.jsp”>Register today!</a>
</shiro:guest>
</p>

还有其他标签可让您根据拥有(或没有)的角色,分配(或未分配)什么权限以及是否对它们进行身份验证,从“记住我”服务中记住这些权限或匿名访客。

Shiro支持许多其他特定于Web的功能,例如简单的“ Remember Me”服务,REST和BASIC身份验证,当然,如果要使用Shiro的本机企业会话,则当然还支持透明的HttpSession支持。 请参阅Apache Shiro网站文档以获取更多信息。

网络会话管理

最后,有趣的是指出Shiro对Web环境中的会话的支持。

默认Http会话

对于Web应用程序,Shiro缺省其会话基础结构使用我们都习惯的现有Servlet容器会话。 也就是说,当您调用方法subject.getSession()和subject.getSession(boolean)时,Shiro将返回由Servlet容器的HttpSession实例支持的Session实例。 这种方法的优点在于,调用subject.getSession()的业务层代码与Shiro Session实例进行交互-它不知道与基于Web的HttpSession对象一起工作。 在跨架构层保持清晰隔离时,这是一件非常好的事情。

Web层中Shiro的本机会话

如果由于需要Shiro的企业会话功能(例如与容器无关的集群)而在Web应用程序中启用了Shiro的本机会话管理,那么您当然希望HttpServletRequest.getSession()和HttpSession API与“本机”会话一起使用,并且而不是servlet容器会话。 如果您必须重构任何使用HttpServletRequest和HttpSession API的代码来替代使用Shiro的Session API,那将非常令人沮丧。 Shiro当然不会期望您这样做。 相反,Shiro完全实现了Servlet规范的Session部分,以支持Web应用程序中的本机会话。 这意味着无论何时调用相应的HttpServletRequest或HttpSession方法调用,Shiro都会将这些调用委派给其内部的本地Session API。 最终结果是,即使您使用Shiro的“本地”企业会话管理,也不必更改Web代码-确实是非常方便(且必不可少)的功能。

附加功能

Apache Shiro框架中还有其他对保护Java应用程序有用的功能,例如:

  • 线程和并发支持,用于跨线程维护主题(Executor和ExecutorService支持)
  • 可调用和可运行支持将逻辑作为特定主题执行
  • “运行方式”支持,用于假设另一个主题的身份(例如,在管理应用程序中很有用)
  • 测试工具支持,使在单元测试和集成测试中对Shiro安全代码进行全面测试变得非常容易

框架局限性

尽我们所能,Apache Shiro并不是“银弹”-它不会轻松解决所有安全问题。 Shiro无法解决的某些事情可能值得了解:

  • 虚拟机级别的问题 :Apache Shiro当前不处理虚拟机级别的安全性,例如基于访问控制策略阻止某些类加载到类加载器中的能力。 但是,Shiro可以与现有的JVM安全操作集成在一起并不是不可想象的-只是没有人为该项目做出过这样的贡献。
  • 多阶段身份验证 :Shiro当前不支持“多阶段”身份验证,在这种身份验证中,用户可能通过一种机制登录,只是要求用户然后使用另一种机制再次登录。 这已在基于Shiro的应用程序中完成,但是该应用程序会先收集所有必需的信息,然后与Shiro进行交互。 将来的Shiro版本中很可能会支持此功能。
  • 领域写入操作 :当前,所有Realm实现都支持“读取”操作,以获取身份验证和授权数据以执行登录和访问控制。 不支持“写入”操作,例如创建用户帐户,组和角色,或将用户与角色组和权限相关联。 这是因为支持这些操作的数据模型在应用程序之间差异很大,并且很难在所有Shiro用户上强制执行“写入” API。

即将推出的功能

Apache Shiro的社区每天都在继续增长,并且随着它的增长,Shiro的功能也在不断增长。 在即将发布的版本中,您可能会看到:

  • 更干净的Web筛选器机制,无需子类即可提供更多可插入的筛选支持。
  • 更多可插拔的默认Realm实现,更倾向于组合而不是继承。 您将能够插入用于查找身份验证和授权数据的组件,而无需要求将Shiro Realm实现子类化
  • 强大的OpenIDOAuth (可能还有混合)客户端支持
  • 验证码支持
  • 100%无状态应用程序(例如,许多REST环境)的配置更容易。
  • 通过请求/响应协议的多阶段身份验证。
  • 通过AuthorizationRequest进行粗粒度的授权。
  • 用于安全性断言查询的ANTLR语法(例如('role(admin)&&(guest ||!group(developer))')

摘要

Apache Shiro是功能齐全,健壮且通用的Java安全框架,可用于保护应用程序安全。 通过简化应用程序安全性的四个领域,即身份验证,授权,会话管理和密码学,可以更轻松地在实际应用程序中理解和实现应用程序安全性。 Shiro的简单体系结构和JavaBeans兼容性使它几乎可以在任何环境中进行配置和使用。 Additional web support and auxiliary features like multithreading and test support round out the framework to provide what could be your 'one stop shop' for application security. Apache Shiro's development team continues to move forward, refining the codebase and supporting the community. With continued open-source and commercial adoption, Shiro is only expected to grow stronger.

资源资源

关于作者

Les Hazlewood is the Apache Shiro PMC Chair and co-founder and CTO of Katasoft , a start-up focusing on application security products and Apache Shiro professional support. Les has 10 years of experience as a professional Java developer and enterprise architect, with previous senior roles at Bloomberg, Delta Airlines, and JBoss. Les has been actively involved in Open Source development for more than 9 years, committing or contributing to projects like the Spring Framework, Hibernate, JBoss, OpenSpaces, and of course JSecurity, Apache Shiro's predecessor. Les currently lives in San Mateo, CA and practices Kendo and studies Japanese when he is not programming.

Update on using Apache Shiro

Pairing Apache Shiro and Java EE 7 - Learn how to use Shiro in a JavaEE7 application and how to use it in a web application.

翻译自: https://www.infoq.com/articles/apache-shiro/?topicPageSponsorship=c1246725-b0a7-43a6-9ef9-68102c8d48e1

apache shiro

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值