下面講解基于實戰系列一,是以相關的java檔案擷取pom.xml及其log4j檔案同樣适用于本次講解。
一、Using Shiro
Using Shiro 現在我們的 SecurityManager 已經設定好并可以使用了,現在我們能夠開始做一些我們真正關心的事情——執行安 全操作。 當保護我們的應用程式時,我們對自己可能提出的最為相關的問題是“目前使用者是誰”或“目前使用者是否被允許做 XXX”。當我們編寫代碼或設計使用者接口時,問這些問題是很常見的:應用程式通常是基于使用者的背景情況建立的, 且你想基于每個使用者标準展現(保障)功能。是以,對于我們考慮應用程式安全的最自然的方式是基于目前使用者。 Shiro 的 API 使用它的 Subject 概念從根本上代表了“目前使用者”的概念。
幾乎在所有的環境中,你可以通過下面的調用擷取目前正在執行的使用者:
Subject currentUser=SecurityUtils.getSubject();
使用 SecurityUtils.getSubject(),我們可以獲得目前正在執行的 Subject。Subject 是一個安全術語,它基本上的意思是 “目前正在執行的使用者的特定的安全視圖”。它并沒有被稱為"User"是因為"User"一詞通常和人類相關聯。在安全 界,術語"Subject"可以表示為人類,而且可是第三方程序,cron job,daemon account,或其他類似的東西。它僅僅 意味着“該事物目前正與軟體互動”。對于大多數的意圖和目的,你可以把 Subject 看成是 Shiro 的"User"概念。
getSubject()在一個獨立的應用程式中調用,可以傳回一個在應用程式特定位置的基于使用者資料的 Subject,并且在服 務器環境中(例如,Web 應用程式),它擷取的 Subject 是基于關聯了目前線程或傳入請求的使用者資料的。
二、現在你擁有了一個 Subject,你能拿它來做什麼?
如果你想在應用程式的目前會話中使事物對于使用者可用,你可以獲得他們的會話:
Session session = currentUser.getSession();
session.setAttribute("someKey", "aValue");
Session 是一個 Shiro 的特定執行個體,它提供了大部分你經常與 HttpSessoins 使用的東西,除了一些額外的好處以及一 個巨大的差別:它不需要一個 HTTP 環境! 如果在一個 Web 應用程式内部部署,預設的 Session 将會是基于 HttpSession 的。但在一個非 Web 環境中,像這個簡單的教程應用程式,Shiro 将會預設自動地使用它的 Enterprise Session Management。這意味着你會使用相同的 API 在你的應用程式,在任何層,不論部署環境!這開辟了應用程式的新世界,由于任何需要會話的應用程式不必 再被強制使用 HttpSession 或 EJB Stateful Session Beans。并且,任何用戶端技術現在能夠共享會話資料。
三、是以,現在你能擷取一個 Subject 以及他們的 Session。如果他們被允許做某些事,如對角色和權限的檢查,像“檢 查”真正有用的地方在哪呢?
嗯,我們隻能為一個已知的使用者做這些檢查。我們上面的 Subject 執行個體代表了目前使用者,但誰又是目前使用者?呃, 他們是匿名的——也就是說,直到直到他們至少登入一次。那麼,讓我像下面這樣做:
if(!currentUser.isAuthenticated()) {
UsernamePasswordToken token = new UsernamePasswordToken("lonestarr","vespa");
token.setRememberMe(true);
try {
currentUser.login(token);
} catch (UnknownAccountException e) {
// TODO: handle exception
log.info("there is no user with username of"+token.getPrincipal());
}catch (IncorrectCredentialsException e) {
// TODO: handle exception
log.info("Password for account"+token.getPrincipal()+"was incorrect");
}catch (LockedAccountException e) {
// TODO: handle exception
log.info("The account for username"+token.getPrincipal()+"is locked."+"Please contact your adminstrator to unlock it.");
}
}
比方說,
他們是是誰:
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("winnebego: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();
以上代碼完全版如下所示:
import org.apache.log4j.Logger;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.IncorrectCredentialsException;
import org.apache.shiro.authc.LockedAccountException;
import org.apache.shiro.authc.UnknownAccountException;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.config.IniSecurityManagerFactory;
import org.apache.shiro.mgt.SecurityManager;
import org.apache.shiro.session.Session;
import org.apache.shiro.util.Factory;
public class Tutorial {
private static Logger log = Logger.getLogger(Tutorial.class);
public static void main(String[] args) {
log.info("My First Apache Shiro Application");
Factory<SecurityManager> factory = new IniSecurityManagerFactory("classpath:shiro.ini");
SecurityManager securityManager = factory.getInstance();
SecurityUtils.setSecurityManager(securityManager);
org.apache.shiro.subject.Subject currentUser = SecurityUtils.getSubject();
Session session = currentUser.getSession();
session.setAttribute("someKey", "aValue");
String value = (String) session.getAttribute("someKey");
if(value.equals("aValue")) {
log.info("Retrieved the correct value!["+value+"]");
}
if(!currentUser.isAuthenticated()) {
UsernamePasswordToken token = new UsernamePasswordToken("lonestarr","vespa");
token.setRememberMe(true);
try {
currentUser.login(token);
} catch (UnknownAccountException e) {
// TODO: handle exception
log.info("there is no user with username of"+token.getPrincipal());
}catch (IncorrectCredentialsException e) {
// TODO: handle exception
log.info("Password for account"+token.getPrincipal()+"was incorrect");
}catch (LockedAccountException e) {
// TODO: handle exception
log.info("The account for username"+token.getPrincipal()+"is locked."+"Please contact your adminstrator to unlock it.");
}
}
log.info("User["+currentUser.getPrincipal()+"]"+"logged in successfully");
//test a role
if(currentUser.hasRole("schwartz")) {
log.info("May the schwartz be with you!");
}else {
log.info("Hello,mere mortal");
}
if(currentUser.isPermitted("winnebego: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();
System.exit(0);
}
}
以上是完整的示例說明如下:
從建立工廠加載配置檔案shiro.init到建立安全管理器,到擷取目前使用者,到用sesion儲存使用者執行個體。
再到擷取使用者執行個體及其擷取使用者角色及其相應權限