写在前面

还记得在之前的文章中,我们在user表中手动插入了3条数据吗?

当时,大家就会有疑问。这一串密码是怎么来的呢,我们为啥要对密码进行加密?

带着这些疑问,我们继续上路。我们在开发一个应用系统,肯定是少不了用户注册功能的。说到注册,无非就是往user用户信息表中插入一条数据。

这条数据包含用户名 [xiezhr]、密码 [123456]等字段,而往往 密码这个字段不可能将123456直接存储的,而是通过各种加密手段处理。最终如上图所示,

即使数据库因各种原因泄露,法外狂徒张三也不知道用户的密码,这让系统又加了一把锁。

一、密码明文存储的危害

不知道大家前段时间有没有听到这么一个新闻。爱尔兰数据保护委员会(DPC)对Meta(前Facebook) 处以9100万欧元(7.14亿元人民币)的罚款,

原因正是因为Meta在未加保护或加密的情况下以明文形式存储用户密码

从Meta事件再次证明了,即使在大的企业,也难免会有所疏漏,虽然事件中并没有提到泄露信息,但一旦泄露,后果真的不可想象。

密码明文存储就像是你把家里的钥匙挂在门上,任何人都可以拿走钥匙,进入你的家;你的日记本没有上锁,任何人都可以打开看;

安全无小事,安全无小事,安全无小事。

二、加密方式及实现

2.1 对称加密

简介

就像你和你的好朋友之间有一个只有你们俩知道的秘密暗号。你们用这个暗号来传递信息,别人就算看到了也看不懂。

常见算法

  • AES(高级加密标准)
  • DES(数据加密标准)

实现

首先,你和你的朋友要商量好一个“暗号”(密钥)。然后,你把想说的话(明文)转换成只有你们俩能懂的暗号(密文)。你的朋友收到后,再用同样的“暗号”把密文变回原话。

2.2 非对称加密

简介

你有一个带锁的信箱,你把钥匙分成两把,一把公钥(可以给别人),一把私钥(自己保管)。别人用公钥把信锁上,只有你能用私钥打开

常见算法

  • RSA算法

实现

你生成一对钥匙,公钥和私钥。别人用你的公钥加密信息,然后发给你。你收到后,用自己的私钥解密。

2.3 哈希加密

简介

像是把信息扔进一个特殊的搅拌机,出来的是一个固定大小的“信息指纹”。这个“指纹”不能还原成原来的信息。

常见算法

  • MD5
  • SHA-1
  • SHA-256
  • SHA-512

实现

把信息(明文)通过一个哈希函数处理,生成一个哈希值。这个哈希值用来验证信息是否被篡改。

  • 选择一个哈希算法(如SHA-256)。

  • 把明文通过哈希算法处理,生成哈希值。

  • 存储或传输哈希值。

  • 接收者收到信息后,再次计算哈希值,与收到的哈希值对比,验证信息完整性。

回到Spring Sesurity中,框架提供了PasswordEncoder 接口来实现密码加密。通过不同的实现,来配置不同Hash算法(MD5SHA-256SHA-512等)

但是仅仅通过上面简单的加密依然不能防止恶意用户的攻击,为什么呢?

恶意用户会预先计算很多密码的加密结果,保存到“表”里。这里的“表”指的就我们常说的彩虹表

当想要破解某个密码时,就会用这个密码去“表”里查找对应的加密结果,如果找到了,就知道这个密码是什么了。

那么SpringSecurity怎么才能防止彩虹表攻击呢?

常用的就是使用盐(Salt)

顾名思义,盐就是给密码加点“料”,每次加密时都加点不同的“料”,这样即使两个用户的密码相同,加密后的结果也会因为盐的不同而不同。

Spring Security可以通过配置密码编码器(如BCryptPasswordEncoder)来自动为每个密码生成一个唯一的盐来保证安全。

三、密码加密测试

上面说了一堆理论知识,接下来我们来测试下通过BCryptPasswordEncoder 来加密

@Test
public void testPasswordEncoder(){
BCryptPasswordEncoder encoder = new BCryptPasswordEncoder();
//明文都是xiezhr,但是每次生成的密文是不一致的
String ret1 = encoder.encode("xiezhr");
String ret2 = encoder.encode("xiezhr");
System.out.println("第一次生成密码:"+ret1);
System.out.println("第二次生成密码:"+ret2); Assert.isTrue(encoder.matches("xiezhr", ret1), "密码不一致");
Assert.isTrue(encoder.matches("xiezhr", ret2), "密码不一致"); }
//输出
第一次生成密码:$2a$10$96WLiLGkHOcxYNw9wWHDeuXYVznW30S7F5u4Stib71gFp3Mq/mENa
第二次生成密码:$2a$10$f1JowhAXqYI1UBF4jRY5AeziL/83NRzWfvUtxoXzgW0xUQ/uLLUWK
//这里并没有抛出密码不一致的异常

