写在前面

还记得在之前的文章中,我们在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. Idea - 关于mybatis的插件

      idea中配置的mybatis的mapper类和xml文件的图标怎么自动变为mybatis的logo?需要安装什么插件,怎么安装?   在 IntelliJ IDEA 中,要使 MyBatis 的 ...

  2. STM32实战——ESP8266 WIFI模块

    ESP8266 硬件介绍 ESP8266系列模组有哪些: 在本实验中,ESP8266与ESP-01不做区分. ESP-01引脚介绍: 引脚 功能 3.3 3.3V供电,避免使用5V供电 RX UART ...

  3. 【由技及道】API契约的量子折叠术:Swagger Starter模块的十一维封装哲学【人工智障AI2077的开发日志】

    摘要:本文记录一个未来AI如何通过Swagger-Starter组件实现接口文档的维度折叠,让RESTful接口规范成为跨越时空的永恒契约. 动机:契约精神的量子困境 "一个软件?无外乎支持 ...

  4. 抓包分析:wireshark抓不到TLS1.3数据包中证书的解决方案

    近日工作中遇到需要分析使用TLS1.3协议进行通信的数据包的情况,但使用wireshark进行分析发现不能抓到服务端证书,感到诧异遂设法解决 这篇博客给出解决方案,和简单的原理分析 解决方案: 第一步 ...

  5. 查看当前linux占用的端口号

    Linux 查看端口占用情况可以使用 lsof 和 netstat 命令. centos 下无法使用lsof命令:"-bash: lsof: command not found"1 ...

  6. JDK各个版本发布时间和版本名称

    版权 版本 名称 发行日期 JDK 1.0 Oak(橡树) 1996-01-23 JDK 1.1   1997-02-19 JDK 1.1.4 Sparkler(宝石) 1997-09-12 JDK ...

  7. 多态的前提--java进阶day02

    1.多态的前提条件 第一点和第二点都很好理解,第三点父类引用指向子类对象是什么意思?以下图进行讲解 我们以前的写法,如下图,叫做子类引用指向子类 那父类引用呢?就是把左边换成父类Animal即可 因为 ...

  8. 多态的引入--java进阶day02

    1.多态的介绍 总的来说就是一句话,使用多态,所有的子类都可以根据父类这个桥梁来连接它们各自的成员方法,从而调用方法,减少多次的代码重写,使代码更加简单便捷 我们以之前说的公司写业务为例子来理解多态, ...

  9. 大量数据topk-分桶+堆+多路并归解决方案

    利用分桶.堆与多路归并解决 TopK 问题:结果处理阶段解析 在处理大规模数据时,TopK 问题是一个常见且具有挑战性的任务,即从海量数据中找出最大(或最小)的 K 个元素.为了高效地解决这个问题,我 ...

  10. MySQL 中的 MVCC 是什么?

    MySQL 中的 MVCC 是什么? MVCC(Multi-Version Concurrency Control) 是 MySQL 数据库用来处理并发访问的技术,特别是在 InnoDB 存储引擎中, ...