SpringBoot+shiro+redis整合(二)

上一篇,我们已经搭建简单的搭建好了基于mysql数据库数据的shiro安全框架。接下来,我们为密码进行3DES加密。

需要注意的是,密码字段加密,正常思路是在注册时,把注册信息存进数据库前对密码进行加密后再存入。我们这里没有注册业务,所以我们自行提供一个接口为密码字段进行加密,然后再更新进数据库。

这里简单的说下,3DES,也称为3DESede或TripleDES,属于双向加密,是三重数据加密,且可以逆推的一种算法方案。1975年美国IBM公司成功研究并发布了DES加密算法,但DES密码长度容易被暴力破解,通过对DES算法进行改进,针对每个数据块进行三次DES加密,也就是3DES加密算法。算法本身是公开的,主要是依靠唯一密钥,也就是key,来确保数据加密解密的安全。

1. 3DES加密核心类

ThreeDES.class:

@SuppressWarnings({ "restriction" })
public class ThreeDES {

    private static final String IV = "1234567-";
    public static final String KEY = "uatspdbcccgame2014061800";

    /**
     * DESCBC加密
     *
     * @param src
     *            数据源
     * @param key
     *            密钥,长度必须是8的倍数
     * @return 返回加密后的数据
     * @throws Exception
     */
    public String encryptDESCBC(final String src, final String key) throws Exception {

        // --生成key,同时制定是des还是DESede,两者的key长度要求不同
        final DESKeySpec desKeySpec = new DESKeySpec(key.getBytes("UTF-8"));
        final SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("DES");
        final SecretKey secretKey = keyFactory.generateSecret(desKeySpec);

        // --加密向量
        final IvParameterSpec iv = new IvParameterSpec(IV.getBytes("UTF-8"));

        // --通过Chipher执行加密得到的是一个byte的数组,Cipher.getInstance("DES")就是采用ECB模式,cipher.init(Cipher.ENCRYPT_MODE,
        // secretKey)就可以了.
        final Cipher cipher = Cipher.getInstance("DES/CBC/PKCS5Padding");
        cipher.init(Cipher.ENCRYPT_MODE, secretKey, iv);
        final byte[] b = cipher.doFinal(src.getBytes("UTF-8"));

        // --通过base64,将加密数组转换成字符串
        final BASE64Encoder encoder = new BASE64Encoder();
        return encoder.encode(b);
    }

    /**
     * DESCBC解密
     *
     * @param src
     *            数据源
     * @param key
     *            密钥,长度必须是8的倍数
     * @return 返回解密后的原始数据
     * @throws Exception
     */
    public String decryptDESCBC(final String src, final String key) throws Exception {
        // --通过base64,将字符串转成byte数组
        final BASE64Decoder decoder = new BASE64Decoder();
        final byte[] bytesrc = decoder.decodeBuffer(src);

        // --解密的key
        final DESKeySpec desKeySpec = new DESKeySpec(key.getBytes("UTF-8"));
        final SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("DES");
        final SecretKey secretKey = keyFactory.generateSecret(desKeySpec);

        // --向量
        final IvParameterSpec iv = new IvParameterSpec(IV.getBytes("UTF-8"));

        // --Chipher对象解密Cipher.getInstance("DES")就是采用ECB模式,cipher.init(Cipher.DECRYPT_MODE,
        // secretKey)就可以了.
        final Cipher cipher = Cipher.getInstance("DES/CBC/PKCS5Padding");
        cipher.init(Cipher.DECRYPT_MODE, secretKey, iv);
        final byte[] retByte = cipher.doFinal(bytesrc);

        return new String(retByte);

    }

    // 3DESECB加密,key必须是长度大于等于 3*8 = 24 位哈
    public String encryptThreeDESECB(final String src, final String key) throws Exception {
        final DESedeKeySpec dks = new DESedeKeySpec(key.getBytes("UTF-8"));
        final SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("DESede");
        final SecretKey securekey = keyFactory.generateSecret(dks);

        final Cipher cipher = Cipher.getInstance("DESede/ECB/PKCS5Padding");
        cipher.init(Cipher.ENCRYPT_MODE, securekey);
        final byte[] b = cipher.doFinal(src.getBytes());

        final BASE64Encoder encoder = new BASE64Encoder();
        return encoder.encode(b).replaceAll("\r", "").replaceAll("\n", "");

    }

    // 3DESECB解密,key必须是长度大于等于 3*8 = 24 位哈
    public String decryptThreeDESECB(final String src, final String key) throws Exception {
        // --通过base64,将字符串转成byte数组
        final BASE64Decoder decoder = new BASE64Decoder();
        final byte[] bytesrc = decoder.decodeBuffer(src);
        // --解密的key
        final DESedeKeySpec dks = new DESedeKeySpec(key.getBytes("UTF-8"));
        final SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("DESede");
        final SecretKey securekey = keyFactory.generateSecret(dks);

        // --Chipher对象解密
        final Cipher cipher = Cipher.getInstance("DESede/ECB/PKCS5Padding");
        cipher.init(Cipher.DECRYPT_MODE, securekey);
        final byte[] retByte = cipher.doFinal(bytesrc);

        return new String(retByte);
    }

}

2. 密码加密并更新数据库

UserController.class添加更新密码的接口:

@ApiOperation("根据用户名为密码加密")
@RequestMapping(value = "/encrypt/{username}", method = RequestMethod.GET)
@ResponseBody
public Object updatePasswordWithEncryption(@PathVariable String username) throws Exception {
    ThreeDES threeDES = new ThreeDES();

    User user = userService.getUserInfoByName(username);
    String password = user.getPassword();
    //  密码加密
    password = threeDES.encryptThreeDESECB(URLEncoder.encode(password, "UTF-8"), key);

    int i = userService.updatePasswordWithEncryption(username, password);
    return i == 1? "加密成功":"加密失败";
}

接下来,可以通过http://localhost:8080/user/encrypt/{需要加密的用户名},进行加密,加密完可以在数据库中看到加密后的密码,也可以通过接口查询出用户的信息看到加密后的密码。

如果你只是想用3DES加密,不要整合shiro框架的话,那你可以直接使用以下代码进行加密解密。

//唯一密钥,即key
final String key = "cf410f84904a44cc8a7f48fc4134e8f9";
ThreeDES threeDES = new ThreeDES();
//加密
String str_encrypt = threeDES.encryptThreeDESECB(URLEncoder.encode(str, "UTF-8"), key);
//解密
String str_dencrypt = threeDES.decryptThreeDESECB(str, key);

3. 修改shiro相关

上面已经为数据库中的密码进行加密了,那么我们在UserRealm类的AuthenticationInfo()方法中,执行密码验证那里,需要先给密码进行解密再验证。

//判断密码
try {
    SimpleAuthenticationInfo simpleAuthenticationInfo = new SimpleAuthenticationInfo(user, threeDES.decryptThreeDESECB(user.getPassword(), key), "");
    return simpleAuthenticationInfo;
} catch (Exception e) {
    e.printStackTrace();
    return null;
}

到这里,我们整合3DES加密就完成了。下一篇我们进行基于redis的cache缓存管理和session会话管理整合。

如果有什么需要改进的,还请多加指教。

你可能感兴趣的:(SpringBoot,shiro,redis)