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

news2024/10/5 13:06:13

上一章我们成功的注册了一个新用户,按照正常逻辑来说,这一章应该是登录了,但是我们也看到了,这数据库保存的居然是明文密码,这谁受得了,这要是用户信息泄露了,这不让人一锅端了啊,还什么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工具类,一个是前台引用的加密插件。

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

LeetCode | 21. 合并两个有序链表

LeetCode | 21. 合并两个有序链表 OJ链接 定义一个新链表&#xff0c;把小的结点尾插到新的链表注意在插入新的链表中&#xff0c;1. 空链表&#xff0c;插入的节点就是链表的头节点和尾结点。2. 非空链表&#xff0c;插入的节点就是链表的新的尾结点&#xff0c;头结点不变…

Lazarus安装和入门资料

azarus-2.2.6-fpc-3.2.2-win64 下载地址 Lazarus 基础教程 - Lazarus Tutorials for Beginners Lazarus Tutorial #1 - Learning programming_哔哩哔哩_bilibili https://www.devstructor.com/index.php?pagetutorials Lazarus是一款开源免费的object pascal语言RAD IDE&…

【Linux权限:系统中的数字锁与安全之门】

1.Linux下的用户 Linux下有两种用户&#xff1a;超级用户&#xff08;root&#xff09;、普通用户。 超级用户&#xff1a;可以再linux系统下做任何事情&#xff0c;不受限制普通用户&#xff1a;在linux下做有限的事情。超级用户的命令提示符是“#”&#xff0c;普通用户的命令…

HashMap 是怎么解决哈希冲突的?

&#xff08;本文摘自mic老师面试文档&#xff09; 常用数据结构基本上是面试必问的问题&#xff0c;比如 HashMap、LinkList、 ConcurrentHashMap 等。 关于 HashMap&#xff0c;有个学员私信了我一个面试题说&#xff1a; “HashMap 是怎么解决哈希冲突 的&#xff1f;” …

Redis极速上手开发手册【Redis全面复习】

文章目录 什么是RedisRedis的特点Redis的应用场景Redis安装部署Redis基础命令Redis多数据库特性Redis数据类型Redis数据类型之stringRedis数据类型之hashRedis数据类型之listRedis数据类型之setRedis数据类型之sorted set案例&#xff1a;存储高一班的学员信息 Redis封装工具类…

DevExpress WinForms桑基图组件,开创大数据流可视化新方式!

界面控件DevExpress WinForms能帮助开发者创建信息丰富的WinForms应用程序&#xff0c;使用其Sankey Diagram&#xff08;桑基图&#xff09;控件&#xff0c;您可以非常轻松地可视化大数据的数据流。 DevExpress WinForms有180组件和UI库&#xff0c;能为Windows Forms平台创…

获奖名单出炉 ,鲲鹏应用创新大赛2023全国总决赛圆满落幕

11月2日&#xff0c;以“数智未来 因你而来”为主题的鲲鹏应用创新大赛2023全国总决赛在四川成都顺利举办。经过长达6个月的层层筛选与激烈角逐&#xff0c;最终从三大赛事、5大赛道中评选出了13个金奖、16个银奖、19个铜奖。 鲲鹏应用创新大赛是面向全球开发者的顶级赛事&…

DxO照片处理工具合集:FilmPack+PureRAW+PhotoLab+ViewPoint中文版

DxO照片处理工具合集是一款强大而全面的图像处理软件&#xff0c;它可以帮助您提升照片的质量&#xff0c;使其更加出色。无论您是一名专业摄影师&#xff0c;还是一个热爱摄影的业余爱好者&#xff0c;DxO照片处理工具合集都能满足您的需求&#xff0c;让您的照片更加出众&…

单元测试框架----UnitTest框架

UnitTest框架核心要点&#xff1a;TestCase(测试用例)、TestSuite(测试套件)、TextTestRunner&#xff08;测试执行器&#xff09;、TextTestResult&#xff08;测试报告&#xff09;、Fixture&#xff08;测试夹具&#xff09; TestSuite 步骤&#xff1a; 步骤1&#xff1a…

git解决冲突的方法。

