从零开始一个完整的全栈项目(13) - 前端密码修改功能的后端实现及Postman测试

185 阅读3分钟

1. 业务逻辑

修改密码包括两种情况:

  1. 用户修改自己的密码:
  • 需要登录后才能修改(安全考虑)
  • 需要提供旧密码(验证身份)
  • 需要提供新密码
  1. 管理员重置用户密码:
  • 不需要旧密码
  • 直接设置新密码
  • 需要管理员权限

2. 后端代码

1. 创建密码修改的DTO

ChangePasswordRequest.java

package com.quickstore.dto;

import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.Size;
import lombok.Data;

@Data
public class ChangePasswordRequest {
    @NotBlank(message = "旧密码不能为空")
    private String oldPassword;

    @NotBlank(message = "新密码不能为空")
    @Size(min = 6, max = 40, message = "新密码长度必须在6-40之间")
    private String newPassword;
} 

ResetPasswordRequest.java

package com.quickstore.dto;

import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.Size;
import lombok.Data;

@Data
public class ResetPasswordRequest {
    @NotBlank(message = "新密码不能为空")
    @Size(min = 6, max = 40, message = "新密码长度必须在6-40之间")
    private String newPassword;
} 

2. 在UserService中添加密码修改方法

package com.quickstore.service;

import com.quickstore.model.User;
import org.springframework.security.core.userdetails.UserDetailsService;
import java.util.List;

public interface UserService extends UserDetailsService {
    User findByUsername(String username);
    User save(User user);
    List<User> findAllUsers();
    User findById(Long id);
    void deleteUser(Long id);
    void changePassword(String username, String oldPassword, String newPassword);
    void resetPassword(Long userId, String newPassword);
} 

3. 在UserServiceImpl中实现这些方法

package com.quickstore.service.impl;

import com.quickstore.model.User;
import com.quickstore.repository.UserRepository;
import com.quickstore.service.UserService;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.security.authentication.BadCredentialsException;

import java.util.Collections;
import java.util.List;

@Service
public class UserServiceImpl implements UserService {

    private final UserRepository userRepository;
    private final PasswordEncoder passwordEncoder;

    public UserServiceImpl(UserRepository userRepository, PasswordEncoder passwordEncoder) {
        this.userRepository = userRepository;
        this.passwordEncoder = passwordEncoder;
    }

    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        User user = findByUsername(username);
        if (user == null) {
            throw new UsernameNotFoundException("User not found with username: " + username);
        }
        return new org.springframework.security.core.userdetails.User(
                user.getUsername(),
                user.getPasswordHash(),
                Collections.singletonList(new SimpleGrantedAuthority("ROLE_" + user.getRole().toUpperCase()))
        );
    }

    @Override
    public User findByUsername(String username) {
        return userRepository.findByUsername(username);
    }

    @Override
    public User save(User user) {
        if (user.getRole() != null) {
            user.setRole(user.getRole().toLowerCase());
        }
        return userRepository.save(user);
    }

    @Override
    public List<User> findAllUsers() {
        return userRepository.findAll();
    }

    @Override
    public User findById(Long id) {
        return userRepository.findById(id).orElse(null);
    }

    @Override
    public void deleteUser(Long id) {
        userRepository.deleteById(id);
    }

    @Override
    public void changePassword(String username, String oldPassword, String newPassword) {
        User user = findByUsername(username);
        if (user == null) {
            throw new UsernameNotFoundException("User not found with username: " + username);
        }

        if (!passwordEncoder.matches(oldPassword, user.getPasswordHash())) {
            throw new BadCredentialsException("Invalid old password");
        }

        user.setPasswordHash(passwordEncoder.encode(newPassword));
        userRepository.save(user);
    }

    @Override
    public void resetPassword(Long userId, String newPassword) {
        User user = findById(userId);
        if (user == null) {
            throw new UsernameNotFoundException("User not found with id: " + userId);
        }

        user.setPasswordHash(passwordEncoder.encode(newPassword));
        userRepository.save(user);
    }
} 

4. 在UserController中添加密码修改端点

package com.quickstore.controller;

