密码加密之Spring Boot实现哈希密码

在当今的数字化世界中,保护用户数据安全是至关重要的。在本文中,我们将探讨如何在Spring Boot后端中实现密码加密,并且给出前端参考代码。 

密码加密的重要性

在用户认证系统中,密码的安全存储是至关重要的。明文存储密码是极其危险的做法,一旦数据库被泄露,用户的密码也会随之暴露。使用强哈希函数对密码进行加密可以大大提高安全性。

后端实现
1. 工具类
package com.example.javaee.config;

import org.springframework.security.crypto.bcrypt.BCrypt;

public class BCryptUtil {

/**
* 密码加密
* @param rawPassword 原始密码
* @return 加密后的密码
*/
public static String hashPassword(String rawPassword) {
return BCrypt.hashpw(rawPassword, BCrypt.gensalt());
}

/**
* 验证密码是否匹配
* @param rawPassword 原始密码
* @param hashedPassword 加密后的密码
* @return 密码是否匹配
*/
public static boolean checkPassword(String rawPassword, String hashedPassword) {
return BCrypt.checkpw(rawPassword, hashedPassword);
}
}
2.登陆注册方法
package com.example.javaee.service;

import com.example.javaee.config.JwtUtil;
import com.example.javaee.entity.Response;
import com.example.javaee.entity.User;
import com.example.javaee.mapper.UserMapper;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.crypto.bcrypt.BCrypt;
import org.springframework.stereotype.Service;
import java.io.IOException;
import java.util.List;
import java.util.Map;

@Service
public class UserService {

    @Autowired
    private UserMapper userMapper;

    public Response login(String account, String password) {
        User existingUser = userMapper.findByUsername(account);
        if (existingUser != null && existingUser.checkPassword(password)) {
            String token = JwtUtil.generateToken(account);
            String permission = existingUser.getPermission();
            return new Response("登录成功", token, permission);
        }
        return new Response("登录失败", null, null);
    }
    public String register(String username, Integer studentId, String password) {
        // 检查用户名是否已存在
        User existingUser = userMapper.findByUsername(username);
        if (existingUser != null) {
            return "注册失败,用户名已存在";
        }
        // 创建新的 User 对象
        User user = new User();
        user.setUsername(username);
        user.setStudentId(studentId);
        // 使用 BCrypt 加密密码
        String encryptedPassword = BCrypt.hashpw(password, BCrypt.gensalt());
        user.setPassword(encryptedPassword);
        // 将新用户插入数据库
        int result = userMapper.insertUser(user);
        if (result > 0) {
            return "注册成功";
        } else {
            return "注册失败";
        }
    }

    public String addUser(String username, String password, String permission, Integer studentId) {
        User user = new User();
        user.setUsername(username);
        // 使用 BCrypt 加密密码
        String encryptedPassword = BCrypt.hashpw(password, BCrypt.gensalt());
        user.setPassword(encryptedPassword);
        user.setPermission(permission);
        user.setStudentId(studentId);
        int i = userMapper.insertUser2(user);
        if (i > 0) {
            return "添加成功";
        } else {
            return "添加失败,用户名已存在";
        }
    }

}
前端实现
1. 登录页面
<template>
  <div id="login">

    <div class="me-login-box me-login-box-radius">
      <h1>登录界面</h1>

      <el-form ref="userForm" :model="userForm" :rules="rules">
        <el-form-item prop="account">
          <div class="my-form1">
            <img src="../assets/img/user.png" id="user-img">
            <input class="my-input" placeholder="用户名" v-model="userForm.account" ref="account" />
          </div>
        </el-form-item>

        <el-form-item prop="password">
          <div class="my-form1">
            <img src="../assets/img/lock.png" id="password-img">
            <input class="my-input" placeholder="密码" type="password" v-model="userForm.password" ref="password"
              @keyup="onHCapitalize($event)" />
            <img src="../assets/img/eyesclosed.png" id="eyes-img" ref="eyes" @click="show()">
          </div>
        </el-form-item>

        <el-form-item size="small" class="me-login-button">
          <el-button type="primary" @click.native.prevent="login('userForm')">登录</el-button>
        </el-form-item>
      </el-form>
    </div>
  </div>
</template>