1、 cherry-pick git fetch ssh://jingyou.caigerrit.transtekcorp.com:29418/leshan refs/changes/23/34123/3 && git cherry-pick FETCH_HEAD2、 文件解冲突&#xff01; 3、 cherry-pick完整。 git cherry-pick --continue4、查看状态。 5、 push。 git push o…

ChatGPT如何管理对话历史?

问题 由于现在开始大量使用ChatGPT对话功能&#xff0c;认识到他在提供启发方面具有一定价值。比如昨天我问他关于一个微习惯的想法&#xff0c;回答的内容还是很实在&#xff0c;而且能够通过他的表达理解自己的问题涉及到的领域是什么。 此外&#xff0c;ChatGPT能够总结对话…

Stable Diffusion:最先进的文本生成图像模型

稳定扩散 生成式 AI 技术正在迅速发展&#xff0c;现在可以简单地根据文本输入生成文本和图像。Stable Diffusion 是一种文本到图像模型&#xff0c;使您能够创建逼真的应用程序。 扩散模型通过学习去除添加到真实图像中的噪声进行训练。这种降噪过程会产生逼真的图像。这些模…

第一章《补基础:不怕学不懂微积分》笔记

微积分包含众多知识点&#xff0c;例如极限概念、求导公式、乘积法则、链式法则、隐函数求导、 积分中值定理、泰勒公式等。其中&#xff0c;研究导数、微分及其应用的部分一般称为微分学&#xff0c;研究不定积分、定积分及其应用的部分一般称为积分学。微分学和积分学统称为微…

增强swagger

<dependency><groupId>org.springdoc</groupId><artifactId>springdoc-openapi-starter-webmvc-ui</artifactId><version>${org.springdoc.version}</version> </dependency> Swagger版本要与springboot 版本对应 2.1.0 -&…

携手武重集团共建新营销一体化平台,助推央企迈向世界一流

党的二十大报告指出&#xff0c;深化国资国企改革&#xff0c;加快国有经济布局优化和结构调整&#xff0c;推动国有资本和国有企业做强做优做大&#xff0c;提升企业核心竞争力&#xff0c;加快建设世界一流企业。 在数字中国建设的新时新征程中&#xff0c;数字化转型赋能央…

引入依赖时,右键能点击进入,运行时报错

引入依赖时&#xff0c;右键能点击进入&#xff0c;运行时报错 一、问题二、解决问题的过程三、解决方式1、排除其中一个依赖的公共包2、升级旧依赖 一、问题 我的问题是这样的&#xff1a;以前引入了阿里云文字识别的依赖&#xff0c;最近要调用视频活体检测的接口&#xff0…

Linux CentOS 8(HTTPS的配置与管理)

Linux CentOS 8&#xff08;HTTPS的配置与管理&#xff09; 目录 一、HTTPS 介绍二、SSL 证书的介绍三、实验配置 一、HTTPS 介绍 HTTPS 在 HTTP 的基础下加入 SSL&#xff0c;SSL 是“Secure Sockets Layer”的缩写&#xff0c;中文为“安全套接层”。因此 HTTPS 是以安全为目…

解决MySQL需要根据特定顺序排序

文章目录 0 写在前面1 问题引入2 问题解决3 写在末尾 0 写在前面 在进行业务需求的时候&#xff0c;不会根据排序去选择数据。例如&#xff0c;在导出的时候数据排序是根据编辑时间去排序的&#xff0c;那么他的主键id会打乱。 假如&#xff1a; 要导出id为 3 &#xff0c;1 &…

Python学习笔记--构造(`__new__`)和初始化(`__init__`)

二、构造(__new__)和初始化(__init__) 通过之前的学习&#xff0c;我们已经知道定义一个类时&#xff0c;我们经常会通过 __init__(self) 的方法在实例化对象的时候&#xff0c;对属性进行设置。 比如下面的例子&#xff1a; #!/usr/bin/env python3 # -*- coding: UTF-8 -*…

WordPress页脚配置备案号

进入后台管理页面 后台管理页面地址一般是&#xff1a;域名/wp-admin 在指定位置加入代码 点击外观 -> 主题文件编辑器 在右侧的文件中选择 footer.php,[注意&#xff1a;上方的主题需要是你自己选择的对应的主题]在 </footer>标签这一行的上一行中加入代码 <di…