Shrio04 自定義Realm
1 說明
1.1 Realm的作用
Realm和認證和授權時的資料互動有關,相當於DAO層。
1.2 AuthorizingRealm
》層次關係圖

》作用
繼承AuthorizingRealm類後重寫doGetAuthorizationInfo和doGetAuthenticationInfo就可以實現授權和認證邏輯。
2 程式碼實現
2.1 建立一個maven專案並引入shiro、junit依賴
2.2 建立一個類繼承AuthorizingRealm
2.3 重寫doGetAuthorizationInfo和doGetAuthenticationInfo
2.4 完整程式碼
package com.xunyji.demo04.realm; import com.xunyji.demo0.StringUtilsXyj; 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.authz.SimpleAuthorizationInfo; import org.apache.shiro.crypto.hash.Md5Hash; import org.apache.shiro.realm.AuthorizingRealm; import org.apache.shiro.subject.PrincipalCollection; import org.apache.shiro.util.ByteSource; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.util.HashMap; import java.util.HashSet; import java.util.Map; import java.util.Set; /** * @author AltEnter * @create 2019-01-23 20:32 * @desc 自定義Realm,md **/ public class CustomRealm extends AuthorizingRealm { private Logger log = LoggerFactory.getLogger(this.getClass()); private Map<String, String> userMap = new HashMap<String, String>(); { getName(); //userMap.put("fury", "111111"); //userMap.put("fury", "96e79218965eb72c92a549dd5a330112"); userMap.put("fury", "66b747dd6c7c7c8ca4227a67fff8ea6e"); } /** * 授權邏輯 * @param principals * @return */ @Override protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) { // 01 獲取使用者名稱 String username = (String) principals.getPrimaryPrincipal(); // 02 獲取許可權集合 Set<String> permissionSet = getPermissionSetByUsername(username); // 03 獲取角色集合 Set<String> roleSet = getRoleSetByUsername(username); // 04 封裝SimpleAuthorizationInfo物件 SimpleAuthorizationInfo simpleAuthorizationInfo = new SimpleAuthorizationInfo(); simpleAuthorizationInfo.setRoles(roleSet); simpleAuthorizationInfo.setStringPermissions(permissionSet); return simpleAuthorizationInfo; } /** * 根據使用者名稱獲取許可權集合 * @param username * @return */ private Set<String> getPermissionSetByUsername(String username) { HashSet<String> permissionSet = new HashSet<>(); permissionSet.add("user:create"); permissionSet.add("user:delete"); permissionSet.add("user:update"); return permissionSet; } /** * 根據使用者名稱獲取角色集合 * @param username * @return */ private Set<String> getRoleSetByUsername(String username) { HashSet<String> roleSet = new HashSet<>(); roleSet.add("admin"); roleSet.add("user"); return roleSet; } /** * 認證邏輯 * @param token * @return * @throws AuthenticationException */ @Override protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException { // 01 獲取前端使用者名稱和密碼 String username = (String) token.getPrincipal(); String passoword = new String((char[]) token.getCredentials()); if (StringUtilsXyj.isEmpty(passoword) || StringUtilsXyj.isEmpty(username)) { String msg = "doGetAuthenticationInfo - 使用者名稱和密碼不能為空"; log.info(msg); throw new RuntimeException(msg); } log.info(String.format("doGetAuthenticationInfo - 前端傳過來的使用者資訊為 - 使用者名稱為:%s ,使用者密碼為:%s", username, passoword)); System.out.println(String.format("doGetAuthenticationInfo - 前端傳過來的使用者資訊為 - 使用者名稱為:%s ,使用者密碼為:%s", username, passoword)); // 02 根據使用者名稱獲取使用者密碼 String pwd = getPasswordByUsername(username); // 03 前端密碼加密加鹽處理 passoword = string2Md5Hash(passoword, "AltEnter"); System.out.println("加鹽加密後的密碼為:" + pwd); // 04 密碼比對 if (passoword.equals(pwd)) { // 封裝SimpleAuthenticationInfo物件 SimpleAuthenticationInfo simpleAuthenticationInfo = new SimpleAuthenticationInfo(username, passoword, getName()); // 加鹽處理 simpleAuthenticationInfo.setCredentialsSalt(ByteSource.Util.bytes("AltEnter")); return simpleAuthenticationInfo; } else { String msg = "doGetAuthenticationInfo - 使用者名稱或者密碼錯誤"; log.info(msg); System.out.println(msg); throw new RuntimeException(msg); } } /** * 密碼加密加鹽處理 * @param password 待加密密碼 * @param salt 鹽 * @return 經過加密和加鹽處理後的密碼 */ private String string2Md5Hash(String password, String salt) { return new Md5Hash(password, salt).toString(); } /** * 根據使用者名稱獲取密碼 * @param username * @return */ private String getPasswordByUsername(String username) { String pwd = userMap.get(username); return pwd; } public static void main(String[] args) { //Md5Hash md5Hash = new Md5Hash("111111"); //System.out.println("111111加密後的結果為:" + md5Hash.toString()); //96e79218965eb72c92a549dd5a330112 Md5Hash md5Hash = new Md5Hash("111111", "AltEnter"); System.out.println("111111經過MD5加密和AltEnter加鹽後的結果為:" + md5Hash.toString()); //66b747dd6c7c7c8ca4227a67fff8ea6e } }
3 測試類
package com.xunyji.demo04.realm; import org.apache.shiro.SecurityUtils; import org.apache.shiro.authc.UsernamePasswordToken; import org.apache.shiro.authc.credential.HashedCredentialsMatcher; import org.apache.shiro.authc.pam.FirstSuccessfulStrategy; import org.apache.shiro.authc.pam.ModularRealmAuthenticator; import org.apache.shiro.mgt.DefaultSecurityManager; import org.apache.shiro.subject.Subject; import org.junit.Test; import static org.junit.Assert.*; public class CustomRealmTest { @Test public void test01() { CustomRealm customRealm = new CustomRealm(); // shiro加密 start HashedCredentialsMatcher matcher = new HashedCredentialsMatcher(); //選擇加密方式 matcher.setHashAlgorithmName("md5"); //加密次數 matcher.setHashIterations(1); // 給自定義Realm設定加密規則 customRealm.setCredentialsMatcher(matcher); //shiro加密 end // 更改認證策略 start DefaultSecurityManager defaultSecurityManager = new DefaultSecurityManager(); FirstSuccessfulStrategy firstSuccessfulStrategy = new FirstSuccessfulStrategy(); ModularRealmAuthenticator modularRealmAuthenticator = new ModularRealmAuthenticator(); modularRealmAuthenticator.setAuthenticationStrategy(firstSuccessfulStrategy); defaultSecurityManager.setAuthenticator(modularRealmAuthenticator); // 更改認證策略 end defaultSecurityManager.setRealm(customRealm); SecurityUtils.setSecurityManager(defaultSecurityManager); Subject subject = SecurityUtils.getSubject(); UsernamePasswordToken token = new UsernamePasswordToken("fury", "111111"); subject.login(token); System.out.println(String.format("認證資訊為:%s", subject.isAuthenticated())); System.out.println(String.format("擁有admin角色嗎? - %s", subject.hasRole("admin"))); System.out.println(String.format("擁有user:create許可權嗎? - %s", subject.isPermitted("user:create"))); subject.logout(); System.out.println(String.format("認證資訊為:%s", subject.isAuthenticated())); } }
4 注意
4.1 可以給SecurityManager設定認證策略
4.2 可以給Realm設定MD5加密
4.3 SecurityManager必須先設定認證策略再設定Realm