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

 

posted @ 2019-01-23 21:43  寻渝记  阅读(369)  评论(0编辑  收藏  举报