java中BCryptPasswordEncoder密码的加密与验证方式

 更新时间:2023年08月25日 11:28:14   作者:DMY小天天  
这篇文章主要介绍了java中BCryptPasswordEncoder密码的加密与验证方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教

java BCryptPasswordEncoder密码的加密与验证

import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
public class Test{
    public static void main(String[] args) {
        BCryptPasswordEncoder bcp = new BCryptPasswordEncoder();
        String mm_pub = "123456";
        String mm_encode = bcp.encode(mm_pub);
        //bcp.matches(mm_pub,mm_encode),第一个参数是前端传递过来的明文密码,如123456,第二个参数是添加用户时存储的密码
        if(bcp.matches(mm_pub,mm_encode)){
            System.out.println("密码校验成功");
        }else{
            System.out.println("密码错误");
        }
    }
}

BCryptPasswordEncoder加密、验证策略

通过查看源码,了解PasswordEncoder加密以及验证密码(数据库存储的加密密码与用户输入的密码比较)的流程、方式。

加密

public String encode(CharSequence rawPassword) {
		String salt;
		if (random != null) {
			salt = BCrypt.gensalt(version.getVersion(), strength, random);//生成盐
		} else {
			salt = BCrypt.gensalt(version.getVersion(), strength);//生成盐
		}
		return BCrypt.hashpw(rawPassword.toString(), salt);//根据 明文密码 ,盐(随机) 然后生成加密密码
	}

BCryptPasswordEncoder类有三个构造方法,影响了盐的生成,如果在生成BCryptPasswordEncoder对象的时候没有指定任何参数(或只指定了一个参数),BCrypt会提供默认值,最终都会调用BCrypt.gensalt(strength, random)方法来生成盐。

接着看BCrypt类的hashpw()方法,在这个方法中根据salt值和明文密码来生成密文密码。

具体的生成细节就不再展示了,有兴趣的可以自己去看。

需要记住的是,它是先 生成盐值,根据盐值以及明文密码 生成密文。

解密

因为匹配方法里面用到解密

BCryptPasswordEncoder的matches()方法代码如下:

public boolean matches(CharSequence rawPassword, String encodedPassword) {
		if (encodedPassword == null || encodedPassword.length() == 0) {
			logger.warn("Empty encoded password");
			return false;
		}
		if (!BCRYPT_PATTERN.matcher(encodedPassword).matches()) {
			logger.warn("Encoded password does not look like BCrypt");
			return false;
		}
		return BCrypt.checkpw(rawPassword.toString(), encodedPassword);
	}
  • rawPassword :提交表单的用户密码,就是未加密的,例如表单提交为:123456
  • encodedPassword:从数据库 中获取的 已加密的密码(例如数据库中加密过的密码:“$2a$10$3HY7qAX3Hry.6uuipvWjs.liaOjCIxw93SWxYaviQygwVg3VzUqHq”(反正看不懂,这个加密密码里面有一部分是 盐)

“$2a$10$3HY7qAX3Hry.6uuipvWjs.liaOjCIxw93SWxYaviQygwVg3VzUqHq” 就是用明文 123456 加密

如果表单密码和数据库加密密码匹配,则返回true

如果不匹配,则返回false。

因为上面的matches()方法最后是调用checkpw(),所以我们来看一下

public static boolean checkpw(String rawPassword, String encodedPassword) {
        return equalsNoEarlyReturn(encodedPassword, hashpw(rawPassword, encodedPassword));
}

hashpw()这个上面说过了,就是根据 明文密码 盐 ,然后生成加密密码

  • encodedPassword: 数据库的密文密码
  • hashpw(rawPassword, encodedPassword)):把表单的密码和数据库的密文密码 加密 成 新的密文密码

然后再把这个 新的密文密码 和 数据库的密文密码 比较,如果相同就返回true。

就是说 数据库的密文密码 本身不会被解码

只是用表单的密码通过某种规则加密成新的密码,然后再把新的密码和数据库的密文密码做比较。

如果有小伙伴想研究的更深的话,可以继续看一下源码。

下面我给大家看一下我的的例子

