10 Apache Shiro 的分钟教程

Share |

Introduction

欢迎使用 Apache Shiro 的 10 分钟教程!

通过快速简单的教程,您应该完全了解开发人员如何在其应用程序中使用 Shiro。而且您应该能够在 10 分钟内完成操作。

Overview

什么是 Apache Shiro?

Apache Shiro 是一个功能强大且易于使用的 Java 安全框架,它为开发人员提供了一种直观,全面的身份验证,授权,加密和会话 Management 解决方案。

实际上,它可以 Management 应用程序安全性的所有方面,同时尽可能避免干扰。它构建在可靠的界面驱动设计和 OO 原理之上,可在您可以想象的任何地方实现自定义行为。但是,对于所有内容都使用合理的默认值,它就像应用程序安全性一样“轻松”。至少那是我们所追求的。

Apache Shiro 可以做什么?

很多 。但是我们不想夸大快速入门。如果您想了解它可以为您做什么,请查看我们的Features页面。另外,如果您对我们的起步方式以及我们为什么存在感到好奇,请参阅四郎的历史与使命页。

好。现在让我们实际做些事情!

Note

Shiro 可以在任何环境中运行,从最简单的命令行应用程序到最大的企业 Web 和群集应用程序,但是对于此 QuickStart,我们将在简单的``方法中使用最简单的示例,以便您对 API。

Download

  • 确保已安装 JDK 1.6 和 Maven 3.0.3.

  • Download页下载最新的“源代码分发”。在此示例中,我们使用 1.5.3 版本分发。

解压源码包:

$ unzip shiro-root-1.5.3-source-release.zip
  • Importing 快速入门目录:
$ cd shiro-root-1.5.3/samples/quickstart
  • 运行快速入门:
$ mvn compile exec:java

该目标只会打印一些日志消息,让您知道发生了什么,然后退出。阅读此快速入门时,请随时查看samples/quickstart/src/main/java/Quickstart.java下的代码。更改该文件,并根据需要多次运行上面的mvn compile exec:java命令。

Quickstart.java

上面引用的Quickstart.java文件包含使您熟悉 API 的所有代码。现在让我们在这里将其分解成块,以便您可以轻松了解发生了什么。

在几乎所有环境中,都可以通过以下调用获取当前执行的用户:

Subject currentUser = SecurityUtils.getSubject();

使用SecurityUtilsgetSubject(),我们可以获得当前正在执行的Subject。 * Subject *只是应用程序用户的特定于安全性的“视图”。我们实际上想将其称为“用户”,因为那“很合理”,但我们决定反对:太多的应用程序具有已经具有自己的用户类/框架的现有 API,并且我们不想与它们发生冲突。同样,在安全领域中,术语Subject实际上是公认的术语。好吧,continue...

独立应用程序中的getSubject()调用可能会基于特定于应用程序位置的用户数据返回Subject,而在服务器环境(例如 Web 应用程序)中,它会基于与当前线程或传入请求相关联的用户数据获取Subject

现在您有了Subject,该怎么办?

如果要在用户与应用程序的当前会话期间使事情可用,则可以获取他们的会话:

Session session = currentUser.getSession();
session.setAttribute( "someKey", "aValue" );

Session是 Shiro 特定的实例,它提供了常规 HttpSession 所使用的大部分功能,但具有一些额外的好处,并且有一个“很大的”区别:它不需要 HTTP 环境!

如果部署在 Web 应用程序中,则默认情况下Session将基于HttpSession。但是,在非 Web 环境中,例如简单的快速入门,Shiro 将默认自动使用其企业会话 Management。这意味着无论部署环境如何,您都可以在任何层的应用程序中使用相同的 API。这为应用程序打开了一个全新的世界,因为不需要强制要求会话的任何应用程序使用HttpSession或 EJB 状态会话 Bean。而且,任何 Client 端技术现在都可以共享会话数据。

因此,现在您可以获得Subject和他们的Session。 “true”有用的东西(例如检查是否被允许做事,例如检查角色和权限)呢?

