shiro是一個強大而且易用的安全框架(主要包括認證和授權),它比spring security更加簡單,而且它不依賴於任何容器,可以和許多框架集成。 shiro的核心是安全管理器(SecurityManagement),它主要包括四個模塊: 1.Authentication:認證模塊,主要用於驗證 ...
shiro是一個強大而且易用的安全框架(主要包括認證和授權),它比spring security更加簡單,而且它不依賴於任何容器,可以和許多框架集成。
shiro的核心是安全管理器(SecurityManagement),它主要包括四個模塊:
1.Authentication:認證模塊,主要用於驗證subject的身份和憑證,這裡的subject包括但不僅限於用戶。
2.Authorization:授權模塊,主要用於將用戶在資料庫中對應的角色和許可權查詢出來並緩存起來供用戶後續資源操作的許可權判斷使用;
3.Session management:會話管理器,管理subject請求會話;
4.cryptography:加密,主要是對憑證加密(單向的,這也正是subject忘記密碼了只能創建新密碼的原因)。
shiro還支持web,支持緩存機制,支持併發以及單元測試等等。
因為今天我就學了認證模塊,所以今天先簡單講講認證模塊的實現。
實現步驟如下:
1.創建一個java項目;
2.導入shiro相關的jar包:
commons-beanutils-1.9.3.jar
commons-logging-1.2.jar
jcl-over-slf4j-1.7.12.jar
log4j-1.2.16.jar
shiro-all-1.4.1.jar
slf4j-api-1.7.25.jar
slf4j-log4j12-1.6.4.jar
3.創建shiro的數據文件(這裡用.ini文件來提供模擬資料庫的數據)
4.編寫代碼流程
前兩步我們這裡省略,不會創建項目和導包的請自行百度0 0。
以下是測試用的shiro.ini文件:
[users] zhangsan=11111
其中[users]是subject存儲身份和憑證的目錄,下麵的zhangsan就是身份,而11111則是憑證或者說密碼,這裡我們給出的時具體的數據,但實際應用的數據應該是從資料庫查詢出來的,但我們這邊就先這樣簡單測試。
接下來編寫認證代碼:
package test; import org.apache.shiro.SecurityUtils; import org.apache.shiro.authc.AuthenticationException; import org.apache.shiro.authc.UsernamePasswordToken; import org.apache.shiro.config.IniSecurityManagerFactory; import org.apache.shiro.mgt.SecurityManager; import org.apache.shiro.subject.Subject; import org.apache.shiro.util.Factory; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class TestAuthencation {
//日誌列印 private final static Logger logger = LoggerFactory.getLogger(TestAuthencation.class);
public static void main(String[] args) { //1.創建securityManagement工廠(讀取配置文件) Factory<SecurityManager> factory = new IniSecurityManagerFactory("classpath:shiro.ini");
//2.創建securityManagement實例 SecurityManager securityManager = factory.getInstance();
//3.將securityManagement設置進SecurityUtils中 SecurityUtils.setSecurityManager(securityManager);
//4.通過SecurityUtils獲取subject實例 Subject subject = SecurityUtils.getSubject();
try { //5.根據用戶名和密碼獲取token UsernamePasswordToken token = new UsernamePasswordToken("zhangsan", "1111");
//6.調用subject.login()方法驗證用戶token subject.login(token);
//7.判斷是否驗證登陸成功 if(subject.isAuthenticated()) { System.out.println("登陸成功"); } } catch (AuthenticationException e) { // TODO Auto-generated catch block logger.error("用戶名或者密碼錯誤!"); } } }
從上面代碼可以看到shiro認證的完整流程,其中subject.login(token)這個方法的流程跳轉非常複雜,但是最終在ModularRealmAuthenticator類中調用doAuthenticate(AuthenticationToken)這個方來進行認證,在這個方法中,會判斷當前存在的realm數量,如果只有一個則直接將token與realm中查詢出來的用戶信息進行比對認證,如果是多個realm則通過Authentication Strategy(認證策略,後續學到具體的我會更新)來對token進行認證。當然我們也可以自定義realm,只需要創建一個新的realm類去繼承AuthenticatingRealm或者AuthorizingRealm,然後實現認證和授權的方法即可編寫自己的認證邏輯。
認證環節可能會發生異常,因此需要我們捕獲異常並且列印異常日誌,以便排查錯誤,這裡常見的異常有上述代碼中的AuthenticationException及它下麵的子類異常如UnknowAccountException(用戶名錯誤異常)和IncorrectCredentialsException(用戶憑證錯誤異常)等等,這裡需要註意,針對這些異常,我們需要進行模糊的提示,比如上面代碼中的用戶名或密碼錯誤,而不能說當發生用戶名錯誤異常時直接提示用戶用戶名異常,這樣會讓人明確知道錯誤的時用戶名還是密碼,會給一些不法人員有機可乘,雖然還有登陸嘗試次數過多的異常,但是儘量避免輸出明確的提示!
認證流程總結:
1.首先讀取.ini文件獲取安全管理器的工廠Factory;
2.然後通過工廠來生成SecurityManagement實例;
3.將安全管理器實例設置到SecurityUtils中去;
4.通過SecurityUtils生成Subject;
5.通過UsernamePasswordToken來生成用戶令牌(通過傳入用戶身份和憑證);
6.調用subject.login(token)來對用戶信息進行認證;
6.1.通過subject介面的實現類DelegatingSubject中的login方法,將token交給securityManager進行認證;
6.2.securityManager介面將認證過程交給它的實現類DefaultSecurityManager中,DefaultSecurityManager中的login方法又調用了AuthenticatingSecurityManager中的authenticate方法來進行認證;
6.3.AuthenticatingSecurityManager的authenticate方法中將認證過程交給了authenticator(認證器,終於到了認證器了。。。),最後認證器將這個token交由它的實現類ModularRealmAuthenticator去進行認證,具體是調用ModularRealmAuthenticator中的doAuthenticate(AuthenticationToken)方法來進行認證;
上述這幾步可通過源碼一步一步進行研究= =。
7.通過subject.isAuthenticated()方法來判斷用戶是否驗證成功;
8.需要對驗證部分進行異常捕獲,並列印出合理的提示信息日誌。
以上是今天我所學到的shiro的認證部分,等我學完授權模塊我將會繼續更新分享我的學習所得,大家有什麼補充和分享的歡迎在評論區留言!