文章目录

  • 回顾
  • 密码明文会带来什么问题?
  • 如何加密?
    • PasswordEncoder 加密接口
    • 如何配置?
  • 加密的密码在登录的时候是怎么校验的?
  • 默认的加密是什么?
  • DaoAuthenticationProvider 是怎么初始化的?怎么设置用户配置的PasswordEncoder?

回顾

前面我们介绍了spring security的登录验证,涉及到密码的都是明文存储,明文匹配的,这在企业项目开发中是不允许的,要是不小心被客户知道了,会投诉企业,指不定会破产,好了,在阅读本文之前,建议先看我之前的文章,方便更好的理解!

  1. 面试不要在说不熟悉spring security了,一个demo让你使劲忽悠面试官
  2. 循序渐进学习spring security 第二篇,如何修改默认用户?
  3. 循序渐进学习spring security 第三篇,如何自定义登录页面?登录回调?
  4. 循序渐进雪spring security 第四篇,登录流程是怎样的?登录用户信息保存在哪里?
  5. 循序渐进学习spring security 第五篇,如何处理重定向和服务器跳转?登录如何返回JSON串?
  6. 循序渐进学spring security第六篇,手把手教你如何从数据库读取用户进行登录验证,mybatis集成
  7. 循序渐进学spring security 第七篇,如何基于用户表和权限表配置权限?越学越简单了

密码明文会带来什么问题?

2011 年 12 月,有人在网络上公开了600 万个 CSDN 用户资料的数据库,数据全部为明文储存,包含用户名、密码以及注册邮箱。事件发生后 CSDN 在微博、官方网站等渠道发出了声明,解释说此数据库系 2009 年备份所用,因不明原因泄露,已经向警方报案,后又在官网发出了公开道歉信。在接下来的十多天里,金山、网易、京东、当当、新浪等多家公司被卷入到这次事件中。整个事件中最触目惊心的莫过于 CSDN 把用户密码明文存储,由于很多用户是多个网站共用一个密码,因此一个网站密码泄露就会造成很大的安全隐患。由于有了这么多前车之鉴,我们现在做系统时,密码都要加密处理。

2018年,我在一家专门做户外平台的企业工作,该企业主要是做户外活动平台,用户量有300万+,进入公司一段时间后,发现了一个重要秘密,用户的密码竟然是明文存储在数据库中的!这是多少危险的事情啊,万一被不怀好意的人把密码泄漏出去,指不定会做出来什么坏事!可能会让客户倾家荡产,客户倾家荡产,这家公司还能平安无事吗?

而作为开发工程师,在企业项目开发中,也许你不是项目的负责人,但是确实执行人,如果出现密码明文泄漏了,企业被投诉,会不找你来背锅吗?到时只能吃哑巴亏了

如何加密?

密码加密一般会用到散列函数,又称散列算法、哈希函数,这是一种从任何数据中创建数字“指纹”的方法。散列函数把消息或数据压缩成摘要,使得数据量变小,将数据的格式固定下来,然后将数据打乱混合,重新创建一个散列值。散列值通常用一个短的随机字母和数字组成的字符串来代表。好的散列函数在输入域中很少出现散列冲突。在散列表和数据处理中,不抑制冲突来区别数据,会使得数据库记录更难找到。我们常用的散列函数有 MD5 消息摘要算法、安全散列算法(Secure Hash Algorithm)。

仅仅使用散列函数还不够,为了增加密码的安全性,一般在密码加密过程中还需要加盐,所谓的盐可以是一个随机数也可以是用户名,加盐之后,即使密码明文相同的用户生成的密码密文也不相同,这可以极大的提高密码的安全性。但是传统的加盐方式需要在数据库中有专门的字段来记录盐值,这个字段可能是用户名字段(因为用户名唯一),也可能是一个专门记录盐值的字段,这样的配置比较繁琐。

Spring Security 提供了多种密码加密方案,官方推荐使用 BCryptPasswordEncoder,BCryptPasswordEncoder 使用 BCrypt 强哈希函数,开发者在使用时可以选择提供 strength 和 SecureRandom 实例。strength 越大,密钥的迭代次数越多,密钥迭代次数为 2^strength。strength 取值在 4~31 之间,默认为 10。

不同于 Shiro 中需要自己处理密码加盐,在 Spring Security 中,BCryptPasswordEncoder 就自带了盐,处理起来非常方便。

而 BCryptPasswordEncoder 就是 PasswordEncoder 接口的实现类。

PasswordEncoder 加密接口

PasswordEncoder 这个接口中就定义了三个方法

publicinterface PasswordEncoder {String encode(CharSequence rawPassword);boolean matches(CharSequence rawPassword, String encodedPassword);default boolean upgradeEncoding(String encodedPassword) {return false;}
}
  • encode 方法用来对明文密码进行加密,返回加密之后的密文。
  • matches 方法是一个密码校对方法,将用户传来的明文密码和数据库中保存的密文密码作为参数,传入到这个方法中去,根据返回的 Boolean 值判断用户密码是否正确。
  • upgradeEncoding 是否还要进行再次加密,这个一般来说就不用了。

