Apache shiro 学习(一)-----shiro 入门(官网)

一、特点
简单 Java 安全
二、简介
Apache Shiro(发音为“shee-roh”,日语中的’castle’)是一个功能强大且易于使用的Java安全框架,可执行身份验证,授权,加密和会话管理,并可用于保护任何应用程序 - 从命令行应用程序,移动应用程序到最大的Web和企业应用程序。
Shiro提供了应用程序安全API来执行以下方面(我喜欢将这些称为应用程序安全性的4个基石):
身份验证 - 证明用户身份,通常称为用户“登录”。
授权 - 访问控制
密码学 - 保护或隐藏窥探数据的数据
会话管理 - 每用户时间敏感状态
Shiro还支持一些辅助功能,例如Web应用程序安全性,单元测试和多线程支持,但这些有助于强化上述四个主要问题。
三、主要功能介绍

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

收集用户的标识信息,称为主体,并支持身份证明,称为凭证。
将主体和凭据提交给系统。
如果提交的凭据与系统对该用户标识(主体)的期望值匹配,则认为该用户已通过身份验证。如果它们不匹配,则不会将用户视为已通过身份验证。
每个人都熟悉的这个过程的一个常见例子是用户名/密码组合。当大多数用户登录软件应用程序时,他们通常会提供用户名(主体)和支持密码(凭证)。如果存储在系统中的密码(或其表示)与用户指定的密码匹配,则认为它们已经过身份验证。

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

清单5.主题登录

// 1。获取提交的主体和凭证:
AuthenticationToken令牌=
new UsernamePasswordToken(用户名,密码);
// 2。获取当前主题:
主题currentUser = SecurityUtils.getSubject();

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

如您所见,Shiro的API很容易反映出常见的工作流程。您将继续将此简单性视为所有主题操作的主题。调用login方法时,SecurityManager将接收AuthenticationToken并将其分派给一个或多个已配置的域,以允许每个域根据需要执行身份验证检查。每个Realm都能够根据需要对提交的AuthenticationTokens做出反应。但是如果登录尝试失败会发生什么?如果用户指定了错误的密码该怎么办?您可以通过对Shiro的运行时AuthenticationException作出反应来处理故障,如清单6所示。

清单6.处理失败的登录

// 3。登录:
尝试{
currentUser.login(令牌);
} catch(IncorrectCredentialsException ice){…
} catch(LockedAccountException lae){…
}

catch(AuthenticationException ae){…
}
您可以选择捕获其中一个AuthenticationException子类并进行具体反应,或者通常处理任何AuthenticationException(例如,向用户显示通用的“不正确的用户名或密码”消息)。根据您的应用要求,您可以选择。

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

2.授权

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

清单7.角色检查

if(subject.hasRole(“administrator”)){
//显示“创建用户”按钮
} else {
//灰色按钮?
}
如您所见,您的应用程序可以根据访问控制检查启用或禁用功能。

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

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

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

清单8.权限检查

if(subject.isPermitted(“user:create”)){
//显示“创建用户”按钮
} else {
//灰色按钮?
}
这样,任何分配了“user:create”权限的角色或用户都可以单击“创建用户”按钮,这些角色和分配甚至可以在运行时更改,为您提供非常灵活的安全模型。

“user:create”字符串是遵循某些解析约定的权限字符串的示例。Shiro通过WildcardPermission开箱即用,支持这种约定。虽然超出了本介绍文章的范围,但您会看到WildcardPermission在创建安全策略时非常灵活,甚至支持实例级访问控制等内容。

清单9.实例级权限检查

if(subject.isPermitted(“user:delete:jsmith”)){
//删除’jsmith’用户
} else {
//不要删除’jsmith’
}
此示例显示,如果需要,您甚至可以控制对非常细粒度的实例级别的访问。如果您愿意,您甚至可以创建自己的权限语法。有关更多信息,请参阅Shiro权限文档。最后,就像身份验证一样,上述调用最终会进入SecurityManager,它将咨询一个或多个Realms以做出访问控制决策。这允许Realm根据需要响应身份验证和授权操作。

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

