在Spring项目中使用Maven和BCrypt来实现修改密码功能

news2025/2/24 3:34:08

简介 

在数字时代,信息安全的重要性不言而喻,尤其当涉及到个人隐私和账户安全时。每天,无数的用户登录各种在线服务,从社交媒体到银行账户,再到电子邮件和云存储服务。这些服务的背后,是复杂的系统架构,其中包含着用户最为敏感的数据——密码。

过去,简单的加密方法和弱密码策略导致了许多严重的数据泄露事件。例如,2013年雅虎(Yahoo)遭遇的大规模数据泄露事件,影响了数十亿的用户账户,部分原因就是由于使用了不够安全的密码存储技术。再如2016年的LinkedIn数据泄露事件,尽管该公司使用了SHA-1散列算法对密码进行了处理,但未加盐的密码散列最终还是被破解,暴露了用户的隐私。

这些事件引发了行业对于密码安全的深刻反思,促使开发者和安全专家寻找更安全的解决方案。BCrypt作为一种适应性强且经过时间考验的密码哈希算法,成为了现代密码安全的基石。它不仅能够有效抵御暴力破解和彩虹表攻击,还能通过增加工作因子来适应未来计算能力的增长。

在本文中,我们将深入探讨如何在Spring项目中利用Maven和BCrypt来实现一个安全的密码修改功能。这不仅仅是关于代码实现的问题,更是一次对密码安全重要性的重申,以及对如何在实际应用中践行这一原则的示范。我们将从环境搭建开始,逐步构建出一个既实用又安全的密码修改流程,确保即使在最恶劣的情况下,用户的密码也能得到妥善保护。

通过本文的学习,你将获得宝贵的实践经验,了解如何在自己的项目中实施类似的解决方案,从而提升应用的安全性,给用户提供更加安心的在线体验。在接下来的内容中,我们将一步步解析实现过程,从添加依赖到编写核心业务逻辑,直至完成完整的功能测试,确保每一步都遵循最佳的安全实践。

controller(UserController)

/**
     * 修改密码
     */
    @PutMapping("/update/pwd/{id}")
    public Result update(@PathVariable("id") long id, @RequestBody ChangePasswordVo changePasswordVo) {
        try{
           userService.changePassword(changePasswordVo,id);
            return Result.success("修改成功!");

        }catch (Exception e){
            // 捕获异常,获取异常信息
            String message = e.getMessage();
            // 如果修改失败,返回失败的结果,并附带异常信息
            return Result.failed(message);
        }
    }

  1. 注解 @PutMapping("/update/pwd/{id}")

    • @PutMapping 是Spring MVC中的一个注解,用于处理HTTP PUT请求。
    • "/update/pwd/{id}" 是该方法的URL路径。其中 {id} 是一个路径变量,用于接收用户ID。
  2. 方法定义 public Result update(...)

    • 这是一个公开的方法,名为update,返回一个Result对象。
    • Result 很可能是一个自定义的响应类,通常用于封装API的响应结果,包括状态码、消息和数据等。
  3. 方法参数

    • @PathVariable("id") long id:这是从URL路径中提取的id变量。@PathVariable 注解告诉Spring MVC从URL中提取名为id的变量值,并将其转换为long类型。
    • @RequestBody ChangePasswordVo changePasswordVo@RequestBody 注解用于将HTTP请求体中的JSON数据转换为ChangePasswordVo类型的对象。ChangePasswordVo 可能是一个包含旧密码和新密码等信息的DTO(数据传输对象)。
  4. 方法体

    • 首先,它尝试调用 userService.changePassword(changePasswordVo,id);。这里假设userService是一个已经注入的服务类,用于处理与用户相关的业务逻辑。changePassword 方法可能会根据提供的用户ID和密码信息来更新用户的密码。
    • 如果上述操作成功,方法将返回一个表示成功的Result对象,并附带消息“修改成功!”。
    • 如果在更新密码的过程中发生异常(如数据库错误、密码验证失败等),catch 块将捕获该异常,并获取其消息。然后,它返回一个表示失败的Result对象,并附带异常的消息。


