使用 Apache Shiro 的 Java 身份验证指南

身份验证是身份验证的过程-您试图证明用户就是他们所说的真实身份。为此,用户需要提供系统可以理解和信任的某种身份证明。

本指南的目标是引导您了解如何在 Shiro 中执行 Java 身份验证。如果您还没有,请花些时间阅读 Shiro 的10 分钟教程,以便对如何使用 Shiro 有了基本的了解。

您需要的术语

  • 主题 -应用程序用户的特定于安全性的用户“视图”。它可以是人,第三方进程,连接到您的应用程序的服务器,甚至是 cron 作业。基本上,它是与您的应用程序通信的任何东西。

  • 校长 -识别属性的主题。名,姓,社会保险号,用户名

  • 凭据 -用于验证身份的 Secret 数据。密码,bioFeature 数据,x509 证书,

  • 领域 -特定于安全性的 DAO,数据访问对象,与后端数据源对话的软件组件。如果您在 LDAP 中具有用户名和密码,那么您将拥有一个与 LDAP 通信的 LDAP 域。这个想法是,您将为每个后端数据源使用一个领域,而 Shiro 会知道如何与这些领域一起协调以完成您必须做的事情。

如何使用 Shiro 在 Java 中进行身份验证

在 Shiro 的框架以及与此相关的大多数其他框架中,Java 身份验证过程可以分为三个不同的步骤。

Steps

  • 收集受试者的校长和证书

  • 将主体和凭据提交到身份验证系统。

  • 允许访问,重试身份验证或阻止访问

这是一些有关如何在 Shiro 中进行此操作的代码。

步骤 1-收集主题的负责人和证书

//Example using most common scenario: 
//String username and password.  Acquire in 
//system-specific manner (HTTP request, GUI, etc)
UsernamePasswordToken token = new UsernamePasswordToken( username, password );

//"Remember Me" built-in, just do this: 
token.setRememberMe(true);

在这种情况下,我们使用的是名为UsernamePasswordToken的类。它是框架中最常用的身份验证令牌。

我们使用此令牌来 Binding 以某种方式在 Java 应用程序中获取的用户名和密码。可能是通过用户 Web 表单,HTTPHeaders 或命令行提交的。在 Shiro 中,如何获取它们并不重要-它与协议无关。

在此示例中,我们决定希望应用程序在用户返回时记住他们。因此,一旦创建了令牌,我们就可以通过在令牌上将 Shiro 设置为 true 来使用 Shiro 内置的“记住我”功能。这是使用令牌的setRememberMe()方法完成的

步骤 2-将主体和凭据提交到身份验证系统。

因此,我们以令牌的形式收集了信息,并将其设置为记住回头用户。身份验证过程中的下一步是将令牌提交给身份验证系统。在 Shiro 中,您的身份验证系统由特定于安全的 DAO(称为Realms)表示。有关领域的更多信息,请查看Shiro 境界指南

在 Shiro 中,我们尝试使这一部分尽可能人性化快速简便。我们将其简化为一行 Java 代码!

//With most of Shiro, you'll always want to make sure you're working with the currently 
//executing user, referred to as the subject 
Subject currentUser = SecurityUtils.getSubject();

//Authenticate the subject by passing 
//the user name and password token 
//into the login method 
currentUser.login(token);

首先,我们需要获取当前正在执行的用户,称为主题。主题只是用户的安全特定视图-它可以是人员,流程,日常任务,都没有关系。在 Shiro 中,始终有一个主题实例可用于当前正在执行的线程。主题的概念是 Shiro 的核心,并且大多数框架都围绕着与主题合作。在此示例中,我们将将此主题命名为 currentUser。

要获取该主题,我们使用SecurityUtils类,它也是 Shiro API 的核心部分。它将通过getsubject()方法调用获取当前执行的用户。然后,我们返回一个主题实例,该实例表示当前用户是谁,谁正在与系统交互。在示例中,此时,主题 currentUser 是匿名的。没有与他们相关联的身份。

现在,有了用户表示形式,我们只需调用login())方法对它们进行身份验证,然后提交我们刚刚构建的令牌。

步骤 3-允许访问,重试身份验证或阻止访问

同样,非常简单的单方法调用。如果login()方法调用成功,则该用户已登录并与用户帐户或身份相关联。从这里开始,由于我们在示例中设置了“记住我”,因此用户可以 continue 使用您的应用程序并保留他们的身份,甚至可以保留整个会话的时间。

