Apache Shiro系列三,概述 —— 10分钟入门
一、介绍
看完这个10分钟入门之后,你就知道如何在你的应用程序中引入和使用Shiro。以后你再在自己的应用程序中使用Shiro,也应该可以在10分钟内搞定。
二、概述
关于Shiro的废话就不多说了,详情可以看本系列第一篇博文:Apache Shiro系列一:初识
答案是很多,但是在这里我们就不展开说了,如果对这个有兴趣,可以去看Shiro的特性。
三、下载
1)确保安装了1.6及其以上版本的JDK,以及3.0.3以上版本的maven;
2)从Download 页面下载最新版本的”Source Code Distribution”,我们下面的例子将使用1.3.2版本;
3)解压;
4)进入到quickstart目录;
$ cd shiro-root-1.3.2/samples/quickstart
5)运行quickstart;
$ mvn compile exec:java
在看本入门文档的过程中,可以打开源文件samples/quickstart/src/main/java/Quickstart.java,并且随意修改以测试你的想法。
四、QuickStart.java
下面我们来分解说明Quickstart.java内的源码以便你可以更好的理解。
在任何环境下你都可以通过如下代码来获取当前登录的用户。
Subject currentUser =SecurityUtils.getSubject();
所谓Subject其实就是其他系统中的User,这里只是换一个说法,因为能够登录系统的不仅仅是人,还有其他系统。
如果是在一个独立的应用程序中调用getSubject(),我们会得到一个应用程序本地登录的用户信息,如果是一个web应用,则会得到一个和当前线程或者当前的session相关的用户。
不管怎么样,现在你得到了一个用户了,接下来可以做什么呢?
如果你想要让某些数据在当前用户登录会话期间内一直有效,则可以像下面这么做:
Session session = currentUser.getSession();
session.setAttribute("someKey","aValue");
我们可以把这个Session当成是HttpSession在Shiro中的特殊实现,他和HttpSession有着相似的接口,大家用起来不会陌生。但是他还有一个额外的好处:不依赖于HTTP的上下文环境。这样你就可以在一个非web应用(比如类似于本例子的命令行程序)中使用Session了。
如果是在一个Web应用程序中使用Session,则返回的Session是一种基于HttpSession的实现;而如果是在一个非web环境下使用,则默认使用的是Enterprise Session。不管怎么样,这意味着我们不用理会应用程序的部署环境,总是使用相同的API来操作session,带来一致的用户体验。现在,web应用和非web应用可以共享session数据了。
到目前为止,我们得到了一个Subject以及他的Session,现在我们用它们来做点有实际意义的事情怎么样,比如检查一下这个用户是否有权限做某件事情?
我们可以为一个已知的用户做这些检查。我们上文中的Subject代表着当前用户,但是截至目前来说,谁是当前用户呢?在真正登录之前,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 =newUsernamePasswordToken("lonestarr","vespa"); //this is all you have to do to support 'remember me' (no config - built in!): token.setRememberMe(true); currentUser.login(token); }
就这样,简单的不能再简单了。
1 try{ 2 currentUser.login( token ); 3 //if no exception, that's it, we're done! 4 }catch(UnknownAccountException uae ){ 5 //username wasn't in the system, show them an error message? 6 }catch(IncorrectCredentialsException ice ){ 7 //password didn't match, try again? 8 }catch(LockedAccountException lae ){ 9 //account for that username is locked - can't login. Show them a message? 10 } 11 ... more types exceptions to check if you want ... 12 }catch(AuthenticationException ae ){ 13 //unexpected condition - error? 14 }
//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.