<script>
import { login } from '../api/api'
import { TOKEN_KEY } from '../router/index'
export default {
  name: 'Login',
  data() {
    return {
      userForm: {
        account: '',
        password: ''
      },
      rules: {
        account: [
          { required: true, message: '用户名不能为空' }
        ],
        password: [
          { required: true, message: '密码不能为空' },
          { min: 6, message: 'password must be at least 6 characters' }
        ]
      },
      flag: 'false',
      bigChar: 'false'
    }
  },

  methods: {
    login(formName) {
      let that = this;
      this.$refs[formName].validate((valid) => {
        if (valid) {
          if (this.userForm.account.trim() !== "" && this.userForm.password.trim() !== "") {
            let params = new URLSearchParams();
            params.append('account', this.userForm.account);
            params.append('password', this.userForm.password);

            login(params)
              .then(function (response) {
                if (response.data.message === '登录成功') {
                  const token = response.data.token;
                  // 存储 Token 到 localStorage
                  localStorage.setItem('authToken', token);
                  // 根据返回的权限进行路由跳转
                  switch (response.data.permission) {
                    case '超级管理员':
                      that.$router.push({ name: 'superadmin' });
                      break;
                    case '普通管理员':
                      that.$router.push({ name: 'admin' });
                      break;
                    case '注册用户':
                      that.$router.push({ name: 'user' });
                      break;
                    default:
                      console.error('未知权限');
                  }
                } else if (responseData.message === '登录失败') {
                  console.error('登录失败,用户名不存在或者密码错误');
                }
              })
              .catch(function (error) {
                console.error(error);
              });
          } else {
            // 验证账号密码是否为空,并设置输入框边框颜色
            if (this.userForm.account.trim() === "") {
              this.$refs.account.style.borderColor = "red";
            } else {
              this.$refs.account.style.borderColor = "#797979";
            }

            if (this.userForm.password.trim() === "") {
              this.$refs.password.style.borderColor = "red";
            } else {
              this.$refs.password.style.borderColor = "#797979";
            }
            return false;
          }
        }
      });
    },
    show() {
      if (this.flag) {
        this.$refs.eyes.src = "../../static/img/eyes.png";
        this.$refs.password.setAttribute("type", "text");
      } else {
        this.$refs.eyes.src = "../../static/img/eyesclosed.png";
        this.$refs.password.setAttribute("type", "password");
      }
      this.flag = !this.flag;
    },
  }
}
</script>

<style>
</style>
2. 注册页面
<template>
    <div id="register">
  
      <div class="me-register-box me-register-box-radius">
        <h1>注册界面</h1>
  
        <el-form ref="registerForm" :model="registerForm" :rules="rules">
  
          <el-form-item prop="username">
            <div class="my-form1">
              <img src="../assets/img/user.png" id="user-img">
              <input class="my-input" placeholder="用户名" v-model="registerForm.username" ref="username" />
            </div>
          </el-form-item>
  
          <el-form-item prop="studentId">
            <div class="my-form1">
              <img src="../assets/img/id.png" id="password-img">
              <input class="my-input" placeholder="学号" v-model="registerForm.studentId" ref="studentId" />
            </div>
          </el-form-item>
  
          <el-form-item prop="password">
            <div class="my-form1">
              <img src="../assets/img/lock.png" id="password-img">
              <input class="my-input" placeholder="密码" type="password" v-model="registerForm.password" ref="password" />
            </div>
          </el-form-item>
  
          <el-form-item size="small" class="me-register-button">
            <el-button type="primary" @click.native.prevent="register('registerForm')">注册</el-button>
          </el-form-item>
  
        </el-form>
  
      </div>
    </div>
  </template>
  
  <script>
  import { registerUser } from '../api/api';
  export default {
    name: 'register',
    data() {
      return {
        registerForm: {
          username: '',
          studentId: '',
          password: ''
        },
        rules: {
          username: [
            { required: true, message: '用户名不能为空!' }
          ],
          studentId: [
            { required: true, message: '学号不能为空!' },
            { min: 9, message: '学号至少由九位组成!' }
          ],
          password: [
            { required: true, message: '密码不能为空!' },
            { min: 6, message: '密码至少由六位组成!' }
          ]
        }
      }
    },
    methods: {
      register(formName) {
        let that = this;

        this.$refs[formName].validate((valid) => {
          if (valid) {
            if (this.registerForm.username.trim() != "" && this.registerForm.password.trim() != "") {
              let params = new URLSearchParams();
              params.append("username", this.registerForm.username);
              params.append("studentId", this.registerForm.studentId);
              params.append("password", this.registerForm.password);
              registerUser(params)
                .then(function (response) {
                  console.log(response);
                  if (response.data === "注册成功") {
                    that.$router.push({ name: "Home" });
                  } else if (response.data === "注册失败") {
                    alert("注册失败,用户名已存在");
                  }
                })
                .catch(function (error) {
                  console.log(error);
                });
            }
          } else {
            if (this.registerForm.username.trim() === "") {
              this.$refs.username.style.borderColor = "red";
            } else {
              this.$refs.username.style.borderColor = "#797979";
            }

            if (this.registerForm.password.trim() === "") {
              this.$refs.password.style.borderColor = "red";
            } else {
              this.$refs.password.style.borderColor = "#797979";
            }
            return false;
          }
        });
      },
    },
  }
  </script>
  
  <style scoped>

  </style>
测试和调试

进行测试是必不可少的,确保密码加密正确无误。

package com.example.javaee;

import com.example.javaee.config.BCryptUtil;
import org.junit.Assert;
import org.junit.Test;
import org.springframework.security.crypto.bcrypt.BCrypt;

