1.加密简介
在真实开发中我们存在数据库的密码都是加密过的,不会存明文,shiro作为安全管理框架自然也考虑到了这个问题,提供了各种加密算法,其中最常用的就是MD5加密和SHA1加密。我在上一篇实现了自定义Realm的基础上在对密码进行加密。
2.MD5Utils工具类
package cn.hzu;
import org.apache.shiro.crypto.hash.Md5Hash;
import org.apache.shiro.crypto.hash.Sha1Hash;
public class MD5Utils {
public static void main(String[] args) {
String source="123456";
Md5Hash hash1=new Md5Hash(source);
System.out.println("使用MD5加密后的结果:"+hash1.toString());
Md5Hash hash2=new Md5Hash(source, "张三");
System.out.println("使用MD5加密并加盐后的结果:"+hash2.toString());
Md5Hash hash3=new Md5Hash(source, "张三", 2);
System.out.println("使用MD5加密加盐并散列两次后的结果:"+hash3.toString());
}
/**
* 对密码加密 md5
* @param source 要加密的明文
* @param salt 盐
* @param hashIterations 散列次数
* @return
*/
public static String md5(String source, Object salt, Integer hashIterations) {
return new Md5Hash(source, salt, hashIterations).toString();
}
/**
* 对密码加密sha1
* @param source 要加密的明文
* @param salt 盐
* @param hashIterations 散列次数
* @return
*/
public static String sha1(String source, Object salt, Integer hashIterations) {
return new Sha1Hash(source, salt, hashIterations).toString();
}
}
3.修改UserServiceImpl
把模拟从数据库查出的密码改成密文,zhangsan的密码为123456加盐(张三)再散列两次形成。这里使用zhangsan这个用户做测试其他用户不改。
package cn.hzu.service.impl;
import cn.hzu.domain.User;
import cn.hzu.service.UserService;
public class UserServiceImpl implements UserService {
@Override
public User queryUserByUserName(String username) {
//模擬查詢數據庫
User user=null;
switch(username){
case "zhangsan": user=new User("zhangsna","654407ac2e454fe560337510aa6adb97");
break;
case "lisi": user=new User("zhangsna","123456");
break;
}
return user;
}
}
4.修改自定义Realm的认证方法
这里用创建的SimpleAuthenticationInfo对象用另一个构造方法带有4个参数的。前面我们将密码加了密还加盐散列了两次。这个构造方法就是把盐传过去而已,另外的散列次数和使用什么类型的加密算法要在其他地方配置。这里利用shiro的自带的工具类将字符串(盐)转成bytes数组。其他代码不变。
ByteSource salt= ByteSource.Util.bytes("zhangsan");
SimpleAuthenticationInfo info=new SimpleAuthenticationInfo(activerUser,user.getPassword(),salt,this.getName());
5.凭证配置
在这里我们要将我们用了什么加密算法和散列次数告诉shiro,shiro的认证器才能根据规则帮我们比对。这里一共有三种方式告诉shiro,原理都一样。
方式1.在自定义Realm里面声明
在自定义Realm的午餐构造函数加个配置
public MyRealm(){
HashedCredentialsMatcher credentialsMatcher=new HashedCredentialsMatcher();
//指定加密算法
credentialsMatcher.setHashAlgorithmName("MD5");
//指定散列次数
credentialsMatcher.setHashIterations(2);
setCredentialsMatcher(credentialsMatcher);
}
方式2.在xxx.ini文件里面配置
这种方法个spring差不多,上一篇有提到过
[main]
#创建凭证匹配器
credentialsMatcher=org.apache.shiro.authc.credential.HashedCredentialsMatcher
credentialsMatcher.hashAlgorithmName=md5
credentialsMatcher.hashIterations=2
#创建自定义realm
myRealm=cn.hzu.realm.MyRealm
#把当前对象给安全管理器(安全管理器在测试的时候创建)
securityManager.realms=$myRealm
myRealm.credentialsMatcher=$credentialsMatcher
方式3.在测试的时候在安全管理器设置
// ============================================================
// 3,创建UserRealm
MyRealm realm = new MyRealm();
//注入凭证匹配器
HashedCredentialsMatcher credentialsMatcher=new HashedCredentialsMatcher();
//指定加密 算法
credentialsMatcher.setHashAlgorithmName("md5");
//指定散列次数
credentialsMatcher.setHashIterations(2);
realm.setCredentialsMatcher(credentialsMatcher);
//将realm注入SecurityManager
securityManager.setRealm(realm);
// ============================================================
总结:其实这三种方式的原理都一样,只是在不同的地方设置而已,在整合了spring会更加简单。下一篇测试整合spring。