只是Controller里面的一个方法,至于service,dao层 自己写啦,这应该都会

/*
	* 新建、修改用户
	* */
	@PostMapping
	@ResponseBody
	public String saveUser(User user){
		PasswordEncoder encoder=new BCryptPasswordEncoder();
		if(user.getId()==null){
			//新增用户,所以把表单的密码加密一下
			String encodePassword=encoder.encode(user.getPassword());
			user.setPassword(encodePassword);	
		}else{
			//判断密码是否做了修改
			User DbUser=userService.getUserById(user.getId());//从数据库查找数据
			boolean isMatch=encoder.matches(user.getPassword(),DbUser.getPassword());//第一个参数是表单的密码(未加密的),第二个是数据库里面已经加密过的密码
			if(!isMatch){
				//因为要改密码,所以把表单的密码加密
				String encodePassword=encoder.encode(user.getPassword());
				user.setPassword(encodePassword);
			}else{
				user.setPassword(DbUser.getPassword());//虽然密码没变,但是这个表单user也要保存到数据库,要么把表单密码加密放进数据库,要么就直接用数据库原本的加密密码
			}
		}
		userService.saveOrUpdateUser(user);//把这个user保存到数据库
		return "添加或修改用户成功";
	}

总结

以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。

相关文章

  • 简单的一次springMVC路由跳转实现

    简单的一次springMVC路由跳转实现

    本文主要介绍了springMVC路由跳转实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2022-04-04
  • java 使用POI合并两个word文档

    java 使用POI合并两个word文档

    这篇文章主要介绍了java 使用POI合并两个word文档的操作,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2021-07-07
  • Spring注解@Autowired和@Resource的区别详解

    Spring注解@Autowired和@Resource的区别详解

    这篇文章主要介绍了Spring注解@Autowired和@Resource的区别详解,@Autowired与@Resource都可以用来装配bean,都可以写在字段或setter方法上,@Resource是JDK提供的注解,默认按照名称进行装配,名称可通过name属性进行指定,需要的朋友可以参考下
    2023-12-12
  • java代码如何实现存取数据库的blob字段

    java代码如何实现存取数据库的blob字段

    这篇文章主要介绍了java代码如何实现存取数据库的blob字段问题,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教
    2025-04-04
  • java实现上传图片尺寸修改和质量压缩

    java实现上传图片尺寸修改和质量压缩

    这篇文章主要为大家详细介绍了java实现上传图片尺寸修改和质量压缩,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2022-04-04
  • Java设置Excel页面的配置指南

    Java设置Excel页面的配置指南

    本指南将深入探讨如何在Java代码中精细化控制Excel的页面设置,帮助你告别打印噩梦,轻松打造出媲美手动操作的专业级报表,快跟随小编一起学习一下吧
    2025-10-10
  • 分布式之全面了解Kafka的使用与特性

    分布式之全面了解Kafka的使用与特性

    Kafka 是我工作多年使用最多的消息中间件 ,特点是拥有巨大吞吐量(数百万/秒),作为当下最流行的分布式,可水平扩展,可容错的“消息系统”,下面跟随小编看下分布式之全面了解Kafka的使用与特性
    2021-11-11
  • Springboot+Netty+Websocket实现消息推送实例

    Springboot+Netty+Websocket实现消息推送实例

    这篇文章主要介绍了Springboot+Netty+Websocket实现消息推送实例,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2021-02-02
  • 使用Java后端操作Docker的详细教程

    使用Java后端操作Docker的详细教程

    Docker 是现代开发和部署流程中不可或缺的一部分,它简化了应用程序的环境配置、打包和分发,使得在不同机器上运行相同的应用变得更加轻松和一致,本文将详细介绍如何使用命令行工具(CMD)操控 Docker 来配置环境,需要的朋友可以参考下
    2025-02-02
  • 剑指Offer之Java算法习题精讲排列与N叉树

    剑指Offer之Java算法习题精讲排列与N叉树

    跟着思路走,之后从简单题入手,反复去看,做过之后可能会忘记,之后再做一次,记不住就反复做,反复寻求思路和规律,慢慢积累就会发现质的变化
    2022-03-03

最新评论