Spring Security使用总结五,加密用户密码,不再使用明文保存密码

上一章我们成功的注册了一个新用户,按照正常逻辑来说,这一章应该是登录了,但是我们也看到了,这数据库保存的居然是明文密码,这谁受得了,这要是用户信息泄露了,这不让人一锅端了啊,还什么security。这一章主要就是讲加密的。

加密也分为两个部分,第一部分是前台密码的加密,第二部分是后台对密码的加密,这第一部分也是需要后台进行协助的,因为security自带了很多的加密方式,这次就使用BCryptPasswordEncoder的加密方式,而前台密码加密就使用RSA的加密方式,RSA需要有一个私钥一个公钥,在后台生成这对密钥,然后将公钥传到前台用来给密码加密,然后后台接收加密之后的密码,再用私钥解密,判断两次输入的密码是否一致,然后再用BCryptPasswordEncoder的方式对解密后的密码再次进行加密,存入数据库。

先在后台创建一个RSA解密以及生成秘钥的工具

import org.apache.tomcat.util.codec.binary.Base64;

import javax.crypto.Cipher;
import java.security.*;
import java.security.spec.PKCS8EncodedKeySpec;

public class RSAUtils {
    public static final String RSA_ECB_PKCS1_PADDING = "RSA/ECB/PKCS1Padding";

    public static final int KEY_SIZE_2048 = 2048;

    private static final String ALGORITHM = "RSA";


    public static KeyPair generateKeyPair() {
        return generateKeyPair(KEY_SIZE_2048);
    }

    public static KeyPair generateKeyPair(int keySize) {
        try {
            KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance(ALGORITHM);
            keyPairGenerator.initialize(keySize);
            return keyPairGenerator.generateKeyPair();
        } catch (NoSuchAlgorithmException e) {
            throw new IllegalArgumentException("Failed to generate key pair!", e);
        }
    }

    public static PrivateKey getPrivateKey(String base64PrivateKey) {
        try {
            PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(Base64.decodeBase64(base64PrivateKey));
            KeyFactory keyFactory = KeyFactory.getInstance(ALGORITHM);
            return keyFactory.generatePrivate(keySpec);
        } catch (Exception e) {
            throw new IllegalArgumentException("Failed to get private key!", e);
        }
    }

    public static String decrypt(byte[] data, PrivateKey privateKey) {
        try {
            Cipher cipher = Cipher.getInstance(RSA_ECB_PKCS1_PADDING);
            cipher.init(Cipher.DECRYPT_MODE, privateKey);
            return new String(cipher.doFinal(data));
        } catch (Exception e) {
            throw new IllegalArgumentException("Decrypt failed!", e);
        }
    }

    public static String decrypt(String data, String base64PrivateKey) {
        return decrypt(Base64.decodeBase64(data), getPrivateKey(base64PrivateKey));
    }

}

在RegistryController将代码修改为如下所示:

@Controller
public class RegisterController {

    @Resource
    RegisterService registerService;

    private static final KeyPair keyPair = RSAUtils.generateKeyPair();

    private static final String privateKey = Base64.encodeBase64String(keyPair.getPrivate().getEncoded());

    @RequestMapping("/register")
    public String register(Model model){
        String publicKey = Base64.encodeBase64String(keyPair.getPublic().getEncoded());
        model.addAttribute("ssKey",publicKey);
        return "register";
    }

    @ResponseBody
    @PostMapping("/registration")
    public JSONObject registration(@RequestBody RegisterDTO register){
        String decrypt = RSAUtils.decrypt(register.getPassword(), privateKey);
        String confirmDecrypt = RSAUtils.decrypt(register.getConfirmPassword(), privateKey);
        if(!decrypt.equals(confirmDecrypt)){
            return JSONObject.parseObject("两次密码不一致");
        }
        return registerService.register(register.getName(),decrypt);
    }
}

前台的代码修改如下所示,添加一条引用,将密码等信息在发送时加密:

<script type="text/javascript" th:src="@{/static/js/encrypt.js}"></script>
<script type="text/javascript">

    const encrypt = new JSEncrypt();
    const ssKey = "[[${ssKey}]]";
    encrypt.setPublicKey(ssKey);

    $(function() {
        $("#register").click(function(){
            $.ajax({
                type: "POST",
                dataType: "json",
                url: 'http://localhost:8080/registration',
                contentType: "application/json",
                data:JSON.stringify({
                    "name": $("#name").val(),
                    "password": encrypt.encrypt($("#password").val()),
                    "confirmPassword":encrypt.encrypt($("#confirmPassword").val())
                }),
                success: function (result) {
                    console.log("data is :" + result)
                }
            });
        })
    });
</script>

