(1)測試類web
// 用戶登錄和退出,這裏我自定了一個realm(開發確定須要自定義realm獲取數據庫密碼和權限) @Test public void testCustomRealmMd5() { // 建立securityManager工廠,經過ini配置文件建立securityManager工廠 Factory<SecurityManager> factory = new IniSecurityManagerFactory( "classpath:shiro-realm-md5.ini"); // 建立SecurityManager SecurityManager securityManager = factory.getInstance(); // 將securityManager設置當前的運行環境中 SecurityUtils.setSecurityManager(securityManager); // 從SecurityUtils裏邊建立一個subject Subject subject = SecurityUtils.getSubject(); // 在認證提交前準備token(令牌) // 這裏的帳號和密碼 未來是由用戶輸入進去 UsernamePasswordToken token = new UsernamePasswordToken("zhangsan", "111111"); try { // 執行認證提交 subject.login(token); } catch (AuthenticationException e) { e.printStackTrace(); } // 是否定證經過 boolean isAuthenticated = subject.isAuthenticated(); System.out.println("加密後是否定證經過:" + isAuthenticated); // 退出操做 subject.logout(); // 是否定證經過 isAuthenticated = subject.isAuthenticated(); System.out.println("退出後是否定證經過:" + isAuthenticated); }
(2)shiro-realm-md5.ini (有關散列加密下面會舉例子)算法
我在ini配置了加密的規則,這個規則要和用戶註冊保存的密碼加密規則一致。spring
[main] #定義憑證匹配器 credentialsMatcher=org.apache.shiro.authc.credential.HashedCredentialsMatcher #散列算法 credentialsMatcher.hashAlgorithmName=md5 #散列次數 credentialsMatcher.hashIterations=1 #將憑證匹配器設置到realm customRealm=com.jincou.shiro.realm.CustomRealmMd5 customRealm.credentialsMatcher=$credentialsMatcher securityManager.realms=$customRealm
(3)自定義CustomRealmMd5類數據庫
/** *自定義Realm特色 *(1)繼承AuthorizingRealm類 *(2)重寫AuthenticationInfo(認證) * doGetAuthorizationInfo(受權)兩個方法 * 注意: * 1:這裏password = "f3694f162729b7d0254c6e40260bf15c"確定也是經過明文(這裏指zhangsan)+鹽(這裏是qwerty)進行加密後的字符串 * 2:實際應用是將鹽和散列後的值存在數據庫中,自動realm從數據庫取出鹽和加密後的值由shiro完成密碼校驗。 * 3:這裏要注意它們兩的加密規則必定要一致,不然沒法比較。 */ public class CustomRealmMd5 extends AuthorizingRealm { // 設置realm的名稱(任意和其它也無關聯) @Override public void setName(String name) { super.setName("customRealmMd5"); } // 用於認證 @Override protected AuthenticationInfo doGetAuthenticationInfo( AuthenticationToken token) throws AuthenticationException { System.out.println("測試..自定義CustomRealmMd5方法裏面......"); // token是用戶輸入的 // 第一步從token中取出身份信息 String userCode = (String) token.getPrincipal(); // 第二步:根據用戶輸入的userCode從數據庫查詢 // .... //若是數據庫查詢不到zhangsan用戶信息,則返回null /*if(user==null){ return null; }*/ // 模擬從數據庫查詢到密碼,散列值 String password = "f3694f162729b7d0254c6e40260bf15c"; // 從數據庫獲取salt String salt = "qwerty"; //上邊散列值和鹽對應的明文:111111 // 若是查詢到返回認證信息AuthenticationInfo,這裏的密碼加密判斷交給底層處理 SimpleAuthenticationInfo simpleAuthenticationInfo = new SimpleAuthenticationInfo( userCode, password, ByteSource.Util.bytes(salt), this.getName()); return simpleAuthenticationInfo; } // 用於受權(後面寫) @Override protected AuthorizationInfo doGetAuthorizationInfo( PrincipalCollection principals) { return null; } }
運行效果:apache
結論:subject.login(token)我在提交認證,它就會去調用我自定義的CustomRealm,由於我在ini進行配置自定義CustomRealm編程
由於在ini裏面配置的加密規則,那我第一次用戶註冊的時候,確定也須要按它的規則進行加密後,把密碼保存到數據庫ide
/** * 加密算法 */ public class MD5Test { public static void main(String[] args) { //原始 密碼 String source = "111111"; //鹽 String salt = "qwerty"; //散列次數(和ini中credentialsMatcher.hashIterations=1一致) int hashIterations = 1; //上邊散列1次:f3694f162729b7d0254c6e40260bf15c //上邊散列2次:36f2dfa24d0a9fa97276abbe13e596fc //第一個參數:散列算法 //這裏的散列算法是md5要和ini中credentialsMatcher.hashAlgorithmName=md5一致) //第二個參數:明文,原始密碼 //第三個參數:鹽,經過使用隨機數 //第四個參數:散列的次數,好比散列兩次,至關 於md5(md5('')) SimpleHash simpleHash = new SimpleHash("md5", source, salt, hashIterations); System.out.println(simpleHash.toString()); } } //這個結果:f3694f162729b7d0254c6e40260bf15c就是在自定義realm中的密文也就是該用戶保存到數據庫中的密文。
Shiro 支持三種方式的受權:
(1)編程式:經過寫if/else 受權代碼塊完成:測試
Subject subject = SecurityUtils.getSubject(); if(subject.hasRole(「admin」)) { //有權限 } else { //無權限 }
(2)註解式:經過在執行的Java方法上放置相應的註解完成ui
@RequiresRoles("admin") public void hello() { //有權限 }
(3)JSP/GSP 標籤:在JSP/GSP 頁面經過相應的標籤完成this
<shiro:hasRole name="admin"> <!— 有權限—> </shiro:hasRole>
這裏受權測試使用第一種編程方式,實際與web系統集成使用後兩種方式。
(1)測試類
// 自定義realm進行資源受權測試 @Test public void testAuthorizationCustomRealm() { // 建立SecurityManager工廠 Factory<SecurityManager> factory = new IniSecurityManagerFactory( "classpath:shiro-realm.ini"); // 建立SecurityManager SecurityManager securityManager = factory.getInstance(); // 將SecurityManager設置到系統運行環境,和spring後將SecurityManager配置spring容器中,通常單例管理 SecurityUtils.setSecurityManager(securityManager); // 建立subject Subject subject = SecurityUtils.getSubject(); // 建立token令牌 UsernamePasswordToken token = new UsernamePasswordToken("zhangsan", "111111"); // 執行認證 try { subject.login(token); } catch (AuthenticationException e) { // TODO Auto-generated catch block e.printStackTrace(); } System.out.println("認證狀態:" + subject.isAuthenticated()); // 認證經過後執行受權 // 基於資源的受權,調用isPermitted方法會調用CustomRealm從數據庫查詢正確權限數據 // isPermitted傳入權限標識符,判斷user:create:1是否在CustomRealm查詢到權限數據以內 boolean isPermitted = subject.isPermitted("user:create:1"); System.out.println("單個權限判斷" + isPermitted); boolean isPermittedAll = subject.isPermittedAll("user:create:1", "user:create"); System.out.println("多個權限判斷" + isPermittedAll); // 使用check方法進行受權,若是受權不經過會拋出異常 subject.checkPermission("items:add:1"); }
(2)shiro-realm.ini
[main] #自定義 realm customRealm=com.jincou.shiro.realm.CustomRealm #將realm設置到securityManager securityManager.realms=$customRealm
(3)自定義CustomRealm類
public class CustomRealm extends AuthorizingRealm { // 用於認證(上面寫過) @Override protected AuthenticationInfo doGetAuthenticationInfo( AuthenticationToken token) throws AuthenticationException { return null; } // 用於受權 @Override protected AuthorizationInfo doGetAuthorizationInfo( PrincipalCollection principals) { //從 principals獲取主身份信息 //將getPrimaryPrincipal方法返回值轉爲真實身份類型(在上邊的doGetAuthenticationInfo認證經過填充到SimpleAuthenticationInfo中身份類型), String userCode = (String) principals.getPrimaryPrincipal(); //根據身份信息獲取權限信息 //鏈接數據庫... //模擬從數據庫獲取到數據 List<String> permissions = new ArrayList<String>(); permissions.add("user:create");//用戶的建立 permissions.add("items:add");//商品添加權限 //.... //查到權限數據,返回受權信息(要包括 上邊的permissions) SimpleAuthorizationInfo simpleAuthorizationInfo = new SimpleAuthorizationInfo(); //將上邊查詢到受權信息填充到simpleAuthorizationInfo對象中 simpleAuthorizationInfo.addStringPermissions(permissions); return simpleAuthorizationInfo; } }
運行結果:
想太多,作太少,中間的落差就是煩惱。想沒有煩惱,要麼別想,要麼多作。少校【5】