1. 新建项目

1.1 新建并启动项目

新建 Spring Boot 项目,添加 Spring Web 和 Spring Security 依赖:

其中 Spring Security 依赖中主要的是这两个:

项目创建成功后,添加一个测试接口:

package com.javaboy.vms;import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;/*** @author: gaoyang* @date: 2021-04-14 17:47* @description: 启动类*/
@SpringBootApplication
public class VmsServerApplication {public static void main(String[] args) {SpringApplication.run(VmsServerApplication.class, args);}}

然后启动项目:

我们可以在控制台看到一串UUID,这个就是 Spring Security默认的登录密码,默认用户名是:user。

登录以后我们就可以看到返回的数据了。

在 Spring Security 中,默认的登录页面和登录接口,都是 /login ,只不过一个是 get 请求(登录页面),另一个是 post 请求(登录接口)。

1.2 默认用户名和密码是如何生成的

和用户相关的自动化配置类在 UserDetailsServiceAutoConfiguration 里,在该类的getOrDeducePassword 方法中,我们可以看到打印密码的代码:logger.info()

private String getOrDeducePassword(User user, PasswordEncoder encoder) {String password = user.getPassword();if (user.isPasswordGenerated()) {logger.info(String.format("%n%nUsing generated security password: %s%n", user.getPassword()));}return encoder == null && !PASSWORD_ALGORITHM_PATTERN.matcher(password).matches() ? "{noop}" + password : password;}

控制台的密码就是从这打印来的,打印的条件是 isPasswordGenerated 方法返回 true,即密码是默认生成的。

获取密码的方法 user.getPassword() 在 SecurityProperties 类中,在 SecurityProperties 中我们可以看到 User 内部类有如下定义:

/*** 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。

2. 用户配置

默认的密码有一个明显的缺陷就是:每次重启密码都会改变,这很不方便,在未连接到数据库以前,我们先来学习一下两种非主流的用户名/密码配置方案,分别为配置文件、配置类。

2.1 配置文件配置用户

我们可以在 application.yml 中配置默认的用户名密码。

spring:security:user:name: javaBoypassword: 123

这里是怎么覆盖默认配置的呢?我可以看到 SecurityProperties 定义是这样的:

@ConfigurationProperties(prefix = "spring.security")
public class SecurityProperties {

而默认的用户就定义在 SecurityProperties 的 User 静态内部类里,并通过 set 方法注入到属性中去:

public void setName(String name) {this.name = name;
}public void setPassword(String password) {if (!StringUtils.hasLength(password)) {return;}this.passwordGenerated = false;this.password = password;
}

从这里我们可以看出,如果传输的密码长度 == 0,则返回,此时用默认生成的 UUID 作为密码;否则,则使用传入的密码,并且把 passwordGenerated 置为 false,此时控制台就不会打印密码了。

再重启项目,就可以用配置好的用户名/密码登录。

2.2 配置类配置用户

先上代码,然后我们再一起解释:

package com.javaboy.vms.config;import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.crypto.password.NoOpPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;/*** @author: gaoyang* @date: 2021-04-15 16:35* @description: Spring Security 配置类*/
@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {@BeanPasswordEncoder passwordEncoder() {return NoOpPasswordEncoder.getInstance();}@Overrideprotected void configure(AuthenticationManagerBuilder auth) throws Exception {auth.inMemoryAuthentication().withUser("javaBoy_1024").password("123").roles("admin");}}
  1. 首先我们自定义 SecurityConfig 继承自 WebSecurityConfigurerAdapter,重写里边的configure 方法。

configure 方法中,我们通过 inMemoryAuthentication 来开启在内存中定义用户,withUser 中是用户名,password 中则是用户密码,roles 中是用户角色。

  1. 提供了一个 PasswordEncoder 的实例,因为目前的案例还比较简单,因此我暂时先不给密码进行加密,所以返回NoOpPasswordEncoder 的实例即可。

PasswordEncoder 中提供了三个方法:

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

3. 密码加密

3.1 密码为什么要加密?

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

这次泄密,也留下了一些有趣的事情,特别是对于广大程序员设置密码这一项。人们从 CSDN 泄密的文件中,发现了一些好玩的密码,例如如下这些:

  • ppnn13%dkstFeb.1st 这段密码的中文解析是:娉娉袅袅十三余,豆蔻梢头二月初。
  • csbt34.ydhl12s 这段密码的中文解析是:池上碧苔三四点,叶底黄鹂一两声

