1.1 散列算法
通常需要對密碼 進行散列,常用的有md5、sha,
對md5密碼,如果知道散列後的值可以通過窮舉算法,得到md5密碼對應的明文。
建議對md5進行散列時加salt(鹽),進行加密相當 於對原始密碼+鹽進行散列。(鹽就相當於加入一個隨機數)
正常使用時散列方法:
在程序中對原始密碼+鹽進行散列,將散列值存儲到數據庫中,並且還要將鹽也要存儲在數據庫中。
如果進行密碼對比時,使用相同 方法,將原始密碼+鹽進行散列,進行比對。
1.2 MD5測試
package cn.qlq.authentication;
import org.apache.shiro.crypto.hash.Md5Hash;
import org.apache.shiro.crypto.hash.SimpleHash;
/**
* 測試MD5算法
* @author: qlq
* @date : 2017年7月28日下午9:31:45
*/
public class MD5Test {
public static void main(String[] args) {
//原始 密碼
String source = "111111";
//鹽
String salt = "qwerty";
//散列次數
int hashIterations = 2;
//上邊散列1次:f3694f162729b7d0254c6e40260bf15c
//上邊散列2次:36f2dfa24d0a9fa97276abbe13e596fc
//構造方法中:
//第一個參數:明文,原始密碼
//第二個參數:鹽,通過使用隨機數
//第三個參數:散列的次數,比如散列兩次,相當 於md5(md5(''))
Md5Hash md5Hash = new Md5Hash(source, salt, hashIterations);
String password_md5 = md5Hash.toString();
System.out.println(password_md5);
// 第二種方法
//第一個參數:散列算法
SimpleHash simpleHash = new SimpleHash("md5", source, salt, hashIterations);
System.out.println(simpleHash.toString());
}
}
------------------------------------- 自定義realm支持散列算法--------------------------------------------------------------------------------------
新建realm(CustomRealmMd5) 如果未採用md5算法則不用紅色部分第三個參數:
package cn.qlq.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; /** * 自定義realm實現MD5散列算法加密 * @author: qlq * @date : 2017年7月28日下午9:33:14 */ public class CustomRealmMd5 extends AuthorizingRealm { // 設置realm的名稱 @Override public void setName(String name) { super.setName("customRealmMd5"); } // 用於認證 @Override protected AuthenticationInfo doGetAuthenticationInfo( AuthenticationToken token) throws AuthenticationException { // token是用戶輸入的 // 第一步從token中取出身份信息 String userCode = (String) token.getPrincipal(); // 第二步:根據用戶輸入的userCode從數據庫查詢 // .... // 如果查詢不到返回null // 數據庫中用戶賬號是zhangsansan /* * if(!userCode.equals("zhangsansan")){// return null; } */ // 模擬從數據庫查詢到密碼,散列值 String password = "f3694f162729b7d0254c6e40260bf15c";
//String password = new String((char[]) token.getCredentials());
//用戶輸入密碼
// 從數據庫獲取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) {
// TODO Auto-generated method stub
return null;
}
}
在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) {
// TODO Auto-generated catch block
e.printStackTrace();
}
// 是否認證通過
boolean isAuthenticated = subject.isAuthenticated();
System.out.println("是否認證通過:" + isAuthenticated);
}