但是,如果身份验证尝试失败了怎么办?如果他们给您 Importing 了错误的密码,或者他们访问了系统太多次,也许他们的帐户已被锁定怎么办?在这种情况下,Shiro 将引发异常。这就是 Shiro 丰富的异常层次结构发挥作用的地方。

try {
    currentUser.login(token);
} catch  ( UnknownAccountException uae ) { ...
} catch  ( IncorrectCredentialsException ice ) { ...
} catch  ( LockedAccountException lae ) { ...
} catch  ( ExcessiveAttemptsException eae ) { ...
} ...  your own ...
} catch ( AuthenticationException ae ) {
    //unexpected error?
}
//No problems, show authenticated view…

您可以采用该方法调用并将其包装在 try/catch 块中,并且如果要处理它们并做出相应的反应,则可以捕获各种异常。除了 Shiro 提供的一系列丰富的 exception,如果需要自定义功能,则可以创建自己的 exception。有关更多信息,请遵循AuthenticationException上的此链接文档。

Security Tip

安全最佳实践是将通用的登录失败消息发送给用户,因为您不想帮助攻击者尝试闯入您的系统。

“记住我”支持

如上例所示,除了常规的登录过程之外,Shiro 还支持“记住我”的概念。

在 Shiro 中,Subject 对象支持两种方法:isRemembered()isAuthenticated()

“记住的”主题具有身份(不是匿名的),并且其识别属性(称为主体)在上一个会话期间的成功身份验证中会被记住。

经过身份验证的主题在当前会话中证明了自己的身份。

Warning

如果某个主题被记住,并不意味着它们已通过认证。

记住与已认证

在四郎中,重要的是要注意,记住的主题不是经过验证的主题。对isAuthenticated()进行检查是更为严格的检查,因为身份验证是证明您是您所说的身份的过程。当仅记住用户时,记住的身份使系统知道该用户可能是谁,但实际上,它无法绝对保证所记住的主题是否代表当前正在使用该应用程序的用户。主题通过身份验证后,就不再认为它们仅被记住,因为它们的身份在当前会话中已经过验证。

因此,尽管应用程序的许 Multipart 仍可以基于记住的原则(例如自定义视图)执行特定于用户的逻辑,但是在用户通过执行成功的身份验证尝试合法地验证其身份之前,它永远不应执行高度敏感的操作。

例如,检查对象是否可以访问财务信息的检查应几乎始终取决于isAuthenticated()而不是isRemembered(),以确保身份经过验证。

这是一个有助于说明为什么 isAuthenticated 和 isRemembered 之间的区别很重要的方案。

假设您正在使用 Amazon.com。您登录并在购物车中添加了一些书。一天过去了。当然,您的用户会话已经过期,并且您已经注销。但是亚马逊“记住”您,用名字问候您,并且仍在为您提供个性化的书本推荐。对于亚马逊,isRemembered()将返回TRUE。如果您尝试使用已归档的信用卡之一或更改您的帐户信息会怎样?尽管亚马逊“记住”您isRemembered() = TRUE,但不确定您实际上是isAuthenticated()=FALSE。因此,在执行敏感操作之前,亚马逊需要通过在登录屏幕上强制执行身份验证过程来验证您的身份。登录后,您的身份已通过isAuthenticated()=TRUE验证。

这种情况经常在网络上发生,因此 Shiro 内置了该功能,可帮助您轻松地自己区分。

Logging Out

最后,当用户使用完应用程序后,他们可以注销。在 Shiro 中,我们只需一个方法调用即可使注销变得快速而轻松。

currentUser.logout(); //removes all identifying information and invalidates their session too.

当您注销 Shiro 时,它将关闭用户会话并从主题实例中删除任何关联的身份。如果您在网络环境中使用 RememberMe,默认情况下.logout()还将从浏览器中删除 RememberMe cookie。

协助处理文档

尽管我们希望该文档对您使用 Apache Shiro 所做的工作有所帮助,但社区一直在不断改进和扩展文档。如果您想为 Shiro 项目提供帮助,请考虑在需要的地方更正,扩展或添加文档。您提供的每一点帮助都会扩大社区,进而改善 Shiro。

提交文档的最简单方法是通过单击下面的Edit链接提交请求请求,然后将其发送到User Forum用户邮件列表