到此,对于前台向后台传输的密码的加密和解密工作就算是完成了,接下来就是使用security的加密,确保后续的认证工作能够顺利进行下去。上边的加密修改到Controller,接下来的加密就从Service开始,修改RegistryService代码如下所示:

public JSONObject register(String name, String password){
    BCryptPasswordEncoder bCryptPasswordEncoder = new BCryptPasswordEncoder();
    String encodePassword = bCryptPasswordEncoder.encode(password);
    User user = new User();
    user.setName(name).setPassword(encodePassword)
    userRepository.save(user);
    return JSONObject.parseObject("{'userId':"+ userRepository.save(user).getId() +"}");
}

结束,这样密码就算是加密成功了,我来调试一下,看看加密的效果如何:

1.启动项目,访问http://localhost:8080/register ,输入test22,123456

2.在后台打个断点,看看接收到了一个什么玩意儿

 

确实是加密成功了,然后看看解密之后密码是不是123456

3.进入service之后重新加密

 

图里画圈的就是最后存入数据库中的密码,这玩意正常人应该不会用来当密码吧,就是世界记忆大师用这个当密码也得掂量掂量啊。

4.进入数据库里面确认查看

 应该是没有毛病了。

此时的文件结构如下所示

 只多了两个和加密相关的文件,一个是RSA工具类,一个是前台引用的加密插件。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/134851.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Java编程--单例模式(饿汉模式/懒汉模式)/阻塞队列

前言 逆水行舟&#xff0c;不进则退&#xff01;&#xff01;&#xff01; 目录 单例模式 饿汉模式&#xff1a; 懒汉模式&#xff1a; 什么是阻塞队列 什么是高内聚 低耦合 阻塞队列的实现 单例模式 单例模式&#xff08;Singleton Pattern&#xff09;是一种常见…

代码随想录算法训练营第四十八天丨 动态规划part11

123.买卖股票的最佳时机III 思路 这道题目相对 121.买卖股票的最佳时机 (opens new window)和 122.买卖股票的最佳时机II (opens new window)难了不少。 关键在于至多买卖两次&#xff0c;这意味着可以买卖一次&#xff0c;可以买卖两次&#xff0c;也可以不买卖。 接来下我…

(SpringBoot)第五章:SpringBoot创建和使用

文章目录 一&#xff1a;Spring和SpringBoot&#xff08;1&#xff09;Spring已解决和未解决的问题&#xff08;2&#xff09;SpringBoot 二&#xff1a;Spring项目的创建&#xff08;1&#xff09;IDEA创建&#xff08;2&#xff09;网页端创建 三&#xff1a;项目目录介绍及运…

Mac媒体播放器 Fig Player 1.3.7

Fig Player是一款功能强大的多媒体播放器软件&#xff0c;适用于macOS操作系统。它支持广泛的音频和视频格式&#xff0c;如MP3、MP4、AVI、MKV等&#xff0c;并提供了直观易用的用户界面&#xff0c;使用户可以轻松浏览和管理媒体库。 Fig Player具有快速加载和播放媒体文件的…

人机交互——自然语言生成

自然语言生成是让计算机自动或半自动地生成自然语言的文本。这个领域涉及到自然语言处理、语言学、计算机科学等多个领域的知识。 1.简介 自然语言生成系统可以分为基于规则的方法和基于统计的方法两大类。基于规则的方法主要依靠专家知识库和语言学规则来生成文本&#xff0…

用excel计算矩阵的乘积

例如&#xff0c;我们要计算两个矩阵的乘积&#xff0c; 第一个矩阵是2*2的&#xff1a; 1234 第2个矩阵是2*3的&#xff1a; 5697810 在excel中鼠标点到其它空白的地方&#xff0c;用来存放矩阵相乘的结果&#xff1a; 选择插入-》函数&#xff1a; 选中MMULT&#xff0c;…

PHP生成pdf格式准考证带照片完整示范

PDF效果图 PHP生成pdf格式准考证带照片完整示范以某省公务员考试下载的准考证模板为模板参考&#xff0c;故很有参考意义。 环境支持:linux PHP(5.5-7.3)环境,推荐宝塔环境。 基于fpdf.php插件开发&#xff0c;现有模板适合准考证生成并用于查询下载。 现有排版简单:替换data文…

CenterOS 安装 Jira 需求/BUG管理工具

一、Jira 安装配置 1.1 安装 Jira 下载安装包 https://product-downloads.atlassian.com/software/jira/downloads/atlassian-jira-software-9.5.0-x64.bin将下载的安装包上传至服务器中。 创建 jira 安装目录和数据存放目录 mkdir -p /opt/jira/data添加可运行权限 chmo…

RT-Thread构建与配置系统

