創建測試工程

加入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()); }
