創建測試工程
加入shiro-core的jar包及其依賴包
與其它java開源框架類似,將shiro的jar包加入項目就可以使用shiro提供的功能了。shiro-core是核心包必須選用,還提供了與web整合的shiro-web、與spring整合的shiro-spring、與任務調度quartz整合的shiro-quartz等,下邊是shiro各jar包的maven坐標。

<dependency> <groupId>org.apache.shiro</groupId> <artifactId>shiro-core</artifactId> <version>1.3.2</version> </dependency> <dependency> <groupId>org.apache.shiro</groupId> <artifactId>shiro-web</artifactId> <version>1.3.2</version> </dependency> <dependency> <groupId>org.apache.shiro</groupId> <artifactId>shiro-spring</artifactId> <version>1.3.2</version> </dependency> <dependency> <groupId>org.apache.shiro</groupId> <artifactId>shiro-ehcache</artifactId> <version>1.3.2</version> </dependency> <dependency> <groupId>org.apache.shiro</groupId> <artifactId>shiro-quartz</artifactId> <version>1.3.2</version> </dependency> 也可以通過引入shiro-all包括shiro所有的包: <dependency> <groupId>org.apache.shiro</groupId> <artifactId>shiro-all</artifactId> <version>1.3.2</version> </dependency>
創建工程目錄
shiro.ini
通過Shiro.ini配置文件初始化SecurityManager環境。
配置 eclipse支持ini文件編輯:
在eclipse配置后,在classpath創建shiro-realm.ini配置文件,為了方便測試將用戶名和密碼配置的shiro.ini配置文件中:
[users]
zhang=111111
認證代碼
public class TestAhentication { @Test public void testLoginAndLogout() { // 構建SecurityManager工廠,IniSecurityManagerFactory可以從ini文件中初始化SecurityManager環境 Factory<SecurityManager> factory = new IniSecurityManagerFactory("classpath:shiro-realm.ini"); // 通過工廠創建SecurityManager SecurityManager securityManager = factory.getInstance(); // 將securityManager設置到運行環境中 SecurityUtils.setSecurityManager(securityManager); // 創建一個Subject實例,該實例認證要使用上邊創建的securityManager進行 Subject subject = SecurityUtils.getSubject(); // AuthenticationToken arg0 UsernamePasswordToken token = new UsernamePasswordToken("zhang","111111"); try { subject.login(token); } catch (AuthenticationException e) { // TODO Auto-generated catch block e.printStackTrace(); } // 用戶認證狀態 boolean isAuthenticated = subject.isAuthenticated(); System.out.println("用戶登錄認證結果:"+isAuthenticated); //密碼錯誤異常 org.apache.shiro.authc.IncorrectCredentialsException //賬號錯誤異常 org.apache.shiro.authc.UnknownAccountException subject.logout(); System.out.println("用戶退出認證結果"+subject.isAuthenticated()); } }
常見的異常
UnknownAccountException
賬號不存在異常如下:
org.apache.shiro.authc.UnknownAccountException: Realm [org.apache.shiro.realm.text.IniRealm@7c75222b] was unable to find account data for the submitted AuthenticationToken [org.apache.shiro.authc.UsernamePasswordToken - zhang, rememberMe=false].
IncorrectCredentialsException
當輸入密碼錯誤會拋此異常,如下:
org.apache.shiro.authc.IncorrectCredentialsException: Submitted credentials for token [org.apache.shiro.authc.UsernamePasswordToken - zhang, rememberMe=false] did not match the expected credentials.
更多異常
認證執行流程
1、 創建token令牌,token中有用戶提交的認證信息即賬號和密碼
2、 執行subject.login(token),提交給securityManager (安全管理器),安全管理器在通過Authenticator進行認證,
3、 Authenticator 安排ModularRealmAuthenticator調用realm從ini配置文件取用戶真實的賬號和密碼,這里使用的是IniRealm(shiro自帶)
4、 IniRealm先根據token中的賬號去ini中找該賬號,如果找不到則給ModularRealmAuthenticator返回null,如果找到則匹配密碼,匹配密碼成功則認證通過。
通過token獲取user的過程
密碼匹配的過程源碼
自定義Realm實現通過數據庫查詢數據
上邊的程序使用的是Shiro自帶的IniRealm,IniRealm從ini配置文件中讀取用戶的信息,大部分情況下需要從系統的數據庫中讀取用戶信息,所以需要自定義realm。
shiro提供的realm
最基礎的是Realm接口,CachingRealm負責緩存處理,AuthenticationRealm負責認證,AuthorizingRealm負責授權,通常自定義的realm繼承AuthorizingRealm。
創建自定義realm類
public class CustomRealm extends AuthorizingRealm
public class CustomRealm extends AuthorizingRealm{ public void setName() { super.setName("customRealm"); } @Override protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token){ //獲取認證憑證 UsernamePasswordToken upToken = (UsernamePasswordToken) token; String username = upToken.getUsername(); if (username == null) { throw new AuthenticationException("賬號為空"); } //進行數據庫查詢賬號信息 //模擬數據庫查詢信息 if (!username.equals("zhangsan1")) { return null; } //用戶存在 獲取到數據庫的密碼 返回出去 //假設密碼是1111 String password = "1111"; SimpleAuthenticationInfo info = new SimpleAuthenticationInfo(username, password, getName()); return info; } @Override protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) { // TODO Auto-generated method stub return null; } }
shiro-customRealm.ini
[main] #自定義 realm customRealm=com.td.shiro.realm.CustomRealm #將realm設置到securityManager securityManager.realms=$customRealm
進行測試
@Test public void testLoginAndLogout1() { // 構建SecurityManager工廠,IniSecurityManagerFactory可以從ini文件中初始化SecurityManager環境 Factory<SecurityManager> factory = new IniSecurityManagerFactory("classpath:shiro-customRealm.ini"); // 通過工廠創建SecurityManager SecurityManager securityManager = factory.getInstance(); // 將securityManager設置到運行環境中 SecurityUtils.setSecurityManager(securityManager); // 創建一個Subject實例,該實例認證要使用上邊創建的securityManager進行 Subject subject = SecurityUtils.getSubject(); // AuthenticationToken arg0 UsernamePasswordToken token = new UsernamePasswordToken("zhangsan","1111"); try { subject.login(token); } catch (AuthenticationException e) { e.printStackTrace(); } // 用戶認證狀態 boolean isAuthenticated = subject.isAuthenticated(); System.out.println("用戶登錄認證結果:"+isAuthenticated); //密碼錯誤異常 org.apache.shiro.authc.IncorrectCredentialsException //賬號錯誤異常 org.apache.shiro.authc.UnknownAccountException subject.logout(); System.out.println("用戶退出認證結果"+subject.isAuthenticated()); }