从上面测试中,我们可以看出,相同明文"xiezhr" 通过BCrypt算法加密后,每次生成的密文都是不同的。

再通过matches 来验证两次生成的密文,都与“xiezhr” 匹配

四、添加新用户

在前面的学习中,我们知道了怎么进行密码加密,接下来,该轮到实操了。

我们要实现将一个用户添加到数据库中,并且密码进行加密。

4.1 替换默认密码加密方式

Spring Security中默认使用的PasswordEncoder要求数据库中的密码格式为:{id}password 。它会根据id去判断密码的

加密方式 ,所以我们之前数据库中存储的密码为{bcrypt}$2a$10$GRLdNijSQMUvl/au9ofL.eDwmoohzzS7.rmNSJZ.0FxO/BTk76klW

但是我们一般不会采用这种方式。所以就需要替换PasswordEncoder默认实现方式。

我们一般使用SpringSecurity为我们提供的BCryptPasswordEncoder

怎么替换呢?其实非常简单

我们只需要使用把BCryptPasswordEncoder对象注入Spring容器中,SpringSecurity就会使用该PasswordEncoder来进行密码校验。

@Configuration  //标明这个类为配置类,spring应用程序一启动,类中的been 就会被初始化在spring容器中
@EnableWebSecurity //开启spring security 自定义配置
public class WebSecurityConfig { @Bean
public PasswordEncoder passwordEncoder(){
return new BCryptPasswordEncoder();
} }

4.2 Controller

添加addUser 方法,用于接收前台传过来的用户信息。这里省略了上一节的代码

@RestController
@RequestMapping("/user")
public class UserController { @Autowired
private UserService userService; @PostMapping("/addUser")
public int addUser(@RequestBody User user){
return userService.addUser(user);
}
}

4.3 Service

由于要对前台传过来的密码进行加密处理,我们这里需要单独添加addUser 单独处理密码,具体方法如下

1、UserService

public interface UserService extends IService<User> {
int addUser(User user);
}

2、UserServiceImpl

@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService { @Autowired
PasswordEncoder passwordEncoder;
@Autowired
UserMapper userMapper; @Override
public int addUser(User user) {
String encode = passwordEncoder.encode(user.getPassword());
user.setPassword(encode);
user.setEnabled(true);
return userMapper.insert(user);
}
}

4.4 测试一下

到了这里,小伙伴是不是觉得已经大功告成了,我们来用postman工具测试一下

哦豁,报401 Unauthorized了,这是为啥呢?

我们要对/user/addUser 进行放行

@Configuration  //标明这个类为配置类,spring应用程序一启动,类中的been 就会被初始化在spring容器中
@EnableWebSecurity //开启spring security 自定义配置
public class WebSecurityConfig {
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception { http.csrf(csrf-> csrf.disable());
http.authorizeHttpRequests(auth -> auth
.requestMatchers("/user/addUser").permitAll()
.anyRequest().authenticated()
); return http.build();
}
}

添加上面代码之后,再用postman测试,用户就正常添加进去了

我们再来看看数据库,Jon这个用户已经加进去了,而且密码123456 也是加过密的

五、小结

到此,我们已经将一个新用户添加到数据库中了,并且用户密码也做了加密处理。

以上操作,我们只是为了演示添加用户的基本操作,实际项目中会比这个复杂一些,不过原理都是一样的。

在实际的前后端分离项目中,我们还会涉及到跨域处理、统一返回结果、再插入用户之前判断用户是否存在等等。

小伙伴们,不用着急,后续课程中会慢慢补充~

