Shiro权限框架(4):MD5加密

MD5加密

    shiro有很多加密算法,如md5和sha,而且还支持加盐,使得密码的解析变得更有难度,更好的保障了数据的安全性。首先我们来看看md5算法的各种实现方式:

package com.buba.test;

import org.apache.shiro.crypto.hash.Md5Hash;
import org.apache.shiro.crypto.hash.SimpleHash;

public class MD5Test {
    public static void main(String[] args) {
        //要加密的字符串
        String password = "123456";
        //盐
        String salt = "ywz";
        //散列次数
        Integer hashIterations = 2;
        //1.不加盐的md5
        Md5Hash md5 = new Md5Hash(password);
        System.out.println(md5.toString());
        //2.加盐的md5
        md5 = new Md5Hash(password, salt);
        System.out.println(md5.toString());
        //3.加盐再设置散列次数的md5
        md5 = new Md5Hash(password, salt, hashIterations);
        System.out.println(md5.toString());
        //4.利用SimpleHash来设置md5(上面三种都可以通过这个来设置,这里举例加盐加散列次数的)
        //第一个参数是算法名称,这里指定md5,第二个是要加密的密码,第三个参数是加盐,第四个是散列次数
        SimpleHash hash = new SimpleHash("md5", password, salt, hashIterations);
        System.out.println(hash.toString());
    }
}

    上面列举了md5算法的各种实现,包括不加盐的,加盐的,加盐加散列次数的(从HashedCredentialsMatcher的源码可得知,默认散列次数为1),还有通过SimpleHash来实现md5的方式,下面看看它们的输出:

    可以看到,不加盐、加盐、加盐加散列次数后的加密字段是不一样的,而它们的数据安全性也是递增的!但是注意散列次数不能设置过大,否则运行效率会变低。下面讲讲加密算法在realm中的应用。

    一般我们在数据库保存的用户密码都是经过加密后的密码,所以我们想把加密后的用户信息传给shiro进行认证,就必须把该密码加密的算法、添加的盐以及散列的次数告诉shiro,因此我们需要配置realm里面的凭证匹配器credentialsMatcher,当用户将账号密码输进来时,shiro就会根据我们设置的加密规则对密码进行加密加盐,然后与realm中查询封装好的数据库数据进行比对认证。

/**
     * 身份验证
     *
     * @param authenticationToken
     * @return
     * @throws AuthenticationException
     */
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
        // 1.先通过主体传过来的验证信息获取用户名
        String account = (String) authenticationToken.getPrincipal();
        //*********
        // 2.通过用户名去数据库中获取凭证 此处只是简单模拟
        String password = "";
        if (!"user".equals(account)) {
            return null;
        }
        // 用户加密后的密码和盐,这两个应该从数据库中获取
        password = "614279d1b4271f318467f47a11d9ea28";
        String salt = "ywz";
        // ********
        //查询到用户,则返回AuthenticationInfo对象
        SimpleAuthenticationInfo authenticationInfo = new SimpleAuthenticationInfo(account, password, "customRealm");
        // 设置盐
        authenticationInfo.setCredentialsSalt(ByteSource.Util.bytes(salt));
        return authenticationInfo;
    }

    注意SimpleAuthenticationInfo构造函数中的盐是ByteSource类型的,因此我们需要用接口ByteSource中的静态内部类Util下的bytes(String str)方法来将我们的盐转换成ByteSource类型。

    向自定义Realm中注入认证匹配器。 

 /**
     * 将CustomRealm交给Spring管理
     *
     * @return
     */
    @Bean
    public CustomRealm realm() {
        CustomRealm customRealm = new CustomRealm();
        // 添加认证匹配器
        HashedCredentialsMatcher matcher = new HashedCredentialsMatcher();
        // 设置加密算法名字
        matcher.setHashAlgorithmName("MD5");
        // 设置迭代次数
        matcher.setHashIterations(2);
        customRealm.setCredentialsMatcher(matcher);
        return customRealm;
    }

     运行测试:

     可以看到,我们模拟的用户输入的账号是user,密码是123456,但数据库中的密码是加密加盐后的密码,所以我们给realm配置了加密算法的规则,让它将我们传过去的密码进行了同样的加密加盐(这里盐不需要我们设置,是从数据库中查询出来的),然后再和数据库的数据进行比对认证,因此这里认证是成功的(123456进行md5加密和ywz加盐后然后再散列2次就是这一串东西了:614279d1b4271f318467f47a11d9ea28。


版权声明:本文为qq_40298351原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。