本文翻译自Apache Shiro官方文档,原名:10 Minute Tutorial on Apache Shiro。通过本文学习,你可以自己搭建起简单的项目并引入shiro,通过代码示例了解shiro中的概念和最基本的使用。
Apache Shiro 10分钟教程
介绍
欢迎来到Apache Shiro 10分钟教程
通过学习这个快速简单的教程,你应该可以完全了解开发者如何在他们的程序中使用shiro。我相信你应该可以在10分钟内完成本文档的学习。
概览
什么是Apache Shiro?
Apache Shiro是一个功能强大、易于使用的Java安全框架。它提供给开发者直觉化的,并且功能丰富的认证、授权、加密、session管理的解决方案。
在实际使用中,它可以管理你程序安全相关的各个方面,并且尽量不影响你自己的程序。它基于接口驱动设计并且符合面向对象的规范。你可以在任何想到的地方做客制化开发,同时在任何地方,它还拥有令人信服的默认值。它把程序安全尽量做到让你能放手不管,至少这是我们努力的方向。
Apache Shiro能做什么?
非常多:)但是我们不想让快速上手文档变的过于臃肿。如果你想知道它可以为你做什么,请查看我们的Features页面。如果你好奇我们如何开始的以及为什么我们存在,请看
Shiro History and Mission
页面
Ok,让我们真正动起手来吧!
Note
Shiro 可以运行在任何环境,从最简单的命令行到庞大的企业web应用以及集群程序,但是我们通过在一个简单的main方法中,展示一个简单的例子,让你对API有初步的感觉。
下载
1、确保你的JDK在1.6版本以上,Maven 3.0.3版本以上
2、在下载页下载最新的“Source Code Distribution”。本例中我们使用1.3.2 release发布版。
3、解压缩源代码包:
$ unzip shiro-root-1.3.2-source-release.zip
4、进入quickstart目录:
$
cd
shiro-root-1.3.2/samples/quickstart
5、运行QuickStart:
$ mvn compile
exec
:java
这些操作只是为了打印一些log信息,让你知道运行了什么,然后就退出了。在阅读本篇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是安全视角的系统用户。我们通常称之为user,这也是非常符合常理的,但是我们决定换一种方式:太多系统在已有的API中已经存在他们自己的User classes/frameworks,我们不想造成冲突。同时,在安全领域,Subject是事实上被公认的术语。OK,让我们继续。。。。。。
在一个独立应用中调用getSubject(),可能返回的subject是存在于程序制定位置的用户数据。在服务器环境中(例如web应用),它通过关联到当前线程或者request的用户数据来获取Subject。
现在你有了一个Subject,你可以用它来做什么呢?
如果你想使用户的session,那么你应该先获取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。任何客户端都可以共享session数据。
现在你可以获取subject和它的session了。那么真正有用的东西呢,例如检查用户是否被允许做某些事情,或者检查是否违反了角色和权限。
好吧,我只可以对已知用户进行这些检查。我们的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);}
就像这样!简直不能再简单了!
但是,如果登录操作失败了会怎样?你可以捕获所有指定的exception,它会告诉你发什么了什么,你可以针对性的作出处理:
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?
}
这里有很多不同类型的exception,对于shiro没有涉及到的某些个性化情况,你也可以抛出你自己的异常。更多内容请参考
AuthenticationException JavaDoc
Handy Hint
安全的最佳实践是返回通用的登录失败信息,因为你不想帮助攻击者尝试破坏你的系统。
OK,现在我们已经有了一个登录的用户了。我们还能干点什么其他的事情呢?
让他说出他是谁:
//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."
);
}
我们还可以执行实例层面的权限检查--可以看到这个用户是否能够进入指定类型的实体
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的东西,然后在shiro的配置中插入它。
然而,如何配置Realm很大程度上取决于你的运行环境。例如,如果你运行一个独立的程序,或者是一个基于web的程序,也可能是一个Spring或者基于J2EE容器的应用,还可能是组合的形式。如何去配置超出了本文的范围,因为本文的目标是让你没什么障碍的去了解Shiro API及它的概念。
当你准备好学习更为细节的部分,你一定会想阅读
Authentication Guide
及
Authorization Guide
.然后可以去看其他的
Documentation
,特别是
Reference Manual
, 以回答你任何其他的问题。你可能也许会想加入我们的邮件列表-你将会发现我们有一个伟大的社区,里面的人无论何时都会乐于提供帮助。
感谢你坚持阅读到这里。希望你能享受使用Apache Shiro的过程!