entity(VO-ChangePasswordVo)

@Data
public class ChangePasswordVo implements Serializable {

    /**
     * 旧的密码
     */
    private String oldpassword;


    /**
     * 新的密码
     */
    private String newpassword;

}
  1. 注解

    • @Data: 这是一个Lombok库提供的注解。当你添加@Data到类上时,Lombok会自动为这个类生成getter、setter、equals、hashCode和toString方法。这可以大大减少模板代码的数量,使代码更加简洁。
    • implements Serializable: 这表示该类实现了Serializable接口。Serializable是一个标记接口,用于指示一个类的对象可以被序列化。序列化是将对象状态转换为字节流,以便可以将其写入文件或发送到网络上的另一个位置。如果该类或其成员类(如果它们不是基本类型或String数组等)需要被序列化,则必须实现这个接口。
  2. 成员变量

    • private String oldpassword;: 这是一个私有字符串类型的成员变量,用于存储旧的密码。但是,从Java的命名约定来看,变量名应该使用驼峰命名法(camelCase),并且首字母小写。因此,更合适的命名可能是oldPassword
    • private String newpassword;: 同样,这是一个私有字符串类型的成员变量,用于存储新的密码。按照Java的命名约定,它应该被命名为newPassword
  3. 注释

    • 每个成员变量上方都有注释,描述了该变量的用途。这是一个很好的做法,因为它增加了代码的可读性。但是,请注意,这些注释是用中文写的,而在国际项目中,通常建议使用英文注释。

Service


UserService

void changePassword(ChangePasswordVo changePasswordVo, Long id);
  1. 返回类型 (void): 方法前面有一个void关键字,表示这个方法没有返回值。也就是说,当你调用这个方法时,它不会返回任何值或对象。

  2. 方法名 (changePassword): 这是方法的名称,即changePassword。当你想在代码的其他部分调用这个方法时,你会使用这个名字。

  3. 参数:

    • ChangePasswordVo changePasswordVo: 这是方法的第一个参数。

      • ChangePasswordVo: 这是参数的类型。它可能是一个数据传输对象(DTO),用于封装与更改密码相关的数据,如旧密码、新密码等。
      • changePasswordVo: 这是参数的名称。在方法内部,你可以使用这个名称来引用传入的ChangePasswordVo对象。
    • Long id: 这是方法的第二个参数。

      • Long: 这是参数的类型,表示这是一个长整型(64位整数)数据。
      • id: 这是参数的名称。在方法内部,你可以使用这个名称来引用传入的id值。从参数名可以推测,这个id可能表示用户的唯一标识符(如用户ID)。