3.会话管理

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

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

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

清单10.主题的会话

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

清单11.会话方法

Session session = subject.getSession();
session.getAttribute(“key”,someValue);
Date start = session.getStartTimestamp();
日期时间戳= session.getLastAccessTime();
session.setTimeout(米利斯);

4.加密
密码学是隐藏或混淆数据的过程,因此窥探眼睛无法理解它。Shiro在加密方面的目标是简化并使JDK的加密支持变得可用。

重要的是要注意密码学一般不是特定于受试者,因此它是Shiro API的一个非特定主题的区域。您可以在任何地方使用Shiro的加密支持,即使没有使用主题。Shiro真正关注其加密支持的两个领域是加密哈希(也称为消息摘要)和加密密码。让我们更详细地看一下这两个。

哈希
如果您使用过JDK的MessageDigest类,您很快就会意识到使用它有点麻烦。它有一个笨拙的静态方法基于工厂的API而不是面向对象的API,你被迫捕获可能永远不需要捕获的已检查异常。如果您需要十六进制编码或Base64编码消息摘要输出,您可以自己 - 没有标准的JDK支持。Shiro使用简洁直观的散列API解决了这些问题。

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

如果没有 Shiro,您可以尝试这样做:

将文件转换为字节数组。JDK中没有任何内容可以帮助解决这个问题,因此您需要创建一个帮助方法来打开FileInputStream,使用字节缓冲区,并抛出相应的IOExceptions等。
使用MessageDigest类来散列字节数组,处理相应的异常,如下面的清单12所示。
将散列字节数组编码为十六进制字符。JDK中没有任何东西可以帮助解决这个问题,因此您需要创建另一个辅助方法,并且可能在实现中使用按位运算和位移。
清单12. JDK的MessageDigest

尝试{
MessageDigest md = MessageDigest.getInstance(“MD5”);
md.digest(字节);
byte [] hashed = md.digest();
} catch(NoSuchAlgorithmException e){
e.printStackTrace();
}
这对于如此简单和相对常见的事情来说是一项重要的工作。现在,这里是如何与 Shiro 完全相同的事情。

String hex = new Md5Hash(myFile).toHex();
当您使用Shiro简化所有工作时,它会变得非常简单和容易理解。SHA-512哈希和密码的Base64编码同样简单。

String encodedPassword =
新的Sha512Hash(密码,盐,计数).toBase64();
您可以看到Shiro简化了散列和编码的程度,在此过程中为您节省了一些理智。

密码
密码是加密算法,可以使用密钥可逆地转换数据。我们使用它们来保证数据安全,特别是在传输或存储数据时,数据特别容易被窥探的时候。

如果你曾经使用过JDK Cryptography API,特别是javax.crypto.Cipher类,你知道它可能是一个非常复杂的野兽驯服。对于初学者,每个可能的密码配置总是由javax.crypto.Cipher的实例表示。需要做公钥/私钥加密吗?您使用密码。需要使用Block Cipher进行流媒体操作吗?您使用密码。需要创建AES 256位密码来保护数据?您使用密码。你明白了。

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

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

清单13. Apache Shiro的加密API

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

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

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

您可以直接实例化CipherService - 没有奇怪或令人困惑的工厂方法。
密码配置选项表示为兼容JavaBeans的getter和setter - 没有奇怪且难以理解的“转换字符串”。
加密和解密在单个方法调用中执行。
没有强制检查异常。如果你愿意,可以抓住Shiro的CryptoException。
Shiro的CipherService API还有其他好处,例如支持基于字节数组的加密/解密(称为“块”操作)以及基于流的加密/解密(例如,加密音频或视频)的能力。

