散列算法
通常要对密码进行散列,常用的有md5、sha等。
对MD5加密,如果知道散列后的值可以通过穷举法,得到MD5密码对应的明文。建议对MD5进行散列时加salt(盐),进行加密相当于对原始密码+盐 进行散列。
正常使用时散列方法:
在程序中对原始密码+盐进行散列,将散列值存储到数据库中,并且还要将盐也要存储在数据库中。
如果进行密码对比时,使用相同方法,将原始密码+盐进行散列,进行对比。
MD5散列测试程序
public class MD5Test {
public static void main(String[] args) {
//原始密码String source="123456";//盐String salt="qwerty";//散列次数int hashInterrations=2;/* 方法1:* 第一个参数:明文,原始密码 * 第二个参数:盐,通常使用随机数,这里指定固定字符串* 第三个参数:散列的次数,比如散列两次,相当 于md5(md5(''))*/Md5Hash md5Hash=new Md5Hash(source, salt, hashInterrations);System.out.println(md5Hash);//方法2:第一个参数:散列算法 SimpleHash sim=new SimpleHash("md5", source, salt,hashInterrations);System.out.println(sim);}
}
运行测试:
78f50b64a132f209ea77fdeebe501de6
78f50b64a132f209ea77fdeebe501de6
自定义realm支持散列算法
需求:实际开发时realm要进行md5值(明文散列后的值)的对比
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
//token是用户输入的//1、从token中取出身份信息String userCode=(String) token.getPrincipal();//2、根据用户输入的userCode从数据库查询//假设数据库用户是张三//如果查询不到则返回null/*if(!userCode.equals("zs")){return null;}*///模拟从数据库查到密码,散列值(取上面测试生成的散列码)String pwd="78f50b64a132f209ea77fdeebe501de6";// 模拟从数据库获取saltString salt = "qwerty";//上边散列值和盐对应的明文:123//如果查询到则返回认证信息AuthenticationInfoSimpleAuthenticationInfo simpleAuthenticationInfo=new SimpleAuthenticationInfo(userCode,pwd,ByteSource.Util.bytes(salt),this.getName());return simpleAuthenticationInfo;
}
在realm中配置凭证匹配器
[main]
[main]
#定义凭证匹配器
credentialsMatcher=org.apache.shiro.authc.credential.HashedCredentialsMatcher
#散列算法
credentialsMatcher.hashAlgorithmName=md5
#散列次数
credentialsMatcher.hashIterations=2#自定义realm
customRealm=com.oak.shiro.CustomRealm
#将realm设置到securityManager,相当于Spring注入
securityManager.realms=$customRealm
customRealm.credentialsMatcher=$credentialsMatcher
测试:
@Test
public void testLoginAndLogout(){
//创建securityManager工厂,通过ini配置文件创建securityManager工厂Factory<SecurityManager> factory=new IniSecurityManagerFactory("classpath:shiro-realm.ini");//创建SecurityManagerSecurityManager securityManager=factory.getInstance();//将securityManager设置到当前运行环境中SecurityUtils.setSecurityManager(securityManager);//从SecurityUtils里边创建一个subjectSubject subject = SecurityUtils.getSubject();//在认证提交前准备token(令牌)UsernamePasswordToken token=new UsernamePasswordToken("admin","123");//执行认证提交--认证失败subject.login(token);//是否认证通过boolean isAuthenticated =subject.isAuthenticated();System.out.println("是否认证通过:"+isAuthenticated);//退出操作subject.logout();//是否认证通过isAuthenticated=subject.isAuthenticated();System.out.println("是否认证通过:"+isAuthenticated);
}
测试:
是否认证通过:true
是否认证通过:false