写在前面

还记得在之前的文章中,我们在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. 初探PApplet窗口打开方式(Processing程序)

    使用Processing快6年了,是时候回过头来看看它的"main"方法了,也就是它从哪出生的?~~~ 源码学习 ///////////////////////////////// ...

  2. SQL SERVER日常运维巡检系列之-性能

    前言 做好日常巡检是数据库管理和维护的重要步骤,而且需要对每次巡检日期.结果进行登记,同时可能需要出一份巡检报告. 本系列旨在解决一些常见的困扰: 不知道巡检哪些东西 不知道怎么样便捷体检 机器太多体 ...

  3. 注解@Resource与@Autowired的区别

    @Resource @Resource有两个常用属性name.type,所以分4种情况 指定name和type:通过name找到唯一的bean,找不到抛出异常:如果type和字段类型不一致,也会抛出异 ...

  4. .NET 10首个预览版发布:重大改进与新特性概览!

    前言 .NET 团队于2025年2月25日发布博文,宣布推出 .NET 10 首个预览版更新,重点改进.NET Runtime.SDK.Libraries .C#.ASP.NET Core.Blazo ...

  5. 最简单的方式:如何在wsl2上配置CDUA开发环境

    step0:序言 这篇文章可以帮助你以一个最为简单的方式迈出CUDA的第一步,从此一入CUDA深似海,从此头发是路人. 前提:你需要在Windows 11上: 电脑中有nvidia显卡以及驱动,由于w ...

  6. 【Bug记录】node-sass安装失败解决方案

    node-sass 安装失败解决办法 前言 很多小伙伴在安装 node-sass 的时候都失败了,主要的原因是 node 版本和项目依赖的 node-sass 版本不匹配. 解决方案 解决方案:把项目 ...

  7. ssh WARNING: UNPROTECTED PRIVATE KEY FILE!

    前言 在 ssh -i 指定密钥文件 登录时,出现以下报错: Permissions 0644 for 'xxxx' are too open. It is required that your pr ...

  8. go 组合函数 Collection

    我们经常需要程序在数据集上执行操作,比如选择满足给定条件的所有项,或者将所有的项通过一个自定义函数映射到一个新的集合上. 在某些语言中,会习惯使用泛型. Go 不支持泛型,在 Go 中,当你的程序或者 ...

  9. 最新活动 ISS 国际空间站 MAI-75 SSTV活动计划于2020年8月4日至5日

    MAI-75  SSTV活动计划于2020年8月4日和5日举行 8月3日至9日这一周的最后宇航员时间表最近公布了,它显示了定于8月4日和5日进行的MAI-75活动.这是在Space X Demo-2脱 ...

  10. 在Java集合框架中,`Set`接口是一个重要的接口,它表示一个不包含重复元素的集合。常见的`Set`实现类有`HashSet`、`LinkedHashSet`和`TreeSet`。下面是关于`Set`接口的一些基本用法和方法介绍:

    常用实现类 HashSet: 基于哈希表实现,元素无序. 插入.删除.查找操作的时间复杂度为O(1). LinkedHashSet: 继承自HashSet,并使用双向链表来维护元素的插入顺序. 保留元 ...