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