Shiro加盐加密

接本人的上篇文章《Shiro认证、角色、权限》,这篇文章我们来学习shiro的加盐加密实现

自定义Realm:

package com.czhappy.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.authz.SimpleAuthorizationInfo;
import org.apache.shiro.realm.AuthenticatingRealm;
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;

/**
 * 自定义Realm
 */
public class CustomRealm extends AuthorizingRealm {

    Map<String, String> userMap = new HashMap<String, String>(16);
    {
        userMap.put("chen", "eeb9bad681184779aa6570e402d6ef6c");
        super.setName("customRealm");
    }

    //角色权限验证
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
        String userName = (String) principalCollection.getPrimaryPrincipal();
        //从数据库或者缓存中获取角色数据
        Set<String> roleSet = getRolesByUserName(userName);

        //从数据库或者缓存中获取权限数据
        Set<String> permissionSet = getPermissionsByUserName(userName);

        SimpleAuthorizationInfo simpleAuthorizationInfo = new SimpleAuthorizationInfo();
        simpleAuthorizationInfo.setRoles(roleSet);
        simpleAuthorizationInfo.setStringPermissions(permissionSet);
        return simpleAuthorizationInfo;
    }

    /**
     * 模拟从数据库或者缓存中获取权限数据
     * @param userName
     * @return
     */
    private Set<String> getPermissionsByUserName(String userName) {
        Set<String> sets = new HashSet<String>();
        sets.add("user:add");
        sets.add("user:delete");
        return sets;
    }

    /**
     * 模拟从数据库或者缓存中获取角色数据
     * @param userName
     * @return
     */
    private Set<String> getRolesByUserName(String userName) {
        Set<String> sets = new HashSet<String>();
        sets.add("admin");
        sets.add("user");
        return sets;
    }

    //登录验证
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
        //从主体传过来的认证信息中获取用户名
        String userName = (String) authenticationToken.getPrincipal();
        //通过用户名到数据库中获取凭证
        String password = getPasswordByUsername(userName);

        if(password == null){
            return null;
        }
        SimpleAuthenticationInfo simpleAuthenticationInfo = new SimpleAuthenticationInfo
                (userName, password, "customRealm");
        //设置加盐参数
        simpleAuthenticationInfo.setCredentialsSalt(ByteSource.Util.bytes("hello"));
        return simpleAuthenticationInfo;
    }

    /**
     * 模拟数据库访问
     * @param userName
     * @return
     */
    private String getPasswordByUsername(String userName) {
        return userMap.get(userName);
    }
}

编写测试实现类:

设置以md5的加密方式加密,加盐的参数设置为:hello

package com.czhappy.test;

import com.czhappy.realm.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;

public class CustomRealmTest {

    @Test
    public void testAuthentication() {
        CustomRealm customRealm = new CustomRealm();
        //创建SecurityManager环境
        DefaultSecurityManager defaultSecurityManager = new DefaultSecurityManager();
        defaultSecurityManager.setRealm(customRealm);

        HashedCredentialsMatcher matcher = new HashedCredentialsMatcher();
        matcher.setHashAlgorithmName("md5");//加密方式
        matcher.setHashIterations(1);//加密次数

        customRealm.setCredentialsMatcher(matcher);



        //主体提交认证请求
        SecurityUtils.setSecurityManager(defaultSecurityManager);
        Subject subject = SecurityUtils.getSubject();
        UsernamePasswordToken token = new UsernamePasswordToken("chen", "123456");
        subject.login(token);

        System.out.println("isAuthenticated=" + subject.isAuthenticated());
        subject.checkRole("admin");
        subject.checkPermissions("user:delete", "user:add");

    }

    public static void main(String[] args) {
        Md5Hash md5Hash = new Md5Hash("123456", "hello");
        System.out.println(md5Hash.toString());
    }
}

 

Shiro 提供了强大的加密功能,其中 MD5 结合随机盐(salt)是常见的加密方式,以下从相关概念、原理、使用方法等方面进行介绍。 ### 相关概念 - **MD5**:是一种不可逆加密算法,将任意长度的数据通过哈希运算转换为固定长度(通常为 128 位)的哈希值。它具有计算速度快的特点,但安全性相对较低,容易受到碰撞攻击,因此通常会结合随机盐使用以增强安全性 [^1]。 - **随机盐(salt)**:是一个随机生成的字符串,在加密过程中与原始密码进行组合,然后再进行加密操作。使用随机盐可以避免相同密码生成相同的哈希值,增加了密码的安全性 [^1]。 ### 原理 在 Shiro 中使用 MD5 和随机盐进行加密的原理是,先生成一个随机盐,将其与用户的原始密码拼接在一起,然后使用 MD5 算法对拼接后的字符串进行哈希运算,得到最终的加密密码。在验证密码时,从存储的信息中获取盐值,将用户输入的密码与该盐值再次拼接并进行相同的 MD5 运算,将得到的结果与存储的加密密码进行比较,如果相同则验证通过 [^1]。 ### 使用方法 #### 依赖引入 在项目中引入 Shiro加密依赖: ```xml <dependency> <groupId>org.apache.shiro</groupId> <artifactId>shiro-crypto-hash</artifactId> <version>1.11.0</version> </dependency> ``` #### 代码示例 以下是一个简单的 Java 代码示例,展示了如何使用 Shiro 进行 MD5 和随机盐的加密: ```java import org.apache.shiro.crypto.hash.Md5Hash; public class ShiroEncryptionExample { public static void main(String[] args) { String password = "123456"; // 生成随机盐 String salt = Md5Hash.generateSalt(); // 进行 MD5 加密,迭代次数为 1 Md5Hash md5Hash = new Md5Hash(password, salt, 1); String encryptedPassword = md5Hash.toString(); System.out.println("原始密码: " + password); System.out.println("随机盐: " + salt); System.out.println("加密后的密码: " + encryptedPassword); } } ``` ### Shiro 加密服务接口 Shiro 还提供了 `PasswordService` 及 `CredentialsMatcher` 用于提供加密密码及验证密码服务: ```java public interface PasswordService { // 输入明文密码得到密文密码 String encryptPassword(Object plaintextPassword) throws IllegalArgumentException; } public interface CredentialsMatcher { // 匹配用户输入的 token 的凭证(未加密)与系统提供的凭证(已加密) boolean doCredentialsMatch(AuthenticationToken token, AuthenticationInfo info); } ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值