UserServiceImpl

 @Override
   public void changePassword(ChangePasswordVo changePasswordVo, Long id){
       // 根据id查询用户信息
       User user = userMapper.selectById(id);
       // 判断原密码是否正确
       if(!BCrypt.checkpw(changePasswordVo.getOldpassword(),user.getPassword())){
           throw new RuntimeException("原密码不正确");
       }
       // 设置新密码
       user.setPassword(BCrypt.hashpw(changePasswordVo.getNewpassword(), BCrypt.gensalt()));
       // 调用Mapper的updateById方法更新用户信息
       userMapper.updateById(user);
   }
  1. @Override: 这是一个Java注解,它告诉编译器这个方法是从超类或接口中继承或实现的。使用@Override注解可以确保你正确地重写了父类或接口中的方法,如果没有正确重写(例如方法签名不匹配),编译器会报错。

  2. public void changePassword(ChangePasswordVo changePasswordVo, Long id): 这是方法的声明部分。

    • public:表示这是一个公共方法,可以从任何其他类中被访问。
    • void:表示该方法没有返回值。
    • changePassword:是方法的名称。
    • ChangePasswordVo changePasswordVo 和 Long id:是方法的参数。ChangePasswordVo可能是一个数据传输对象(DTO),用于封装密码更改请求所需的信息(如旧密码和新密码)。id则是用户的唯一标识符。
  3. User user = userMapper.selectById(id);

    • 使用userMapper(可能是MyBatis的Mapper或类似的ORM工具)的selectById方法根据提供的id从数据库中查询用户信息,并将查询到的用户信息存储在user变量中。
  4. if(!BCrypt.checkpw(changePasswordVo.getOldpassword(),user.getPassword())){

    • 使用BCrypt库(一个流行的密码哈希库)的checkpw方法检查用户提供的旧密码(从changePasswordVo中获取)是否与数据库中存储的哈希密码(从查询到的user对象中获取)匹配。
    • 如果不匹配(!BCrypt.checkpw(...)返回true),则执行下面的throw语句。
  5. throw new RuntimeException("原密码不正确");

    • 如果旧密码不正确,则抛出一个RuntimeException,并带有消息“原密码不正确”。调用此方法的代码应该捕获此异常并适当地处理它(例如,向用户显示错误消息)。
  6. user.setPassword(BCrypt.hashpw(changePasswordVo.getNewpassword(), BCrypt.gensalt()));

    • 如果旧密码正确,则使用BCrypt库的gensalt方法生成一个新的随机盐值。
    • 使用这个新盐值和用户提供的新密码(从changePasswordVo中获取)作为参数,调用BCrypthashpw方法生成新的哈希密码。
    • 将这个新的哈希密码设置到user对象的password字段中。
  7. userMapper.updateById(user);

    • 使用userMapperupdateById方法更新数据库中对应id的用户的密码信息。这里假设userMapperupdateById方法会处理将user对象中的更改保存到数据库中的逻辑。

 


测试

先新增一条数据

密码:111

进行修改密码;

id为你新增后的id号

输入字段为我之前定义的字段oldpassword与newpassword

可以看到密码已经被修改

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

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

相关文章

进程间关系

目录 亲缘关系 进程组关系 会话关系 孤儿态进程 亲缘关系 亲缘关系主要体现于父子进程,子进程父进程创建,代码继承于父进程,父进程负责回收,子进程诞生至结束父进程全程参与,这种称为强亲缘关系。 系统开机后&…

企业级数据分析平台合集介绍

企业发展离不开数据分析,数据分析推动着企业运营、决策和战略规划。它正逐步深入到各行各业的核心业务流程中,从传统的金融、零售、制造业扩展到医疗健康、教育、能源等更多领域。企业正通过数据分析平台实现数据资源的最大化利用,推动业务与…

wireshark--流量分析利器

🎼个人主页:金灰 😎作者简介:一名简单的大一学生;易编橙终身成长社群的嘉宾.✨ 专注网络空间安全服务,期待与您的交流分享~ 感谢您的点赞、关注、评论、收藏、是对我最大的认可和支持!❤️ 🍊易编橙终身成长社群&#…

基于微信小程序的课堂考勤系统的设计与实现(论文+源码)_kaic

基于微信小程序的课堂考勤系统的设计与实现 摘 要 在高校教育普及的今天,学生人数日益增多,为保证课堂质量,教师多要在课前进行考勤。因此本设计提出基于微信小程序的课堂考勤系统,增加了定位功能,避免了“假打卡”…

探索大型语言模型LLama 2:原理揭秘与代码实践

一、引言 1.1 大型语言模型的重要性 大型语言模型作为人工智能领域的重要研究方向,近年来取得了显著的成果。这些模型在自然语言处理、机器翻译、对话系统、文本生成等领域展现了强大的能力,为人类带来了诸多便利。大型语言模型的出现,使得…

卓码软件测评:软件功能测试和非功能测试详情介绍

随着信息技术的不断发展,软件在我们日常生活与工作中扮演着越来越重要的角色。然而,软件质量的好坏直接关系到使用者的体验和企业的声誉。在软件开发过程中,功能测试和非功能测试作为保证软件质量的重要手段,受到了越来越多的关注…

web后端--Spring事务管理

事务也要日志配置 !!!!debug前面记得加空格 logging:level:org.springframework.jdbc.support.JdbcTransactionManager: debugrollbackFor 默认情况下,只有出现RunTimeException才会回滚事务,rollbackfor属性用于控制出现何种异常类型,回滚…

Flink内存管理机制

前言 在Flink的后台界面,可以看到整个Flink的内存情况。 如JobManager的内存情况: TaskManager的内存情况 一、Flink内存管理 Flink TaskManager内存组成整体结构图如下: 二、总内存管理 三、JobManager内存管理内存管理 四、TaskManager内…

运算符优先级、赋值运算符、一元运算符、逻辑运算符

运算符优先级 字符串 布尔 null undefined 赋值运算符 一元运算符 逻辑运算符 && 逻辑与 ||逻辑或 ??空值合并运算符 称为空值合并运算符,它是ES6的一个新特性,它的作用是当一个表达式是nul或者undefined时为变量设…

Pip换源使用帮助

PyPI 镜像使用帮助 PyPI 镜像帮助提高包安装的速度,特别是当默认源访问较慢时。镜像每次同步成功后,每隔 5 分钟进行更新,确保镜像内容尽量与官方源保持一致。 pip 临时使用 如果您只想在一次安装中使用镜像,可以使用以下命令&…

嵌入式到底是啥嵌入了啥?

嵌入式系统(Embedded System)是指一个专用的计算机系统,它作为一个装置或系统的一部分被嵌入其中,来实现特定的功能。我收集归类了一份嵌入式学习包,对于新手而言简直不要太棒,里面包括了新手各个时期的学习…

项目比赛经验分享:如何让即兴发言出彩

项目比赛经验分享:如何让即兴发言出彩 前言1. 顺势趁便法2. 词语撮要法3. 起承转合法4. 数字串连法结语 在项目管理和比赛的激烈竞争中,即兴发言往往成为展示个人魅力和团队精神的重要环节。如何在短时间内组织语言,表达清晰、有力的观点&…

Python代码规范!详细说明!

背景 最近在协作开发过程中,遇到了诸多问题。总结下来主要有两点大问题 代码风格不统一,代码习惯问题严峻。系统解耦不清晰,信息传输不清晰。 于是打算针对市面上常见的代码规范进行强调,结果在查看Google python代码规范文档的…

098、Python 通过编程实现发送邮件的方法

要通过Python编程实现发送邮件,首先得先登录自己的发送邮箱对发送进行相关设置。 一、进行发送邮箱相关设置 1、如下图,点击设置->POP3/SMTP/IMAP 2、然后开启POP3/SMTP服务,并获取授权码和SMTP服务器的地址,如下图&#xff…

Dify中HTTP请求节点的常见操作

HTTP节点包括API请求类型(GET、POST、HEAD、PATCH、PUT、DELETE),鉴权类型(无、API-Key基础、API-Key Bearer、API-Key自定义),HEADERS键值设置,PARAMS键值设置,BODY(non…

springboot高校生就业系统-计算机毕业设计源码99877

基于内容过滤算法的高校生就业系统的设计与实现 摘 要 在当今信息时代,学校以学生信息管理为导向,企业以学生就业持续创新为目标。为满足这一需求,设计一款高校生就业信息管理系统至关重要。该系统涵盖了系统用户管理、岗位信息管理、企业展示…

Channel应用示例

本地文件写数据,如果没有文件创建文件 /*** 使用ByteBuffer(缓冲)和FileChannel(通道),将Hello NIO写入到file01.txt文件中* 如果文件不存在创建文件* author hrui* date 2024/7/27 22:27*/ public class NIOFileChannel01 {public static void main(String[] args) throws I…

Vue element ui分页组件示例

https://andi.cn/page/621615.html

7-23学习笔记

一、异常 即程序中一些程序处理不了的特殊情况 Exception 能被程序本身处理( try-catch ), Error 是无法处理的(只能尽量避免)。 1、异常类 Exception 见过的异常 NullPointerException ArrayIndexoutOfBoundException等 String strnull;System.out.println(st…

昇思MindSpore学习入门-静态图高级编程技巧

如何优化编译性能 使用lazy_inline装饰器 神经网络模型的编译过程往往采用默认inline的方式,把层级的代码表达最终展开成一张扁平的计算图,一方面寻求最大的编译优化机会,另一方面也可以简化自动微分以及执行的逻辑。inline后形成的计算图包…