写点什么

SpringSecurity 如何实现 [加密] 和 [解码]?,程序员 35 岁真的是分水岭吗

作者:MySQL神话
  • 2021 年 11 月 28 日
  • 本文字数:2541 字

    阅读完需:约 8 分钟

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 收集的一些大厂的面试真题


最新整理电子书



最新整理大厂面试文档



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


本文已被CODING开源项目:【一线大厂Java面试题解析+核心总结学习笔记+最新讲解视频+实战项目源码】收录

用户头像

MySQL神话

关注

还未添加个人签名 2021.11.12 加入

还未添加个人简介

评论

发布
暂无评论
SpringSecurity如何实现[加密]和[解码]?,程序员35岁真的是分水岭吗