SpringBoot3整合SpringSecurity6(四)添加用户、密码加密的更多相关文章

  1. {MySQL数据库初识}一 数据库概述 二 MySQL介绍 三 MySQL的下载安装、简单应用及目录介绍 四 root用户密码设置及忘记密码的解决方案 五 修改字符集编码 六 初识sql语句

    MySQL数据库初识 MySQL数据库 本节目录 一 数据库概述 二 MySQL介绍 三 MySQL的下载安装.简单应用及目录介绍 四 root用户密码设置及忘记密码的解决方案 五 修改字符集编码 六 ...

  2. Maven-009-Nexus 用户密码加密(安全必须)

    信息数据大爆发的时代,我们关心什么?没错,数据安全!数据安全!数据安全!(重要事情说三遍,哈哈哈...) 之前我们存放在 maven settings.xml 文件中的 Nexus 私服用户密码都是明 ...

  3. 如何基于Security框架兼容多套用户密码加密方式

    一.说明 当已上线的系统存在使用其他的加密方式加密的密码数据,并且密码 不可逆 时,而新的数据采用了其他的加密方式,则需要同时兼容多种加密方式的密码校验. 例如下列几种情况: 旧系统用户的密码采用了 ...

  4. C#:使用MD5对用户密码加密与解密

    C#中常涉及到对用户密码的加密于解密的算法,其中使用MD5加密是最常见的的实现方式.本文总结了通用的算法并结合了自己的一点小经验,分享给大家. 一.使用16位.32位.64位MD5方法对用户名加密 1 ...

  5. Cognos权限认证CJP方式之用户密码加密

    在项目开发过程中,用户往往对系统的安全都有明确的要求,下面针对cognos门户认证用户密码如何加密来提供一个简单的wf 1Cognos权限认证方式:CJP 2Cognos用户数据库类型:Oracle ...

  6. c# 对用户密码加密解密

    一.使用16位.32位.64位MD5方法对用户名加密 1)16位的MD5加密 ? 1 2 3 4 5 6 7 8 9 10 11 12 /// <summary> /// 16位MD5加密 ...

  7. 转 C#:使用MD5对用户密码加密与解密

    C#中常涉及到对用户密码的加密于解密的算法,其中使用MD5加密是最常见的的实现方式.本文总结了通用的算法并结合了自己的一点小经验,分享给大家. 一.使用16位.32位.64位MD5方法对用户名加密 1 ...

  8. DRF项目之实现用户密码加密保存

    在DRF项目的开发中,我们通过直接使用序列化器保存的用户信息时,用户的密码是被明文保存到数据库中. 代码实现: def create(self, validated_data): '''重写creat ...

  9. Openfire用户密码加密解密

    需求要求审核过程中都用匿名进行用户注册登录,注册用户审核通过后才使用openfire内置表 如何做到用户密码统一 Openfire是通过org.jivesoftware.util.Blowfish.j ...

  10. 使用bcrypt进行用户密码加密的简单实现

    Bcrypt百度百科: bcrypt,是一个跨平台的文件加密工具.由它加密的文件可在所有支持的操作系统和处理器上进行转移.它的口令必须是8至56个字符,并将在内部被转化为448位的密钥. 除了对您的数 ...

随机推荐

  1. MySQL - [18] mysql中关于cascade的用法

    drop database语句用于删除数据库.但如果想要删除一个数据库并且还要删除所有依赖于该数据库的存储过程.函数等,可以使用cascade关键字.drop database test cascad ...

  2. MyCat分库分表-练习

    模拟这样一个场景: 1.将数据库按业务"垂直"拆分成用户库和订单库: 2.用户库做主从,读写分离: 3.订单库做"水平"切分,并且每个分片表做主从,读写分离: ...

  3. 分布式锁—4.Redisson的联锁和红锁

    大纲 1.Redisson联锁MultiLock概述 2.Redisson联锁MultiLock的加锁与释放锁 3.Redisson红锁RedLock的算法原理 4.Redisson红锁RedLock ...

  4. 设备管理笔记1-oee

    什么是oee 类似于一种设备管理模型,如软件行业的质量模型.cmmi模型等 指标包括什么? 正常指标应该是多少,目前我们的指标为多少? 制造行业存在的6大问题分别是什么 指标包括什么? 包括 可用性性 ...

  5. Laravel11 从0开发 Swoole-Reverb 扩展包(三) - reverb广播驱动使用流程

    前情提要 我们第一节的时候,已经大致介绍reverb,他 是 Laravel 应用程序的第一方 WebSocket 服务器,可将客户端和服务器之间的实时通信直接带到您的指尖.开源且只需一个 Artis ...

  6. Jupyter Notebook的所有文件ipynb保存下来

    前言 如果你想要保存整个 Jupyter Notebook 工作目录,包括所有笔记本和其他相关文件,最直接的方法是将整个文件夹压缩为一个 ZIP 或 TAR 文件. 下载单个文件 压缩文件夹下载 在 ...

  7. docker build 镜像时,无法访问网络

    前言 在使用 docker build 命令构建 Docker 镜像时遇到无法联网的情况,可能会有多种情况的发生. 检查主机网络设置 检查你的主机是否配置了代理服务器或防火墙,这可能会阻止 Docke ...

  8. wps时间戳转换成日期

    第一步 打开WPS表格,选择空表格 第二步 右击选择"设置单元格格式" 第三步 选择"日期",然后选择需要的日期类型 第四步 然后在表格里,输入公式 =(D2/ ...

  9. V8引擎静态库及其调用方法

    V8引擎静态库下载地址由于包含了x86和x64的debug和release静态库,所以资源较大,需要耐心下载. 案例编译工具:VS2019 v8开头的即为V8引擎静态库(附送其它开源静态库libuv. ...

  10. 解决VuePress中的”Error from chokidar : Error: EBUSY“问题

    .title { padding: 10px; background-color: rgba(3, 169, 244, 1); font-size: 16px; color: rgba(255, 25 ...