Shiro加密

Shiro散列配置:

  • HashedCredentialsMatcher:哈希凭证匹配器(工具类)
  • 自定义Realm中使用散列
  • 盐的使用:增加被破解难度

一. 延用自定义Realm,在自定义Realm(CustomRealm)中进行加密操作

1. 在自定义中新增 盐(自定义字符串)
public static final String salt = "realmSalt";
2. 在认证方法中新增盐的设置
// 3. 创建返回对象并设置用户信息
SimpleAuthenticationInfo simpleAuthenticationInfo =
                                        new SimpleAuthenticationInfo(userName, pwd, customName);
// 3.1 设置 盐
simpleAuthenticationInfo.setCredentialsSalt(ByteSource.Util.bytes(salt));
3. 在main方法中先计算出用户明文密码的加密串
public static void main(String[] args) {
    Md5Hash md5Hash = new Md5Hash("123",CustomRealm.salt);
    System.out.println(md5Hash);
}

4. 计算后,修改自定义Realm中模拟的用户密码
Map<String, String> userMap = new HashMap<>();
{
    userMap.put("Mark", "4b9e16b4797ce47212c031d657cd3e37");
    userMap.put("xiaoming", "4b9e16b4797ce47212c031d657cd3e37");
    super.setName(customName);
}

二. 延用测试Realm进行修改

// 3. 创建哈希凭证匹配器
HashedCredentialsMatcher hashedCredentialsMatcher = new HashedCredentialsMatcher();
// 3.1 设置加密算法
hashedCredentialsMatcher.setHashAlgorithmName("md5");
// 3.2 设置加密次数
hashedCredentialsMatcher.setHashIterations(1);
// 3.3 设置自定义Realm中的加密对象
customRealm.setCredentialsMatcher(hashedCredentialsMatcher);

三. 测试 - OK

四. 完整代码

1. 自定义Realm
package com.example.config;

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.authc.credential.HashedCredentialsMatcher;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.apache.shiro.util.ByteSource;

import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;

/**
 * @author :zhangbocong
 * @version :V1.0
 * @program :spring_boot_demo
 * @date :Created in 2021年3月16日 9:10
 * @description :自定义Realm
 */
public class CustomRealm extends AuthorizingRealm {
    private static final String customName = "customName";
    // 加密时使用的盐
    public static final String salt = "realmSalt";

    /**
     * @Description 模拟用户缓存数据
     */
    Map<String, String> userMap = new HashMap<>();
    {
        userMap.put("Mark", "4b9e16b4797ce47212c031d657cd3e37");
        userMap.put("xiaoming", "4b9e16b4797ce47212c031d657cd3e37");
        super.setName(customName);
    }

    /**
     * @Description 授权
     * @Param [principalCollection]
     * @Return org.apache.shiro.authz.AuthorizationInfo
     */
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
        // 1. 获取用户名
        String userName = (String) principalCollection.getPrimaryPrincipal();
        // 2. 获取角色数据
        Set<String> role = getRolesByUserName(userName);
        // 3. 获取权限数据
        Set<String> permission = getPermissionsByRoleName(userName);
        // 4. 创建返回对象
        SimpleAuthorizationInfo simpleAuthenticationInfo = new SimpleAuthorizationInfo();
        // 4.1 设置角色
        simpleAuthenticationInfo.setRoles(role);
        // 4.2 设置权限
        simpleAuthenticationInfo.setStringPermissions(permission);
        return simpleAuthenticationInfo;
    }

    /**
     * @Description 模拟用户角色数据
     */
    public Set<String> getRolesByUserName(String userName) {
        Set<String> roleSet = new HashSet<>();
        roleSet.add("admin");
        roleSet.add("user");
        return roleSet;
    }

    /**
     * @Description 模拟角色权限数据
     */
    public Set<String> getPermissionsByRoleName(String permission) {
        Set<String> permissionsSet = new HashSet<>();
        permissionsSet.add("user:delete");
        permissionsSet.add("user:select");
        return permissionsSet;
    }

    /**
     * @Description 认证
     * @Param [authenticationToken]
     * @Return org.apache.shiro.authc.AuthenticationInfo
     */
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
        // 1. 接收主体传过来的用户名
        String userName = (String) authenticationToken.getPrincipal();
        // 2. 根据用户名在数据库或缓存中获取凭证
        String pwd = userMap.get(userName);
        if (pwd.isEmpty()) {
            return null;
        }
        // 3. 创建返回对象并设置用户信息
        SimpleAuthenticationInfo simpleAuthenticationInfo =
                                         new SimpleAuthenticationInfo(userName, pwd, customName);
        // 3.1 设置 盐
        simpleAuthenticationInfo.setCredentialsSalt(ByteSource.Util.bytes(salt));

        return simpleAuthenticationInfo;
    }
}
2. 测试方法
package com.example.controller;

import com.example.config.CustomRealm;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.authc.credential.HashedCredentialsMatcher;
import org.apache.shiro.crypto.hash.Md5Hash;
import org.apache.shiro.mgt.DefaultSecurityManager;
import org.apache.shiro.subject.Subject;
import org.junit.Test;

/**
 * @author :zhangbocong
 * @version :V1.0
 * @program :spring_boot_demo
 * @date :Created in 2021年3月16日 9:22
 * @description :自定义Realm测试
 */
public class CustomRealmTest {
    /**
     * @Description 自定义Realm测试(加密)
     */
    @Test
    public void realmEncryption() {
        // 1. 创建自定义Realm对象
        CustomRealm customRealm = new CustomRealm();

        // 2. 构建SecurityManage环境,设置域
        DefaultSecurityManager defaultSecurityManager = new DefaultSecurityManager();
        defaultSecurityManager.setRealm(customRealm);

        // 3. 创建哈希凭证匹配器
        HashedCredentialsMatcher hashedCredentialsMatcher = new HashedCredentialsMatcher();
        // 3.1 设置加密算法
        hashedCredentialsMatcher.setHashAlgorithmName("md5");
        // 3.2 设置加密次数
        hashedCredentialsMatcher.setHashIterations(1);
        // 3.3 设置自定义Realm中的加密对象
        customRealm.setCredentialsMatcher(hashedCredentialsMatcher);

        // 4. 提交主体认证请求
        SecurityUtils.setSecurityManager(defaultSecurityManager);
        Subject subject = SecurityUtils.getSubject();

        // 5. 模拟用户
        UsernamePasswordToken token = new UsernamePasswordToken("xiaoming","123");

        // 6. 登录
        subject.login(token);
        // 6.1 验证是否认证
        System.out.println(subject.isAuthenticated());
    }
}