Shiro是什麼
Apache提供的Java輕量級安全框架, 相比Spring Security更爲簡單。
作用主要包括: 認證、授權、加密和會話管理。
核心概念:
Subject: 主體
對應應用程序的用戶(User),Shiro爲了避免衝突,從前安全角度起的名字, 實際就是當前登錄的用戶。
SecurityManager-安全管理器
用於管理主體以及權限。
Realms:域
充當Shiro與應用程序的安全數據之間的“橋樑”或“連接器”。也就是Shiro會從應用程序中獲取身份驗證和授權的信息。
簡單點說,就是安全數據源。 應用中至少需要配置一個Relam,可以使用多種方式,比如.ini的文件,JDBC數據庫連接或是LDAP。
SecurityManager的初始化
在Web應用中,通過在web.xml中配置Shiro的Servlet過濾器;
在獨立應用中,可以通過多種配置方式,包括Java代碼、Spring XML,YAML、.properties和.ini文件。
以INI配置爲例:shiro.ini
[users]
oscar = 123456, admin
[roles]
admin = *
[users] 配置靜態的用戶列表, 方便測試
[roles] 配置角色和權限
主體、角色和權限
主體分配角色, 角色分配權限
比如:主體:root, 角色:admin, 權限: *
root用戶擁有admin角色,admin角色擁有所有權限。
在老版本中, SecurityManager通過工廠類的方式初始化,但是現在這種方式已經廢棄了, 不建議使用。
Factory factory = new IniSecurityManagerFactory(“classpath:shiro.ini”);
SecurityManager securityManager = factory.getInstance();
新版本 SecurityManager初始化方法
DefaultSecurityManager securityManager = new DefaultSecurityManager();
IniRealm iniRealm = new IniRealm(“classpath:shiro.ini”);
securityManager.setRealm(iniRealm);
用戶認證(Authentication)
用戶認證是認證該用戶是否是應用的合法用戶。
認證步驟:
- 收集用認證的身份信息, 以用戶名密碼登錄爲例,產生的認證Token如下:
AuthenticationToken token = new UsernamePasswordToken(“oscar”, “123456”);
-
獲取當前主體
Subject currentUser = SecurityUtils.getSubject(); -
使用產生的Token登錄
currentUser.login(token);
該方法可以通過異常捕獲獲取異常信息,比如密碼錯誤等。
授權(Authorization)
認證後的用戶是否對應用的資源、頁面等有權限訪問。Shiro主要通過角色(Role)和權限(Permission)實現。
授權可以判斷該用戶是否具有某個角色,或是該主體對某個類或是實例是否有權限操作, 代碼示例如下:
//4.1 是admin角色
if(currentUser.hasRole("admin")) {
}
//4.2 有創建用戶權限(類層級)
if (currentUser.isPermitted("user:create") ) {
}
//4.3 有刪除oscar這個用戶的權限(實例層級)
if (currentUser.isPermitted("user:delete:oscar") ) {
}
public class ShiroDemo {
public static void main(String[] args) {
//1. 初始化安全管理器SecurityManager
DefaultSecurityManager securityManager = new DefaultSecurityManager();
IniRealm iniRealm = new IniRealm("classpath:shiro.ini");
securityManager.setRealm(iniRealm);
SecurityUtils.setSecurityManager(securityManager);
//2. 獲取主體
Subject currentUser = SecurityUtils.getSubject();
//3.用戶名/密碼驗證
if (!currentUser.isAuthenticated()) {
System.out.println("開始驗證");
UsernamePasswordToken token = new UsernamePasswordToken("oscar", "123456");
token.setRememberMe(true);
try {
currentUser.login(token);
} catch (UnknownAccountException uae) {
System.out.println("用戶不存在:" + token.getPrincipal());
} catch (IncorrectCredentialsException ice) {
System.out.println("密碼錯誤: " + token.getPrincipal() + " ");
} catch (LockedAccountException lae) {
System.out.println("賬號被鎖了");
}
System.out.println("驗證成功");
}
//4. 授權判斷
//4.1 是admin角色
if(currentUser.hasRole("admin")) {
}
//4.2 有創建用戶權限(類層級)
if (currentUser.isPermitted("user:create") ) {
}
//4.3 有刪除oscar這個用戶的權限(實例層級)
if (currentUser.isPermitted("user:delete:oscar") ) {
}
//5.登出
currentUser.logout();
}
}