从零开始一个完整的全栈项目(5) - 完成后端User部分并用Postman登录(密码加密)

145 阅读2分钟

因为在上一篇中,项目配置好,完成User部分功能后,测试登录时,出现了无法登录的bug(403),所以代码进行过调试。开始本期之前,建议回到上一篇末尾,将代码重新更新后,测试“无加密(明文)”登录是否可行。然后再开始本章的“密码加密”。


主要做了以下几个修改:

1. 创建了一个工具类来生成加密密码(测试用)。

这个工具类主要用于测试,正式项目可以不加。

package com.quickstore.util;


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

public class PasswordGenerator {
    public static void main(String[] args) {
        BCryptPasswordEncoder encoder = new BCryptPasswordEncoder();
        String rawPassword = "admin123";
        String encodedPassword = encoder.encode(rawPassword);
        System.out.println("Encoded password for '" + rawPassword + "': " + encodedPassword);
    }
}

补充:如果运行时出现无法运行的情况,可以尝试用maven启动。

mvn compile exec:java -Dexec.mainClass="com.quickstore.util.PasswordGenerator"

2. 修改AuthController来使用PasswordEncoder

package com.quickstore.controller;

import com.quickstore.model.User;
import com.quickstore.service.UserService;
import org.springframework.http.ResponseEntity;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequestMapping("/auth")
public class AuthController {

    private final UserService userService;
    private final PasswordEncoder passwordEncoder;

    public AuthController(UserService userService, PasswordEncoder passwordEncoder) {
        this.userService = userService;
        this.passwordEncoder = passwordEncoder;
    }

    @PostMapping("/login")
    public ResponseEntity<String> login(@RequestBody LoginRequest loginRequest) {
        User user = userService.findByUsername(loginRequest.getUsername());
        
        if (user != null && passwordEncoder.matches(loginRequest.getPassword(), user.getPasswordHash())) {
            return ResponseEntity.ok("Login successful");
        }
        
        return ResponseEntity.badRequest().body("Invalid username or password");
    }
}

class LoginRequest {
    private String username;
    private String password;

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }
}

本次主要的修改为:

  1. 在 AuthController 中注入了 PasswordEncoder
  2. 使用passwordEncoder.matches() 方法来验证密码,而不是直接比较字符串

这样,我们就实现了安全的密码验证:

  • 密码在数据库中存储的是加密后的形式
  • 即使数据库被泄露,攻击者也无法知道原始密码
  • 每次登录时,系统会将用户输入的密码加密后与数据库中存储的加密密码进行比较

数据库中的数据为:
username: admin
password_hash: $2a$10$uYL7lHjEgxJZG7U4VfXH0eJeHoogahUowX0q/ymFDFYiQ5W9VniLe

最后运行结果为: image.png

返回200状态,成功!


下一篇将会为“登录”功能添加JWT验证。