public class BCryptUtilTest {

    @Test
    public void testPasswordMatching() {
        // 原始密码
        String rawPassword = "123456";
        // 使用BCryptUtil加密原始密码
        String hashedPassword = BCryptUtil.hashPassword(rawPassword);
        // 打印加密前的密码和加密后的密码
        System.out.println("原始密码: " + rawPassword);
        System.out.println("加密后的密码: " + hashedPassword);
        // 验证原始密码与加密后的密码是否匹配
        boolean isMatch = BCryptUtil.checkPassword(rawPassword, hashedPassword);
        // 打印密码匹配结果
        System.out.println("密码匹配结果: " + isMatch);
        // 断言密码匹配结果为true
        Assert.assertTrue(isMatch);
    }
    
    @Test
    public void testPasswordNotMatching() {
        // 原始密码
        String rawPassword = "123456";
        // 故意使用错误的密码进行测试
        String wrongPassword = "654321";
        // 加密原始密码
        String hashedPassword = BCryptUtil.hashPassword(rawPassword);
        // 打印加密前的密码和加密后的密码
        System.out.println("原始密码: " + rawPassword);
        System.out.println("加密后的密码: " + hashedPassword);
        // 验证错误的密码与加密后的密码是否匹配
        boolean isMatch = BCryptUtil.checkPassword(wrongPassword, hashedPassword);
        // 打印密码匹配结果
        System.out.println("密码匹配结果: " + isMatch);
        // 断言密码匹配结果为false
        Assert.assertFalse(isMatch);
    }
}
结论

保护用户数据是每个开发者的责任,使用哈希密码可以大大降低安全风险。

  • 10
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Spring Boot 是一种用于快速创建 Spring 应用程序的开发框架,而 SQLite 是一款轻量级的嵌入式数据库,它的数据库文件默认为非加密状态。如何将两者相结合并实现 SQLite 加密功能呢? 首先,我们需要在 Spring Boot 中引入 SQLite 的依赖包。在 pom.xml 文件中加入以下代码: ```xml <dependency> <groupId>org.xerial</groupId> <artifactId>sqlite-jdbc</artifactId> <version>3.36.0.3</version> </dependency> ``` 然后,在项目中创建 SQLite 数据库文件,并设置密码。这可以通过在 SQLite 的连接字符串中指定 `PRAGMA key='your_password';` 来实现。 接下来,我们需要在 Spring Boot 中配置 SQLite 的数据源。在 `application.properties` 文件中加入以下配置: ```properties spring.datasource.url=jdbc:sqlite:your_db_file_path spring.datasource.driverClassName=org.sqlite.JDBC spring.datasource.username= spring.datasource.password= ``` 其中,`your_db_file_path` 为 SQLite 数据库文件的路径,`org.sqlite.JDBC` 是 SQLite 的 JDBC 驱动类。由于 SQLite 加密功能由 SQLite 自身实现,因此在数据源配置中不需要设置密码。 最后,在 Spring Boot 代码中,我们需要使用 SQLite JDBC 驱动来连接 SQLite 数据库,并执行加密相关的 SQL 语句。以下是一个示例代码: ```java import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.jdbc.datasource.DriverManagerDataSource; import javax.sql.DataSource; public class SQLiteEncryptor { private static final String DB_FILE_PATH = "your_db_file_path"; private static final String DB_PASSWORD = "your_password"; public static void main(String[] args) { // 创建数据源 DataSource dataSource = createDataSource(DB_FILE_PATH); // 执行加密相关的 SQL 语句 JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource); jdbcTemplate.execute("PRAGMA key='" + DB_PASSWORD + "';"); jdbcTemplate.execute("PRAGMA cipher_compatibility = 3;"); jdbcTemplate.execute("PRAGMA cipher_use_hmac = OFF;"); jdbcTemplate.execute("PRAGMA kdf_iter = 64000;"); // 其它操作... } private static DataSource createDataSource(String dbFilePath) { DriverManagerDataSource dataSource = new DriverManagerDataSource(); dataSource.setDriverClassName("org.sqlite.JDBC"); dataSource.setUrl("jdbc:sqlite:" + dbFilePath); dataSource.setUsername(""); dataSource.setPassword(""); return dataSource; } } ``` 在以上代码中,`createDataSource()` 方法用于创建 SQLite 数据源,而 `main()` 方法中则通过 `JdbcTemplate` 来执行加密相关的 SQL 语句。其中,`PRAGMA key='your_password';` 用于设置密码,`PRAGMA cipher_compatibility = 3;` 和 `PRAGMA cipher_use_hmac = OFF;` 用于指定加密算法和哈希算法,`PRAGMA kdf_iter = 64000;` 则用于指定迭代次数。 综上,通过以上步骤,我们就可以在 Spring Boot实现 SQLite 数据库的加密功能。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值