如何配置?

通过前面的文章介绍了密码明文的配置

   @BeanPasswordEncoder passwordEncoder() {return NoOpPasswordEncoder.getInstance();}
``那如果配置加密,自然而然简单了```java@BeanPasswordEncoder passwordEncoder() {return new BCryptPasswordEncoder();}

就这样,就完成了密码按加密来校验了,这里有个前提,密码需要按加密后存储,否则就无法匹配成功

重新使用String encode = new BCryptPasswordEncoder().encode(“123456”); 对密码加密后,将加密串替代数据库的明文秘密,再来登录就OK了


加密的密码在登录的时候是怎么校验的?

Spring Security 中,如果使用用户名/密码的方式登录,密码是在 DaoAuthenticationProvider 中进行校验的,大家可以参考《循序渐进雪spring security 第四篇,登录流程是怎样的?登录用户信息保存在哪里?》


可以看到,密码校验就是通过 passwordEncoder.matches 方法来完成的。

那么 DaoAuthenticationProvider 中的 passwordEncoder 从何而来呢?是不是就是在 SecurityConfig 中配置的那个 Bean 呢?

我们来看下 DaoAuthenticationProvider 中关于 passwordEncoder 的定义,如下:

可以看到DaoAuthenticationProvider 在构造方法中就已经初始化了一个默认的passwordEncoder,如果我们没有配置passwordEncoder,就会用默认的,如果我们配置了passwordEncoder的bean,就用配置的 。

默认的加密是什么?

如果我们不进行任何配置,默认的 PasswordEncoder 也会被提供,那么默认的 PasswordEncoder 是什么呢?

public DaoAuthenticationProvider() {setPasswordEncoder(PasswordEncoderFactories.createDelegatingPasswordEncoder());
}
public class PasswordEncoderFactories {public static PasswordEncoder createDelegatingPasswordEncoder() {String encodingId = "bcrypt";Map<String, PasswordEncoder> encoders = new HashMap<>();encoders.put(encodingId, new BCryptPasswordEncoder());encoders.put("ldap", new org.springframework.security.crypto.password.LdapShaPasswordEncoder());encoders.put("MD4", new org.springframework.security.crypto.password.Md4PasswordEncoder());encoders.put("MD5", new org.springframework.security.crypto.password.MessageDigestPasswordEncoder("MD5"));encoders.put("noop", org.springframework.security.crypto.password.NoOpPasswordEncoder.getInstance());encoders.put("pbkdf2", new Pbkdf2PasswordEncoder());encoders.put("scrypt", new SCryptPasswordEncoder());encoders.put("SHA-1", new org.springframework.security.crypto.password.MessageDigestPasswordEncoder("SHA-1"));encoders.put("SHA-256", new org.springframework.security.crypto.password.MessageDigestPasswordEncoder("SHA-256"));encoders.put("sha256", new org.springframework.security.crypto.password.StandardPasswordEncoder());encoders.put("argon2", new Argon2PasswordEncoder());return new DelegatingPasswordEncoder(encodingId, encoders);}private PasswordEncoderFactories() {}
}

可以看到:

  • 在 PasswordEncoderFactories 中,首先构建了一个 encoders,然后给所有的编码方式都取了一个名字,再把名字做 key,编码方式做 value,统统存入 encoders 中。
  • 最后返回了一个 DelegatingPasswordEncoder 实例,同时传入默认的 encodingId 就是 bcrypt,以及 encoders 实例,DelegatingPasswordEncoder 看名字应该是一个代理对象。

DelegatingPasswordEncoder 有什么作用?
DelegatingPasswordEncoder 也是实现了 PasswordEncoder 接口,所以它里边的核心方法也是两个:encode 方法用来对密码进行编码,matches 方法用来校验密码。
如果我们想同时使用多个密码加密方案,就使用 DelegatingPasswordEncoder 就可以了,而 DelegatingPasswordEncoder 默认还不用配置

DaoAuthenticationProvider 是怎么初始化的?怎么设置用户配置的PasswordEncoder?

再来看看 DaoAuthenticationProvider 是怎么初始化的。

DaoAuthenticationProvider 的初始化是在 InitializeUserDetailsManagerConfigurer#configure 方法中完成的,我们一起来看下该方法的定义:

从这段代码中我们可以看到:

  • 首先去调用 getBeanOrNull 方法获取一个 PasswordEncoder 实例,getBeanOrNull 方法实际上就是去 Spring 容器中查找对象。
  • 接下来直接 new 一个 DaoAuthenticationProvider 对象,大家知道,在 new 的过程中,DaoAuthenticationProvider 中默认的 PasswordEncoder 已经被创建出来了。
  • 如果一开始从 Spring 容器中获取到了 PasswordEncoder 实例,则将之赋值给 DaoAuthenticationProvider 实例,否则就是用 DaoAuthenticationProvider 自己默认创建的 PasswordEncoder。

至此,就真相大白了,我们配置的 PasswordEncoder 实例确实用上了。

总结:本文介绍了加密的重要性,为什么加密,如何加密的相关配置,还介绍了在默认不配置加密的情况下就已经使用加密的方式进行校验,而且是支持多种加密方案的,这一步的操作实验,留给读者自己去尝试吧

循序渐进学spring security 第八篇,如何配置密码加密?是否支持多种加密方案?相关推荐

  1. 实现账号在一端登入_跟我学spring security 基于数据库实现一个基本的登入登出...

    第一章我们基于内存中的用户信息实现了一个基本的登入功能,不过实际的项目中用户信息一般都是存在数据库中的.本章我们来实现一个比较接近真实项目的登入登出,同时引入UserDetailsService的概念 ...

  2. springboot集成Spring Security oauth2(八)

    由于公司项目需要,进行SpringBoot集成Spring Security oauth2,几乎搜寻网上所有大神的案例,苦苦不能理解,不能完全OK. 以下是借鉴各大神的代码,终于demo完工,请欣赏 ...

  3. 跟我学spring security系列文章第一章 实现一个基本的登入

    文章目录 指定依赖 安全配置 添加controller测试代码 测试 源码地址: https://github.com/pony-maggie/spring-security-learn 指定依赖 s ...

  4. Spring Cloud第八篇:Spring Cloud Bus刷新配置

    Spring Cloud Bus 将分布式的节点用轻量的消息代理连接起来.它可以用于广播配置文件的更改或者服务之间的通讯,也可以用于监控.本文要讲述的是用Spring Cloud Bus实现通知微服务 ...

  5. Spring Security 进阶干货:自定义配置类入口WebSecurityConfigurerAdapter

    1. 前言 今天我们要进一步的的学习如何自定义配置 Spring Security 我们已经多次提到了 WebSecurityConfigurerAdapter ,而且我们知道 Spring Boot ...

  6. Spring Security过滤器就该这么配置!

    大家好,我是推干货的DD! 今早看到小胖哥更新干货了,关注Spring Security的小伙伴,不可以错过这篇哦! 以前胖哥带大家用Spring Security过滤器实现了手机验证码认证,今天我们 ...

  7. Spring Security 实战干货:自定义配置类入口 WebSecurityConfigurerAdapter

    点击上方蓝色"程序猿DD",选择"设为星标" 回复"资源"获取独家整理的学习资料! 1. 前言 今天我们要进一步的的学习如何自定义配置 Sp ...

  8. Spring Security 之集群Session配置

    1.   新建Maven项目 cluster-session 2.   pom.xml <project xmlns="http://maven.apache.org/POM/4.0. ...

  9. Spring Security入门(三):密码加密

    前文导读 - Spring Security入门(一):登录与退出 - Spring Security入门(二):基于数据库验证 Github 地址 https://github.com/ChinaS ...

最新文章

  1. 云计算学习(4-1)虚拟化技术
  2. web项目通过ajax提交数据太大报错
  3. Android之category
  4. pandas操作sql数据库
  5. 中枪!这才是当代博士生真实日常大赏
  6. 电力系统服务器故障预案,电网预案推演系统及电网预案推演方法
  7. 小程序下载到手机后的目录。
  8. 软件工程之软件维护与再工程
  9. Tableau画图初学者~新手教程~常见类型图
  10. matlab绘制均匀b样条曲线,MATLAB绘制B样条曲线
  11. 多卡聚合路由器在视频可视化指挥调度的解决方案
  12. mos管的rc吸收电路计算_RC阻容吸收计算公式
  13. C语言|控制台小游戏|打飞机(基础功能版)
  14. iOS打开应用提示未受信任的企业级开发者
  15. [深入研究4G/5G/6G专题-56]: L3信令控制-5-无线承载DRB管理
  16. 关于测试架构师的解读
  17. 完美国际服务器管理修改经验倍数,魔兽地图编辑问题--修改经验倍数
  18. 论文笔记Long_Term_Feature_Bank
  19. 《自学大全》—营造学习氛围
  20. dnf辅助新手制作_网络辅助功能的新手介绍

热门文章

  1. 多目标跟踪MOT入门
  2. 2022年我在梦想清单里又加了3条
  3. Docker 容器仓库之搭建私有仓库、hub仓库
  4. 微阵列数据分析(Microarray data analysis)
  5. 阿里云服务器选择不同地域有什么区别
  6. leng dw $ -string汇编语言
  7. 从零基础到导入运行Java版坦克大战游戏项目 第一节(Java JDK的下载安装配置)
  8. 数据库的基本概念-基础(课堂笔记)
  9. 使用CRM客户关系管理系统的好处有哪些?
  10. 【ESP32】【乐鑫发布 AI 语音麦克风阵列开发板 ESP32-Korvo】