Java密码学不需要痛苦。Shiro的加密支持旨在简化您保护数据安全的工作。
5.网络支持
密码学是隐藏或混淆数据的过程,因此窥探眼睛无法理解它。Shiro在加密方面的目标是简化并使JDK的加密支持变得可用。

重要的是要注意密码学一般不是特定于受试者,因此它是Shiro API的一个非特定主题的区域。您可以在任何地方使用Shiro的加密支持,即使没有使用主题。Shiro真正关注其加密支持的两个领域是加密哈希(也称为消息摘要)和加密密码。让我们更详细地看一下这两个。

哈希
如果您使用过JDK的MessageDigest类,您很快就会意识到使用它有点麻烦。它有一个笨拙的静态方法基于工厂的API而不是面向对象的API,你被迫捕获可能永远不需要捕获的已检查异常。如果您需要十六进制编码或Base64编码消息摘要输出,您可以自己 - 没有标准的JDK支持。Shiro使用简洁直观的散列API解决了这些问题。

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

如果没有 Shiro,您可以尝试这样做:

将文件转换为字节数组。JDK中没有任何内容可以帮助解决这个问题,因此您需要创建一个帮助方法来打开FileInputStream,使用字节缓冲区,并抛出相应的IOExceptions等。
使用MessageDigest类来散列字节数组,处理相应的异常,如下面的清单12所示。
将散列字节数组编码为十六进制字符。JDK中没有任何东西可以帮助解决这个问题,因此您需要创建另一个辅助方法,并且可能在实现中使用按位运算和位移。
清单12. JDK的MessageDigest

尝试{
MessageDigest md = MessageDigest.getInstance(“MD5”);
md.digest(字节);
byte [] hashed = md.digest();
} catch(NoSuchAlgorithmException e){
e.printStackTrace();
}
这对于如此简单和相对常见的事情来说是一项重要的工作。现在,这里是如何与 Shiro 完全相同的事情。

String hex = new Md5Hash(myFile).toHex();
当您使用Shiro简化所有工作时,它会变得非常简单和容易理解。SHA-512哈希和密码的Base64编码同样简单。

String encodedPassword =
新的Sha512Hash(密码,盐,计数).toBase64();
您可以看到Shiro简化了散列和编码的程度,在此过程中为您节省了一些理智。

密码
密码是加密算法,可以使用密钥可逆地转换数据。我们使用它们来保证数据安全,特别是在传输或存储数据时,数据特别容易被窥探的时候。

如果你曾经使用过JDK Cryptography API,特别是javax.crypto.Cipher类,你知道它可能是一个非常复杂的野兽驯服。对于初学者,每个可能的密码配置总是由javax.crypto.Cipher的实例表示。需要做公钥/私钥加密吗?您使用密码。需要使用Block Cipher进行流媒体操作吗?您使用密码。需要创建AES 256位密码来保护数据?您使用密码。你明白了。

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

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

清单13. Apache Shiro的加密API

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

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

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

您可以直接实例化CipherService - 没有奇怪或令人困惑的工厂方法。
密码配置选项表示为兼容JavaBeans的getter和setter - 没有奇怪且难以理解的“转换字符串”。
加密和解密在单个方法调用中执行。
没有强制检查异常。如果你愿意,可以抓住Shiro的CryptoException。
Shiro的CipherService API还有其他好处,例如支持基于字节数组的加密/解密(称为“块”操作)以及基于流的加密/解密(例如,加密音频或视频)的能力。

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

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

跨线程维护主题的线程和并发支持(Executor和ExecutorService支持)
Callable和Runnable支持将逻辑作为特定主题执行
“运行为”支持假设另一个主题的身份(例如在管理应用程序中有用)
测试线束支持,使得在单元和集成测试中完全测试Shiro安全代码非常容易

7.框架限制
尽管我们可能会喜欢它,但Apache Shiro并不是一个“银弹” - 它无法毫不费力地解决所有安全问题。Shiro没有提到可能值得了解的事情:

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

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值