Shiro的使用(二)—使用MD5Hash完成认证(MD5加密)
文章目录
1、MD5Hash的使用问题
问题:在开发的时候、敏感信息在数据库是如何存储的?
- 敏感信息在数据库存储的时候都不能存储明文
- 一部分就类似于密码这种,不需要知道这个值本身是多少(散列)
- MD5 SHA1
- 另外一部分:需要知道这个值 是多少(加密、解密)
- DES AES 3DES RSA
在shiro框架中, 也提供了 密码散列的功能
2、使用MD5Hash完成认证
2.1、简单使用 Md5Hash
public static void main(String[] args){
// 直接散列
Md5Hash md5Hash0 = new Md5Hash("abc");
System.out.println("散列后的结果:"+md5Hash0);
// 为什么要加盐?
// 为了让密码更加安全 更加不容易被破解
Md5Hash md5Hash1 = new Md5Hash("abc", "123");
System.out.println("加盐散列之后的值:"+md5Hash1);
Md5Hash md5Hash2 = new Md5Hash("123abc");
System.out.println("加盐散列之后的值:"+md5Hash2);
System.out.println("md5Hash2 == md5Hash1 : " + md5Hash2 == md5Hash1);
// param1:密码;param2:盐;param3:散列次数
Md5Hash md5Hash = new Md5Hash("123", "", 2);
System.out.println("加盐+次数构成的值:"+md5Hash);
Md5Hash md5Hash3 = new Md5Hash("123");
Md5Hash md5Hash4 = new Md5Hash(md5Hash3);
System.out.println("md5Hash == md5Hash4 : " + md5Hash == md5Hash4);
}
2.2、搭建测试环境
2.2.1、修改数据库
- 增加password的长度(要满足可以填充密码散列后的值)
- 添加一个盐的字段
2.2.2、将数据库的密码改成盐+密码散列后的值
Md5Hash md5Hash1 = new Md5Hash("123", "111");
System.out.println("加盐散列之后的值:" + md5Hash1);
2.2.3、修改pom.xml
其他必须依赖请自行导入,或参照 shiro的使用(一)权限管理—shiro的简单使用
<!-- 添加访问数据库的依赖 -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
<version>5.1.47</version>
</dependency>
<dependency>
<groupId>commons-dbutils</groupId>
<artifactId>commons-dbutils</artifactId>
<version>1.6</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.1.16</version>
</dependency>
2.2.4、修改user.java
@Data
@AllArgsConstructor
@NoArgsConstructor
public class User implements Serializable {
private static final long serialVersionUID = 4026322871228725196L;
private Integer id;
private String name;
private String password;
private String salt;
}
2.2.5、编写JdbcUtils.java
public class JdbcUtils {
private static DruidDataSource dataSource;
static {
dataSource = new DruidDataSource();
dataSource.setDriverClassName("com.mysql.jdbc.Driver");
dataSource.setUrl("jdbc:mysql:///demo");
dataSource.setUsername("root");
dataSource.setPassword("root");
}
/**
* 返回操作数据库的对象
*/
public static QueryRunner getQueryRunner(){
return new QueryRunner(dataSource);
}
}
2.2.6、编写UserDao.java
public class UserDao {
public User getUserByName(String name) throws SQLException {
QueryRunner queryRunner = JdbcUtils.getQueryRunner();
return queryRunner.query("select * from user where name = ?", new BeanHandler<>(User.class), name);
}
}
2.2.7、编写配置文件
shiro-hash.ini resources文件夹下
[main]
# 定义凭证匹配器
credentialsMatcher=org.apache.shiro.authc.credential.HashedCredentialsMatcher
# 散列算法
credentialsMatcher.hashAlgorithmName=md5
# 散列次数
credentialsMatcher.hashIterations=1
# 将凭证匹配器设置到realm
customRealm=com.fu.shiro.realm.UserRealm
customRealm.credentialsMatcher=$credentialsMatcher
securityManager.realms=$customRealm
2.3、编写UserRealm.java
public class UserRealm extends AuthorizingRealm {
private UserDao userDao = new UserDao();
@Override
public String getName() {
return "UserRealm";
}
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
//第一步:通过token获取到用户数据
String userName = (String) authenticationToken.getPrincipal();
//第二步:通过用户名 去数据库查询用户对象
User user = null;
try {
user = userDao.getUserByName(userName);
System.out.println("从数据库里查询出来的数据是:" + user);
} catch (Exception e) {
System.out.println("查询失败: " + e.fillInStackTrace());
}
if (null == user) { // 如果数据库中没有该数据
return null;
}
return new SimpleAuthenticationInfo(user, user.getPassword(), ByteSource.Util.bytes(user.getSalt()), getName());
}
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
return null;
}
}
2.4、测试
@Test
public void userRealmTest() {
IniSecurityManagerFactory iniSecurityManagerFactory = new IniSecurityManagerFactory("classpath:shiro-hash.ini");
SecurityManager securityManager = iniSecurityManagerFactory.createInstance();
SecurityUtils.setSecurityManager(securityManager);
Subject subject = SecurityUtils.getSubject();
UsernamePasswordToken token = new UsernamePasswordToken("kongming", "123");
subject.login(token);
System.out.println("用户的认证状态:" + subject.isAuthenticated());
// 用户退出
subject.logout();
// 再次打印用户认证状态
System.out.println("用户的认证状态:" + subject.isAuthenticated());
}