$Shiro前端
Apache-shiro 是一種簡便的java安全框架,對於身份認證,受權 。權限管理有着很簡單的使用方法java
subject :訪問當前系統的用戶 主體能夠是用戶也能夠是程序 。算法
Shrio SecurityManager :安全管理器 ,shiro 的核心。相似於SpringMVC的前端控制器(DispatcherServlet),接收來自 「subject」 的委託,與認證器 ,受權器等進行交互數據庫
Realm:至關於dataSource 安全的數據源 充當了shiro 與 數據源 的 「鏈接器」 當執行認證,受權時,shiro會從realm中比對信息是否合法合理。apache
Shiro認證(使用ini方式進行測試)---> 全部項目均使用maven方式編寫 安全
shiro.ini(建立一個配置文件存放信息 。模擬從數據庫中獲取信息)框架
[users] #帳號=密碼 chen=123 root=10001
新建一個測試類maven
加載配置文件 獲取當前用戶信息性能
經過單獨測試編寫兩個異常信息 ,反饋當用戶名出錯 或者密碼出錯的狀況,測試
package com.shiro.test; import org.apache.shiro.SecurityUtils; import org.apache.shiro.authc.IncorrectCredentialsException; import org.apache.shiro.authc.UnknownAccountException; 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.junit.Test; /** * 測試shiro * * @author 18609 * */ public class ShiroTest { @Test public void logintest() { // 建立工廠,加載資源 shiro工廠 調用Factory接口 Factory<SecurityManager> factory = new IniSecurityManagerFactory("classpath:shiro-realm.ini"); // 經過工廠對象建立SecurityManager對象 SecurityManager manager = factory.getInstance(); // 將SecurityManager綁定當前環境中。讓系統隨時訪問SecurityManager對象 SecurityUtils.setSecurityManager(manager); // 建立當前登錄主體 未認證 Subject subject = SecurityUtils.getSubject(); // 收集當前用戶信息 UsernamePasswordToken token = new UsernamePasswordToken("root", "10001"); try { subject.login(token); System.out.println("登陸成功"); } catch (IncorrectCredentialsException e) { // 密碼異常錯誤 System.out.println("登錄失敗,密碼錯誤!"); } catch (UnknownAccountException e) { // 帳號異常錯誤 System.out.println("登錄失敗,帳號不存在!"); } finally { subject.logout(); System.out.println("註銷成功"); } } }
經過token 獲取到username 並傳給Realm驗證 ,若是存在相同數據,封裝成以下AuthenticationInfo對象進行返回 不然爲null
自定義一個Realm類 繼承 AuthenticatingRealm 並複寫其類的getName() 實現兩個方法 進行認證操做
package com.shiro.Realm; import org.apache.shiro.authc.AuthenticationException; import org.apache.shiro.authc.AuthenticationInfo; import org.apache.shiro.authc.AuthenticationToken; import org.apache.shiro.authc.SimpleAuthenticationInfo; import org.apache.shiro.authz.AuthorizationInfo; import org.apache.shiro.realm.AuthenticatingRealm; import org.apache.shiro.subject.PrincipalCollection; public class MyRealm extends AuthenticatingRealm { // 重寫 注意返回值 public String getName() { return "MyRealm"; } // 受權 protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) { return null; } // 認證 protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException { System.out.println(token); // 獲取用戶名 String username = (String) token.getPrincipal(); // 經過用戶名查詢 並返回 if (!"root".equals(username)) { return null; } String password = "10001"; // 對比當前信息 SimpleAuthenticationInfo info = new SimpleAuthenticationInfo(username, password, getName()); return info; } }
shiro-realm.ini
#自定義realm MyRealm=com.shiro.Realm.MyRealm #指定自定義realm的實現 securityManager.realms=$MyRealm
執行流程
認證成功
Shiro加密認證(使用ini方式進行測試)---> 全部項目均使用maven方式編寫
shiro 對md5加密有着較好的支持,這裏不說明爲何要進行加密措施。
測試幾種加密方法 越往下 加密措施越好。越不易破解(如下加密方式全選用第三種 密碼 + salt + 散列次數)
package com.shiro.test; import org.apache.shiro.crypto.hash.Md5Hash; import org.junit.Test; public class Md5Test { @Test public void test() { String password = "10001"; // 密碼加密 Md5Hash hash = new Md5Hash(password); System.out.println("password: " + hash); // 密碼 + salt(用戶名) Md5Hash hash1 = new Md5Hash(password, "root"); System.out.println("passsword + salt :" + hash1); // 密碼 + salt(用戶名) + 散列次數 安全性能更好 Md5Hash hash2 = new Md5Hash(password, "root", 3); System.out.println("passsword + salt + count :" + hash2); } }
測試類
package com.shiro.test; import org.apache.shiro.SecurityUtils; import org.apache.shiro.authc.IncorrectCredentialsException; import org.apache.shiro.authc.UnknownAccountException; 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.junit.Test; /** * 測試shiro * * @author 18609 * */ public class ShiroTest { @Test public void loginByPasswordtest() { // 建立工廠,加載資源 shiro工廠 調用Factory接口 Factory<SecurityManager> factory = new IniSecurityManagerFactory("classpath:shiro-md5.ini"); // 經過工廠對象建立SecurityManager對象 SecurityManager manager = factory.getInstance(); // 將SecurityManager綁定當前環境中。讓系統隨時訪問SecurityManager對象 SecurityUtils.setSecurityManager(manager); // 建立當前登錄主體 未認證 Subject subject = SecurityUtils.getSubject(); // 收集當前用戶信息 UsernamePasswordToken token = new UsernamePasswordToken("root", "10001"); try { subject.login(token); System.out.println("登陸成功"); } catch (IncorrectCredentialsException e) { // 密碼異常錯誤 System.out.println("登錄失敗,密碼錯誤!"); } catch (UnknownAccountException e) { // 帳號異常錯誤 System.out.println("登錄失敗,帳號不存在!"); } finally { subject.logout(); System.out.println("註銷成功"); } } }
新建passwordRealm類 進行加密認證
package com.shiro.Realm; import org.apache.shiro.authc.AuthenticationException; import org.apache.shiro.authc.AuthenticationInfo; import org.apache.shiro.authc.AuthenticationToken; import org.apache.shiro.authc.SimpleAuthenticationInfo; import org.apache.shiro.authz.AuthorizationInfo; import org.apache.shiro.realm.AuthorizingRealm; import org.apache.shiro.subject.PrincipalCollection; import org.apache.shiro.util.ByteSource; public class PasswordRealm extends AuthorizingRealm {
//注意返回值 public String getName() { return "PasswordRealm"; } // 受權 protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) { return null; } // 認證 protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException { System.out.println(token); // 獲取用戶名 String username = (String) token.getPrincipal(); // 經過用戶名查詢 並返回 if (!"root".equals(username)) { return null; } // passsword + salt + count :2634402341f810a1007d7c4b4521aef5 String password = "2634402341f810a1007d7c4b4521aef5"; // 對比當前信息 1.用戶名 2.密碼 3.salt(加鹽加密ByteSource.Util.bytes("root")) 4.重寫當前的realm名字 SimpleAuthenticationInfo info = new SimpleAuthenticationInfo (username, password, ByteSource.Util.bytes("root"),getName()); return info; } }
ByteSource.Util.bytes("root") :進行鹽(salt)加密認證 內填用戶名
不寫此參數使用salt加密 會報錯。報密碼錯誤的問題 由於沒有進行用戶名認證。
shiro-md5.ini
填寫與測試中相關的信息 紅色標註不能更改必填項 藍色標註更改項。
#定義憑證匹配器 credentialsMatcher=org.apache.shiro.authc.credential.HashedCredentialsMatcher #散列算法 credentialsMatcher.hashAlgorithmName=md5 #散列次數 credentialsMatcher.hashIterations=3 #指定passwordRealm的realm myRealm=com.shiro.Realm.PasswordRealm #引用憑證 myRealm.credentialsMatcher=$credentialsMatcher #引用指定realm securityManager.realms=$myRealm
經過設置加密的密碼 存入數據庫中 ,並進行加密認證 數據相同時,經過認證。登陸成功。