等等不一而足,你会发现很多程序员的人文素养还是非常高的,让人啧啧称奇。

3.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 接口的实现类。

SpringSecurity系列(二) Spring Security入门相关推荐

  1. Spring Data 系列(二) Spring+JPA入门(集成Hibernate)

    通过[Spring Data 系列(一) 入门]的介绍,通过对比的方式认识到Spring提供的JdbcTemplate的强大功能.通过使用JdbcTemplate,操作数据库,不需要手动处理Conne ...

  2. SpringSecurity权限管理框架系列(六)-Spring Security框架自定义配置类详解(二)之authorizeRequests配置详解

    1.预置演示环境 这个演示环境继续沿用 SpringSecurit权限管理框架系列(五)-Spring Security框架自定义配置类详解(一)之formLogin配置详解的环境. 2.自定义配置类 ...

  3. Spring Security 入门(四):自定义-Filter

    前文导读 - Spring Security入门(一):登录与退出 - Spring Security入门(二):基于数据库验证 - Spring Security入门(三):密码加密 本文解决问题 ...

  4. Spring Security入门到实践(一)HTTP Basic在Spring Security中的应用原理浅析

    一.Spring Security简介 打开Spring Security的官网,从其首页的预览上就可以看见如下文字: Spring Security is a powerful and highly ...

  5. Spring Security 入门(五):在 Spring-Boot中的应用

    前言 本文作为入门级的DEMO,完全按照官网实例演示: 项目目录结构 Maven 依赖  <parent>    <groupId>org.springframework.bo ...

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

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

  7. Spring Security入门基础

    Spring Security入门基础 文章目录 Spring Security入门基础 一,Spring Security的使用 1.1 基本术语 1.2 基本使用 1.2.1 引入依赖 1.2.2 ...

  8. 【Spring Security入门】06-QQ登录实现

    准备工作 1.在 QQ互联 申请成为开发者,并创建应用,得到APP ID 和 APP Key. 2.了解QQ登录时的 网站应用接入流程.(必须看完看懂) 为了方便各位测试,直接把我自己申请的贡献出来: ...

  9. springsecurity拦截ajax,Spring Security Ajax 被拦截

    背景是项目中使用Spring Security 进行安全控制 再使用Ajax的时候会报 403(ajax get  方式是没问题的 post 的时候会报) Spring Security 原本是 防止 ...

最新文章

  1. RecyclerView 的findFirstVisibleItemPosition()与findLastVisibleItemPosition()
  2. kafka消息会不会丢失
  3. ASP.NET 应用中大文件上传研究
  4. python3 graphviz入门教程
  5. php实现变声,PHP:用UTF-8字符串中最接近的7位ASCII等效替换变音符号
  6. vue的自定义标签tag是什么意思啊_好好的衣服为什么洗一次就废,服装标签上的图标究竟是什么意思?...
  7. Dataset之BDD100K:BDD100K数据集的简介、下载、使用方法之详细攻略
  8. python 数据分析工具之 numpy pandas matplotlib
  9. service不是内部或者外部命令
  10. sql查询非ascii字符_SQL替换:如何在SQL Server中替换ASCII特殊字符
  11. electron实践(2)
  12. SLAM_视觉SLAM中的一种单目稠密建图方法
  13. 哈希表---开链法解决哈希冲突
  14. px和毫米的换算_px和厘米怎么换算?
  15. html怎么设置字体的背景颜色,html怎样设置字体的背景颜色?
  16. php网站恶意注册表,突破封锁 解决注册表被恶意锁定的方法
  17. 电脑系统服务器丢失怎么办,电脑本地连接不见了,小编教你怎么解决
  18. 【 MySQL1064错误代码】
  19. CSDN问答标签技能树(二) —— 效果优化
  20. 学习C++:C++进阶(三)CMake基础篇---用一个小型项目了解CMake及环境构建

热门文章

  1. codeforces 664B B. Rebus(乱搞题)
  2. 心路历程(四)-我的2015
  3. Byte[]、Image、Bitmap 之间的相互转换
  4. UVA10733 The Colored Cubes【Polya定理】
  5. UVA10285 Longest Run on a Snowboard【DFS+记忆化搜索】
  6. UVA10673 Play with Floor and Ceil【暴力枚举】
  7. URAL1297 Palindrome【manacher算法】
  8. Bailian2797 最短前缀【字典树】
  9. UVA10018 Reverse and Add【回文数+水题】
  10. HDU1013 POJ1519 Digital Roots(解法二)【废除!!!】