加密概念
数据加密的基本过程就是对原来为明文的文件或数据按某种算法进行处理,使其成为不可读的一段代码,通常称为"密文",使其只能在输入相应的密钥之后才能显示出本来内容,通过这样的途径来达到保护数据不被非法人窃取、阅读的目的。该过程的逆过程为解密,即将该编码信息转化为其原来数据的过程。
加密分类
对称加密
双方使用的同一个密钥,既可以加密又可以解密,这种加密方法称为对称加密,也称为单密钥加密。
非对称加密
一对密钥由公钥和私钥组成(可以使用很多对密钥)。私钥解密公钥加密数据,公钥解密私钥加密数据(私钥公钥可以互相加密解密)。
加密算法分类
单向加密
单向加密是不可逆的,也就是只能加密,不能解密。通常用来传输类似用户名和密码,直接将加密后的数据提交到后台,因为后台不需要知道用户名和密码,可以直接将收到的加密后的数据存储到数据库
双向加密
通常分为对称性加密算法和非对称性加密算法,对于对称性加密算法,信息接收双方都需事先知道密匙和加解密算法且其密匙是相同的,之后便是对数据进行加解密了。非对称算法与之不同,发送双方A,B事先均生成一堆密匙,然后A将自己的公有密匙发送给B,B将自己的公有密匙发送给A,如果A要给B发送消 息,则先需要用B的公有密匙进行消息加密,然后发送给B端,此时B端再用自己的私有密匙进行消息解密,B向A发送消息时为同样的道理。
常见算法
MD5使用实例
public class MD5Test {
@Test
public void test() {
/**
* 对单个信息加密
*/
Md5Hash md5 = new Md5Hash("123456");
System.out.println(md5.toString());
/**
* 加密添加盐值,增大解密难度
*/
md5 = new Md5Hash("123456","aaa");
System.out.println(md5.toString());
/**
* 添加盐值的同时迭代两次,增加解密难度
*/
md5 = new Md5Hash("123456","aaa",2);
System.out.println(md5);
}
}
盐值的作用
使用MD5存在一个问题,相同的password生成的hash值是相同的,如果两个用户设置了相同的密码,那么数据库中会存储两个相同的值,这是极不安全的,加Salt可以在一定程度上解决这一问题,所谓的加Salt方法,就是加点‘佐料’。其基本想法是这样的,当用户首次提供密码时(通常是注册时)由系统自动往这个密码里撒一些‘佐料’,然后在散列,而当用户登录时,系统为用户提供的代码上撒上相同的‘佐料’,然后散列,再比较散列值,来确定密码是否正确。
加盐的原理: 给原文加入随机数生成新的MD5的值
shiro中使用MD5加密
在认证方法中修改
/**
* 认证的方法
* 只认证账号,密码认证shiro自动完成
*/
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
UsernamePasswordToken upToken = (UsernamePasswordToken) token;
String userName = upToken.getUsername();
System.out.println("需要认证的账号:"+userName);
// 根据userName去数据库中查询
if(!"root".equals(userName)){
// 假设数据库只有一条账号为root的记录
return null;
}
// 假设查询得到的密码是 123456
//88316675d7882e3fdbe066000273842c 123456根据盐值aaa得到的密文
String password = "88316675d7882e3fdbe066000273842c";
return new SimpleAuthenticationInfo(userName, password, new SimpleByteSource("aaa"),"myrealm");
}
修改shiro.ini文件
[main]
#定义凭证匹配器
credentialsMatcher=org.apache.shiro.authc.credential.HashedCredentialsMatcher
#散列算法
credentialsMatcher.hashAlgorithmName=md5
#散列次数
credentialsMatcher.hashIterations=1
#将凭证匹配器设置到realm
customRealm=com.yjn.bean.MyRealm
customRealm.credentialsMatcher=$credentialsMatcher
securityManager.realms=$customRealm
测试
@Test
public void test() {
// 获取SecurityManagerFactory对象
Factory<SecurityManager> factory = new IniSecurityManagerFactory("classpath:shiro.ini");
// 根据工厂对象获取SecurityManager对象
SecurityManager manager = factory.getInstance();
// 将SecurityManager添加到运行环境中
SecurityUtils.setSecurityManager(manager);
// 获取Subject对象
Subject subject = SecurityUtils.getSubject();
// 获取对应的认证令牌
AuthenticationToken token = new UsernamePasswordToken("root", "123456") ;
// 做登录认证
try {
subject.login(token);
System.out.println("登录成功....");
} catch (UnknownAccountException e) {
System.out.println("账号错误...");
} catch (IncorrectCredentialsException e) {
System.out.println("密码错误...");
}
}