您的位置:首页 > 数据库

第五章,在数据库中加密密码

2018-01-30 16:34 190 查看
 诶,弄了一个下午了,总共有两种加密方法。有一种是继承某个Realm,在涛哥的项目里面学了,但是我觉得不怎么实用,
原因是为了能够支持角色认证,我觉得有必要使用Shiro自己封装的JdbcRealm体系,重写里面的SQL语句,这样的代码
复用性很高。接下来就来介绍这种方法,花了三个小时才弄完,希望能在未来复习中将赚回来超过三个小时的收益。

 首先是数据库的users表,存放着用户名,加密后密码,密码的私钥。效果如图所示


 
我们就那7号用户“喵喵”来说,原本“喵喵”的密码是123,加密后在数据库中显示成这样。

 配置文件
[main]
#本类是用来加密和解密的类
credentialsMatcher=org.apache.shiro.authc.credential.HashedCredentialsMatcher
#使用md5加密
credentialsMatcher.hashAlgorithmName=md5
#加密2次,就是把加密后的密码在加密一次
credentialsMatcher.hashIterations=2
#我也不懂
credentialsMatcher.storedCredentialsHexEncoded=true

#数据库相关信息
dataSource=com.alibaba.druid.pool.DruidDataSource
dataSource.driverClassName=com.mysql.jdbc.Driver
dataSource.url=jdbc:mysql://localhost:3306/shiro
dataSource.username=root
dataSource.password=3333

#jdbcRealm,它才是我想要的Realm,而不是继承别的Realm,因为它直接与数据库交互
jdbcRealm=org.apache.shiro.realm.jdbc.JdbcRealm
jdbcRealm.dataSource=$dataSource
jdbcRealm.permissionsLookupEnabled=true
#相关解析器,这不是重点
jdbcRealm.saltStyle=COLUMN
#重写的SQL语句,非常important。Shiro的加密规律是 明文密码+加密规则(username+password_salt) = 密文密码
#本次SQL语句就是获取用户的加密规则,与用户在登录页面输入的密码进行计算,得出相应的结果。
#如果这个结果 与 从数据库查询到的password是一致的,那么本次认证成功,否则失败
jdbcRealm.authenticationQuery=select password, concat(username,password_salt) from users where username = ?
#注入加密解密类
jdbcRealm.credentialsMatcher=$credentialsMatcher
securityManager.realms=$jdbcRealm

 

不管什么样的加密,总是离不开一个加密规则,我们可以把它看作是加密器。 明文 + 加密规则 = 密文
因此,比如在Web页面,我们获取到用户的密码,使用我们的加密规则,算出密文,拿着这个密文去与数据库中存放
的密码比较。如果是相同的话,那么证明是正确的帐号密码信息。即
如果存在如下关系,则可以认为是正确的帐号密码:
用户在页面输入的密码 + 数据库存储的加密规则 == 数据库存储的加密密码。

 测试代码package me.jay.chapter5;

import junit.framework.Assert;
import org.apache.commons.beanutils.BeanUtilsBean;
import org.apache.commons.beanutils.converters.AbstractConverter;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.config.IniSecurityManagerFactory;
import org.apache.shiro.crypto.SecureRandomNumberGenerator;
import org.apache.shiro.crypto.hash.SimpleHash;
import org.apache.shiro.realm.jdbc.JdbcRealm;
import org.apache.shiro.subject.Subject;
import org.apache.shiro.util.Factory;
import org.junit.Test;

/**
* Created by jay.zhou on 2018/1/30.
*/
public class TestExample {
/**
* 获取miaomiao的加密的相关信息,手动添加到了数据库中,在项目中肯定是用Mybatis框架来做
*/
@Test
public void testGeneratePassword() {
String algorithmName = "md5";
String username = "miaomiao";//公钥, 加密规则 = “用户名公钥 + 随机生成的私钥”
String password = "123";
//salt是随机生成的私钥,存放在数据库中,公钥的话是用户名。用户名+salt 连接起来 形成了 此帐号的 加密规则
String salt = new SecureRandomNumberGenerator().nextBytes().toHex();
int hashIterations = 2;
//加密规则就是“公钥+私钥” username + salt。我们的 password + 加密规则 = 密文,将其存放到数据库中
SimpleHash hash = new SimpleHash(algorithmName, password, username + salt, hashIterations);
String encodedPassword = hash.toHex();//生成加密后的密码
//每次测试的数据都不一样,因为salt是随机生成的
System.out.println(encodedPassword);//根据本次生成的私钥,加密后的密码是:2a9c616f5dc6d23329ad4622ff8fa89f
System.out.println(salt);//本次生成的私钥是:b58c47e10cc56807ce31010a41c7fa65,手动存放到了数据库中,可以看图

}

@Test
public void testHashedCredentialsMatcherWithJdbcRealm() {
//此代码在配置文件中对应着:jdbcRealm.saltStyle=COLUMN,用于注册一个Enum转换器,用于解析配置文件中COLUMN的含义
BeanUtilsBean.getInstance().getConvertUtils().register(new EnumConverter(), JdbcRealm.SaltStyle.class);
//加载配置文件,并获取工厂,这个SecurityManager可能与java.lang包下的SecurityManager冲突,因此加上泛型
Factory<org.apache.shiro.mgt.SecurityManager> factory = new IniSecurityManagerFactory("classpath:chapter5/jdbc.ini");
//获取shiro的核心SecurityManager对象
org.apache.shiro.mgt.SecurityManager sm = factory.getInstance();
//将安全管理者SecurityManager放入全局对象SecurityUtils
SecurityUtils.setSecurityManager(sm);
//全局对象通过安全管理者生成Subject对象
Subject subject = SecurityUtils.getSubject();
//封装用户的数据
UsernamePasswordToken token = new UsernamePasswordToken("miaomiao", "123");
//将封装用户的标识token 与 数据源 进行对比认证
subject.login(token);
//判断本帐号是否已经被认证
Assert.assertEquals(true, subject.isAuthenticated());
}

/**
* 此类用于解析配置文件中COLUMN的含义,非重点。
* 涛哥:用于注册一个Enum转换器
*/
private class EnumConverter extends AbstractConverter {
@Override
protected String convertToString(final Object value) throws Throwable {
return ((Enum) value).name();
}
@Override
protected Object convertToType(final Class type, final Object value) throws Throwable {
return Enum.valueOf(type, value.toString());
}

@Override
protected Class getDefaultType() {
return null;
}

}

}

 第一个测试的输出的 “私钥” 和 “加密后的密码”,对应着数据库7号miaomiao的加密信息。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: