SpringSecurity 如何实现 [加密] 和 [解码]?,程序员 35 岁真的是分水岭吗
ppnn13%dkstFeb.1st 这段密码的中文解析是:娉娉袅袅十三余,豆蔻梢头二月初。csbt34.ydhl12s 这段密码的中文解析是:池上碧苔三四点,叶底黄鹂一两声
2. 加密方案
密码加密我们一般会用到散列函数,又称散列算法、哈希函数,这是一种从任何数据中创建数字“指纹”的方法。散列函数把消息或数据压缩成摘要,使得数据量变小,将数据的格式固定下来,然后将数据打乱混合,重新创建一个散列值。散列值通常用一个短的随机字母和数字组成的字符串来代表。好的散列函数在输入域中很少出现散列冲突。在散列表和数据处理中,不抑制冲突来区别数据,会使得数据库记录更难找到。我们常用的散列函数有 MD5 消息摘要算法、安全散列算法(Secure Hash Algorithm)。
但是仅仅使用散列函数还不够,为了增加密码的安全性,一般在密码加密过程中还需要加盐,所谓的盐可以是一个随机数也可以是用户名,加盐之后,即使密码明文相同的用户生成的密码密文也不相同,这可以极大的提高密码的安全性。但是传统的加盐方式需要在数据库中有专门的字段来记录盐值,这个字段可能是用户名字段(因为用户名唯一),也可能是一个专门记录盐值的字段,这样的配置比较繁琐。
Spring Security 提供了多种密码加密方案,官方推荐使用 BCryptPasswordEncoder,BCryptPasswordEncoder 使用 BCrypt 强哈希函数,开发者在使用时可以选择提供 strength 和 SecureRandom 实例。strength 越大,密钥的迭代次数越多,密钥迭代次数为 2^strength。strength 取值在 4~31 之间,默认为 10。
不同于 Shiro 中需要自己处理密码加盐,在 Spring Security 中,BCryptPasswordEncoder 就自带了盐,处理起来非常方便。
而 BCryptPasswordEncoder 就是 PasswordEncoder 接口的实现类。
3. PasswordEncoder
二、前期准备
首先新建一个 Spring Boot 项目,创建时引入 Spring Security 依赖和 web 依赖,如下图:

项目创建成功后,Spring Security 的依赖就添加进来了,在 Spring Boot 中我们加入的是 spring-boot-starter-security ,其实主要是这两个:

项目创建成功后,我们添加一个测试的 HelloController,内容如下:
@RestControllerpublicclass HelloController {@GetMapping("/hello")public String hello() {return"hello";}}
接下来什么事情都不用做,我们直接来启动项目。
在项目启动过程中,我们会看到如下一行日志:
Using generated security password: 30abfb1f-36e1-446a-a79b-f70024f589ab
这就是 Spring Security 为默认用户 user 生成的临时密码,是一个 UUID 字符串。
接下来我们去访问 http://localhost:8080/hello 接口,就可以看到自动重定向到登录页面了:

在登录页面,默认的用户名就是 user,默认的登录密码则是项目启动时控制台打印出来的密码,输入用户名密码之后,就登录成功了,登录成功后,我们就可以访问到 /hello 接口了。
在 Spring Security 中,默认的登录页面和登录接口,都是 /login ,只不过一个是 get 请求(登录页面),另一个是 post 请求(登录接口)。
大家可以看到,非常方便,一个依赖就保护了所有接口
有人说,你怎么知道知道生成的默认密码是一个 UUID 呢?
这个其实很好判断。 和用户相关的自动化配置类在 UserDetailsServiceAutoConfiguration 里边,在该类的 getOrDeducePassword 方法中,我们看到如下一行日志:
if (user.isPasswordGenerated()) {logger.info(String.format("%n%nUsing generated security password: %s%n", user.getPassword()));}
毫无疑问,我们在控制台看到的日志就是从这里打印出来的。打印的条件是 isPasswordGenerated 方法返回 true,即密码是默认生成的。
进而我们发现,user.getPassword 出现在 SecurityProperties 中,在 SecurityProperties 中我们看到如下定义:
/**
Default user name./private String name = "user";/*
Password for the default user name.*/private String password = UUID.randomUUID().toString();private boolean passwordGenerated = true;
可以看到,默认的用户名就是 user,默认的密码则是 UUID,而默认情况下,passwordGenerated 也为 true。
二、用户配置
默认的密码有一个问题就是每次重启项目都会变,这很不方便。
在正式介绍数据库连接之前,先和大家介绍两种非主流的用户名/密码配置方案。
1. 配置文件
我们可以在 application.properties 中配置默认的用户名密码。
怎么配置呢?上面说的 SecurityProperties,默认的用户就定义在它里边,是一个静态内部类,我们如果要定义自己的用户名密码,必然是要去覆盖默认配置,我们先来看下 SecurityProperties 的定义:
@ConfigurationProperties(prefix = "spring.security")publ
《一线大厂 Java 面试题解析+后端开发学习笔记+最新架构讲解视频+实战项目源码讲义》
【docs.qq.com/doc/DSmxTbFJ1cmN1R2dB】 完整内容开源分享
icclass SecurityProperties {}
这就很清晰了,我们只需要以 spring.security.user 为前缀,去定义用户名密码即可:
spring.security.user.name=yolospring.security.user.password=123
这就是我们新定义的用户名密码。
在 properties 中定义的用户名密码最终是通过 set 方法注入到属性中去的,这里我们顺便来看下 SecurityProperties.User#setPassword 方法:
public void setPassword(String password) {if (!StringUtils.hasLength(password)) {return;}this.passwordGenerated = false;this.password = password;}
从这里我们可以看到,application.properties 中定义的密码在注入进来之后,还顺便设置了 passwordGenerated 属性为 false,这个属性设置为 false 之后,控制台就不会打印默认的密码了。
此时重启项目,就可以使用自己定义的用户名/密码登录了。
2. 配置类
除了上面的配置文件这种方式之外,我们也可以在配置类中配置用户名/密码。
最后
针对最近很多人都在面试,我这边也整理了相当多的面试专题资料,也有其他大厂的面经。希望可以帮助到大家。
最新整理面试题
![]()
上述的面试题答案都整理成文档笔记。也还整理了一些面试资料 &最新 2021 收集的一些大厂的面试真题
最新整理电子书

最新整理大厂面试文档

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。
评论