简述 RT-Thread的构建与配置系统由以下几个部分组成&#xff1a; KConfig&#xff1a;kernel config配置文件&#xff08;提供系统的配置裁剪功能&#xff09;SCons&#xff1a;构建工具env工具&#xff1a;主要提供构建系统所需的各种环境变量以及软件包的管理 Kconfig在R…

【狂神说Java】Mybatis-plus

✅作者简介&#xff1a;CSDN内容合伙人、信息安全专业在校大学生&#x1f3c6; &#x1f525;系列专栏 &#xff1a;【狂神说Java】 &#x1f4c3;新人博主 &#xff1a;欢迎点赞收藏关注&#xff0c;会回访&#xff01; &#x1f4ac;舞台再大&#xff0c;你不上台&#xff0c…

ESP32网络开发实例-将数据保存到InfluxDB时序数据库

将数据保存到InfluxDB时序数据库 文章目录 将数据保存到InfluxDB时序数据库1、InfluxDB介绍与安装3、软件准备4、硬件准备5、代码实现6、InfluxDB数据可视化在本文中,将介绍 InfluxDB 以及如何将其与 ESP32 开发板一起使用。 我们将向展示如何创建数据库桶并将 ESP32 数据发送…

Python读取csv文件并绘制曲线

前言 有时候我们的数据保存在csv文件中&#xff0c;但是想要更加直观的看出数据的好坏&#xff0c;最好利用matplotlib来画出曲线图 数据准备 我的数据格式如下&#xff1a; 在画图时&#xff0c;我需要把第一行去掉 # 去除第一个元素 xdata xdata.drop(xdata.index[0])…

【Dubbo】Dubbo注册中心原理

&#x1f4eb;作者简介&#xff1a;小明java问道之路&#xff0c;2022年度博客之星全国TOP3&#xff0c;专注于后端、中间件、计算机底层、架构设计演进与稳定性建设优化&#xff0c;文章内容兼具广度、深度、大厂技术方案&#xff0c;对待技术喜欢推理加验证&#xff0c;就职于…

工作量证明是解决拜占庭将军问题的唯一办法

号外&#xff1a;教链内参11.10《以太坊反攻》 文 | Oleg Andreev. 2014.5.23. 原标题&#xff1a;Proof That Proof-of-Work is the Only Solution to the Byzantine Generals Problem &#xff08;本文是&#xff09;回复Vlad_Roberto的话&#xff1a;“不&#xff0c;&#…

【SoC基础】DMA的工作原理

&#x1f4e2;&#xff1a;如果你也对机器人、人工智能感兴趣&#xff0c;看来我们志同道合✨ &#x1f4e2;&#xff1a;不妨浏览一下我的博客主页【https://blog.csdn.net/weixin_51244852】 &#x1f4e2;&#xff1a;文章若有幸对你有帮助&#xff0c;可点赞 &#x1f44d;…

PTA_乙级_1086

#include <iostream> #include<string> #include<algorithm> using namespace std;int reverseNum(int n){//将数字n转为字符串string nStrto_string(n);//翻转字符串reverse(nStr.begin(),nStr.end());//转为数字int resstoi(nStr);return res; }int main()…

Python 潮流周刊#26:requests3 的现状

△点击上方“Python猫”关注 &#xff0c;回复“1”领取电子书 你好&#xff0c;我是猫哥。这里每周分享优质的 Python、AI 及通用技术内容&#xff0c;大部分为英文。本周刊开源&#xff0c;欢迎投稿[1]。另有电报频道[2]作为副刊&#xff0c;补充发布更加丰富的资讯。 &#…

【LeetCode刷题-二分查找】--69.x的平方根

69.x的平方根 class Solution {public int mySqrt(int x) {int l 0,r x ,ans -1;while(l < r){int mid (r - l)/2 l;if((long)mid * mid <x){ans mid;l mid 1;}else{r mid - 1;}}return ans;} }

云原生微服务架构及实现技术

云原生是一种技术理念和架构方法&#xff0c;它充分利用云计算的优势&#xff0c;将应用程序和基础设施进行优化&#xff0c;以适应云环境的特性。云原生的设计原则主要包括弹性、韧性、安全性、可观测性、灰度等&#xff0c;旨在让企业在云环境中实现轻量、敏捷、高度自动化的…

webpack提升构建速度

目录 配置优化减少 resolve 的解析把 loader 应用的文件范围缩小减少 plugin 的消耗选择合适的 devtool 使用工具thread-loaderDLLPlugin 流程优化拆分构建步骤拆分项目代码 版本更新总结 前端项目随着时间推移和业务发展&#xff0c;页面可能会越来越多&#xff0c;或者功能和…