好吧,我们只能对已知用户进行检查。上面的Subject实例代表当前用户,但是是当前用户?好吧,他们是匿名的-也就是说,直到他们至少登录一次。因此,让我们这样做:

if ( !currentUser.isAuthenticated() ) {
    //collect user principals and credentials in a gui specific manner
    //such as username/password html form, X509 certificate, OpenID, etc.
    //We'll use the username/password example here since it is the most common.
    //(do you know what movie this is from? ;)
    UsernamePasswordToken token = new UsernamePasswordToken("lonestarr", "vespa");
    //this is all you have to do to support 'remember me' (no config - built in!):
    token.setRememberMe(true);
    currentUser.login(token);
}

而已!再简单不过了。

但是,如果他们的登录尝试失败了怎么办?您可以捕获各种特定的异常,这些异常可以准确地告诉您发生了什么,并允许您进行相应的处理和响应:

try {
    currentUser.login( token );
    //if no exception, that's it, we're done!
} catch ( UnknownAccountException uae ) {
    //username wasn't in the system, show them an error message?
} catch ( IncorrectCredentialsException ice ) {
    //password didn't match, try again?
} catch ( LockedAccountException lae ) {
    //account for that username is locked - can't login.  Show them a message?
}
    ... more types exceptions to check if you want ...
} catch ( AuthenticationException ae ) {
    //unexpected condition - error?
}

您可以检查许多不同类型的异常,也可以针对自定义条件抛出自己的异常,而 Shiro 可能无法解决。有关详情,请参见AuthenticationException JavaDoc

Handy Hint

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

好的,到目前为止,我们已经有一个登录用户。我们还能做什么?

假设他们是谁:

//print their identifying principal (in this case, a username): 
log.info( "User [" + currentUser.getPrincipal() + "] logged in successfully." );

我们还可以测试一下它们是否具有特定作用:

if ( currentUser.hasRole( "schwartz" ) ) {
    log.info("May the Schwartz be with you!" );
} else {
    log.info( "Hello, mere mortal." );
}

我们还可以查看他们是否有权对某种类型的实体采取行动:

if ( currentUser.isPermitted( "lightsaber:weild" ) ) {
    log.info("You may use a lightsaber ring.  Use it wisely.");
} else {
    log.info("Sorry, lightsaber rings are for schwartz masters only.");
}

此外,我们可以执行极其强大的* instance-level *权限检查-能够查看用户是否具有访问类型的特定实例的能力:

if ( currentUser.isPermitted( "winnebago:drive:eagle5" ) ) {
    log.info("You are permitted to 'drive' the 'winnebago' with license plate (id) 'eagle5'.  " +
                "Here are the keys - have fun!");
} else {
    log.info("Sorry, you aren't allowed to drive the 'eagle5' winnebago!");
}

小菜一碟吧?

最后,当用户使用完应用程序后,他们可以注销:

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

嗯,这是在应用程序开发人员级别使用 Apache Shiro 的核心。而且尽管有一些相当复杂的东西在引擎盖下进行,以使这项工作如此优雅,但实际上仅此而已。

但是您可能会问自己:“但是,谁负责在登录期间获取用户数据(用户名和密码,角色和权限等),以及谁在运行时实际执行那些安全检查?”好的,您可以实现 Shiro 所谓的Realm并将Realm插入 Shiro 的配置中。

但是,如何配置Realm很大程度上取决于您的运行时环境。例如,如果您运行一个独立的应用程序,或者您有一个基于 Web 的应用程序,或者一个基于 Spring 或 JEE 容器的应用程序,或者它们的组合。这种配置类型不在本“快速入门”的范围之内,因为它的目的是使您熟悉 API 和 Shiro 的概念。

当您准备好详细了解一下时,您肯定会想要阅读Authentication GuideAuthorization Guide。然后可以移至其他Documentation,特别是Reference Manual,以回答任何其他问题。您可能还想加入mailing list用户-您会发现我们有一个很棒的社区,其中的人们愿意在可能的情况下提供帮助。

感谢您的关注。我们希望您喜欢使用 Apache Shiro!