import com.quickstore.dto.ChangePasswordRequest;
import com.quickstore.dto.ResetPasswordRequest;
import com.quickstore.dto.UserUpdateRequest;
import com.quickstore.model.User;
import com.quickstore.service.UserService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.ResponseEntity;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.security.core.Authentication;
import org.springframework.web.bind.annotation.*;

import java.util.List;

@RestController
@RequestMapping("/users")
public class UserController {

    private static final Logger logger = LoggerFactory.getLogger(UserController.class);
    private final UserService userService;

    public UserController(UserService userService) {
        this.userService = userService;
    }

    @GetMapping
    @PreAuthorize("hasRole('ADMIN')")
    public ResponseEntity<List<User>> getAllUsers() {
        logger.info("Attempting to get all users");
        List<User> users = userService.findAllUsers();
        logger.info("Found {} users", users.size());
        return ResponseEntity.ok(users);
    }

    @PutMapping("/{id}")
    @PreAuthorize("hasRole('ADMIN')")
    public ResponseEntity<?> updateUser(@PathVariable Long id, @RequestBody UserUpdateRequest request) {
        logger.info("Attempting to update user with id: {}", id);
        
        User user = userService.findById(id);
        if (user == null) {
            logger.warn("User not found with id: {}", id);
            return ResponseEntity.notFound().build();
        }

        // 更新用户信息
        user.setFullName(request.getFullName());
        user.setRole(request.getRole().toLowerCase());

        // 保存更新
        userService.save(user);
        logger.info("User updated successfully: {}", user.getUsername());

        return ResponseEntity.ok(user);
    }

    @DeleteMapping("/{id}")
    @PreAuthorize("hasRole('ADMIN')")
    public ResponseEntity<?> deleteUser(@PathVariable Long id) {
        logger.info("Attempting to delete user with id: {}", id);
        
        User user = userService.findById(id);
        if (user == null) {
            logger.warn("User not found with id: {}", id);
            return ResponseEntity.notFound().build();
        }

        userService.deleteUser(id);
        logger.info("User deleted successfully: {}", user.getUsername());
        
        return ResponseEntity.ok().build();
    }

    @PostMapping("/change-password")
    public ResponseEntity<?> changePassword(Authentication authentication, @RequestBody ChangePasswordRequest request) {
        String username = authentication.getName();
        logger.info("Attempting to change password for user: {}", username);
        
        try {
            userService.changePassword(username, request.getOldPassword(), request.getNewPassword());
            logger.info("Password changed successfully for user: {}", username);
            return ResponseEntity.ok().build();
        } catch (Exception e) {
            logger.error("Failed to change password for user: {}", username, e);
            return ResponseEntity.badRequest().body(e.getMessage());
        }
    }

    @PostMapping("/{id}/reset-password")
    @PreAuthorize("hasRole('ADMIN')")
    public ResponseEntity<?> resetPassword(@PathVariable Long id, @RequestBody ResetPasswordRequest request) {
        logger.info("Attempting to reset password for user id: {}", id);
        
        try {
            userService.resetPassword(id, request.getNewPassword());
            logger.info("Password reset successfully for user id: {}", id);
            return ResponseEntity.ok().build();
        } catch (Exception e) {
            logger.error("Failed to reset password for user id: {}", id, e);
            return ResponseEntity.badRequest().body(e.getMessage());
        }
    }
} 

后端代码完成。

3. 用Postman进行测试

1. 用户修改自己的密码

1. 用Postman登录(获取token)

如上一篇所示。

2. 用Postman发送请求

     Authorization: Bearer {你的token}
     Content-Type: application/json
  • 请求体:
   {
       "oldPassword": "当前密码",
       "newPassword": "新密码"
   }

3. 运行结果

Header:

image.png Body及结果:

image.png 成功!

验证修改后的密码:

image.png 登录成功!

2. 管理员重置用户密码

1. 用Postman登录(需是有admin权限的管理员)

同其他登录。

2. 用Postman发送请求

 Authorization: Bearer {管理员token}
 Content-Type: application/json
  • 请求体:
{
   "newPassword": "新密码"
}

3. 运行结果

Header:

image.png Body及结果:

image.png 返回200状态,修改成功!

验证修改后的密码:

image.png 登录成功!


至此,密码修改的后端代码完成!


下一篇是密码修改功能的前端页面。