Shiro十分钟教程
原文:10 Minute Tutorial on Apache Shiro
介绍
欢迎来到Apache Shiro的十分钟教程!
通过这个快速且简单的教程,你将完全理解一个开发者应该如何在它们的项目中使用Shiro。你应该能在10分钟之内完成!
概览
什么是Apache Shiro
Apache Shiro是一个强大、易于使用的Java安全框架,它提供一个直观而全面的的用于认证、授权、加密和会话管理的解决方案。
实际上,它可以管理你应用安全的方方面面,同时尽可能的不碍事。它在接口驱动设计和面向对象原则上设计,使得您可以在任何您想的地方定制行为。具有合理的默认设置,我们就可以对应用的安全放手不管了,至少,这是我们努力的方向。
Apache Shiro能做什么
非常多!但我们不想将它们塞到这个十分钟的QuickStart中,如果你想看看它能为你做什么,去看Features页面。当然,如果你好奇我们是为什么存在的,可以看看[Shiro History and Mission]页面。
好,现在,让我们做点啥吧!
注意:Shiro可以运行在任意的环境中,从最基本的命令行程序到最大的企业级web和集群应用。但是,我们将使用尽可能简单的例子。我们会为这个QuickStart使用只有一个
main
方法的示例,以至于你可以对API有一些感觉。
下载
- 确保你具有JDK1.8 + 和 Maven 3.0.3 +
- 从下载页面下载最近的“源代码发布”,在这个例子中,我们将使用1.9.0发行版。
- 解压源码包
unzip shiro-root-1.9.0-source-release.zip
- 进入quickstart目录
cd shiro-root-1.9.0/samples/quickstart
- 运行QuickStart
mvn compile exec:java
这个目标将仅仅打印一些日志信息让你知道现在正在做什么,然后便退出。当你在阅读此QuickStart时,请随时查看samples/quickstart/src/main/java/Quickstart.java
中的代码,如果你想的话,请修改那个文件并且运行上面的mvn compile exec:java
。
QuickStart.java
上面引用到的QuickStart.java
文件中包含可以让你熟悉API的所有代码,现在,让我们将它分解成块,你很容易就能理解发生了什么。
在几乎所有环境中,你可以通过下面的调用来获得当前正在执行的用户:
Subject currentUser = SecurityUtils.getSubject();
使用SecurityUtils.getSubject()
,我们可以获取当前正在执行的Subject
。一个Subject
仅仅是一个应用用户的安全相关视图(security-specific view)。我们实际上也想要称它为User
,因为意义就于此,但是我们决定违反这一点:太多应用现存的API中已经有一个它们自己的User
类或框架,而且我们不想与之冲突。而且,在安全的世界里,术语Subject
实际上也是一个公认的命名法。好的,继续。
独立应用程序中的getSubject
调用可以从应用程序指定的位置的用户数据来返回一个Subject
对象,并且在服务器环境中(比如webapp),它可能基于与当前线程或到达请求相关联的用户数据来返回这个Subject
。
现在,你有了一个Subject
,你可以用它来做什么?
如果你想要通过用户的当前的应用绘画来让一些东西变得对用户可见,你可以获取它们的session
:
Session session = currentUser.getSession();
session.setAttribute( "someKey", "aValue" );
Session
是Shiro
特定的实例,它提供了常规HttpSession
的大部分用法,同时有一些额外的好处。一个大大的不同是:它并不需要一个HTTP环境。
如果你在一个web
应用中部署,默认情况下,Session
将是基于HttpSession
的。但,如果你在一个非web环境下,就像这个简单的QuickStart,Shiro默认将使用他自己的企业级Session管理。这意味着无论你部署的环境如何,都可以在任何的应用程序中使用相同的API。这为应用程序打开了一个新世界,任何需要session的应用程序从此不再被强迫使用HttpSession
或EJB有状态Session Beans。并且,任何客户端技术现在可以共享session数据。
所以,现在你可以获取一个Subject
和它们的Session
。那么,一些真正有用的事儿怎么做?比如检查它们是否被允许做某些事,比如检查角色或权限?
我们可以对一个已知的用户做这些检查。我们的Subject
实例代表当前的用户,但是谁是当前的用户?emm...它们是匿名的,直到它们至少登陆一次。所以,让我们试试:
if ( !currentUser.isAuthenticated() ) {
//以gui的方式手机用户的主体和凭证
//比如username/password的html表单,X509整数,OpenID等
//我们使用username和password的例子,因为它极其简单
UsernamePasswordToken token = new UsernamePasswordToken("lonestarr", "vespa");
//这就是你为了实现“记住我”功能要做的所有事(没有配置,已经内置了)
token.setRememberMe(true);
currentUser.login(token);
}
就是这样,不能再简单了。
但是,如果登录尝试失败会怎样?你可以捕获所有告诉你实际上发生了什么的特定异常,并且允许你做相应的反应和处理:
try {
currentUser.login( token );
//如果没有异常,ok!完成!
} catch ( UnknownAccountException uae ) {
//Username不在系统之中,给它们展示一个错误信息
} catch ( IncorrectCredentialsException ice ) {
//password不匹配,再试一次?
} catch ( LockedAccountException lae ) {
//这个用户名被锁定了,无法登录,给他们展示一个错误信息
}
... 如果你愿意,可以捕获更多类型的异常 ...
} catch ( AuthenticationException ae ) {
//未预期的的情况 - error?
}
你可以去检查非常多不同种类的异常,或者抛出Shiro可能没考虑到的自定义异常。更多请查看AuthenticationException JavaDoc。
小提示:安全的一个最佳实践是向用户提供一个泛泛的登录失败消息,因为您不想帮助试图入侵您系统的攻击者。
好的,现在,我们已经有了一个已登录用户,我们还可以做点什么别的吗?
比如,它们是谁?
//打印它们的认证主体(在这个例子中是一个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:wield" ) ) {
log.info("You may use a lightsaber ring. Use it wisely.");
} else {
log.info("Sorry, lightsaber rings are for schwartz masters only.");
}
并且,我们也可以执行一个极度强大的实例级权限检查——一种能够检查用户是否具有访问特定类型的一个实例的能力:
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(); //溢出所有的认证信息,失效它们的session
这就是在应用程序员级别的Apache Shiro的核心用法,虽然在引擎盖下有一些相当复杂的东西来保证它如此优雅的工作,但这真的是Shiro的全部了。
但你也许会问你自己,“在登陆时获取用户数据是谁的责任(如username和password、role和permissions等),并且谁在运行时执行安全检查?”。由你来做这些事,通过实现Shiro中被称作一个Realm的东西,并且将这个Realm插入到Shiro的配置中。
然而,如何配置一个Realm
是极大程度上依赖你的运行时环境的。比如,如果你运行一个独立应用程序,或你有一个基于web的应用,或者是一个基于Spring或JEE容器的应用,或者由这些组合起来。这些类型的配置已经超出了这篇QuickStart的范围,因为它的目标是让你适应API和Shiro的概念。
当你准备好获取更多信息是,你可能想要阅读Authentication Guide和Authorization Guide。你可以移步到其它文档,特别是参考手册。对于一些其它问题,你可能还想加入我们的mailling list——你会发现我们有一个很棒的社区,这里的人们愿意尽可能的提供帮助。
感谢,希望你享受使用Apache Shiro!