修改登录注册bug,实现用户基本信息修改

master
forely 2 months ago
parent 385b377b10
commit b06a6da7de

@ -2,10 +2,7 @@ package com.luojia_channel.common.config;
import com.luojia_channel.common.interceptor.AuthInterceptor; import com.luojia_channel.common.interceptor.AuthInterceptor;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Configuration;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry; import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
@ -15,16 +12,11 @@ public class WebMvcConfig implements WebMvcConfigurer {
private final AuthInterceptor authInterceptor; private final AuthInterceptor authInterceptor;
@Override @Override
public void addInterceptors(InterceptorRegistry registry) { public void addInterceptors(InterceptorRegistry registry) {
// 登录拦截器 // 拦截器
registry.addInterceptor(authInterceptor) registry.addInterceptor(authInterceptor)
.excludePathPatterns("/user/login", .excludePathPatterns("/user/login",
"/user/register" "/user/register"
); );
} }
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
} }

@ -27,7 +27,7 @@ public final class JWTUtil {
private static final long ACCESS_EXPIRATION = 60 * 60 * 1000; //一小时 private static final long ACCESS_EXPIRATION = 60 * 60 * 1000; //一小时
private static final long REFRESH_EXPIRATION = 60 * 60 * 24 * 15 * 1000; //15天 private static final long REFRESH_EXPIRATION = 60 * 60 * 24 * 15 * 1000; //15天
private static final Long NEED_REFRESH_TTL = 7L; private static final long NEED_REFRESH_TTL = 60 * 60 * 24 * 7 * 1000; //7天
private static final String USER_ID_KEY = "userId"; private static final String USER_ID_KEY = "userId";
private static final String USER_NAME_KEY = "username"; private static final String USER_NAME_KEY = "username";
public static final String TOKEN_PREFIX = "Bearer "; public static final String TOKEN_PREFIX = "Bearer ";
@ -144,7 +144,7 @@ public final class JWTUtil {
String newAccessToken = generateAccessToken(user); String newAccessToken = generateAccessToken(user);
String newRefreshToken = generateRefreshToken(user); String newRefreshToken = generateRefreshToken(user);
// 惰性刷新refreshToken // 惰性刷新refreshToken
Long ttl = redisUtil.getExpire(redisKey, TimeUnit.DAYS); Long ttl = redisUtil.getExpire(redisKey, TimeUnit.MILLISECONDS);
if(ttl < NEED_REFRESH_TTL) if(ttl < NEED_REFRESH_TTL)
redisUtil.set(redisKey, newRefreshToken, REFRESH_EXPIRATION, TimeUnit.MILLISECONDS); redisUtil.set(redisKey, newRefreshToken, REFRESH_EXPIRATION, TimeUnit.MILLISECONDS);
user.setAccessToken(newAccessToken); user.setAccessToken(newAccessToken);

@ -48,7 +48,7 @@ public class RedisUtil {
public boolean hasKey(String key) { public boolean hasKey(String key) {
Boolean result = redisTemplate.hasKey(key); Boolean result = redisTemplate.hasKey(key);
return result != null; return result != null && result;
} }
public Long getExpire(String key, TimeUnit timeUnit){ public Long getExpire(String key, TimeUnit timeUnit){

@ -89,12 +89,12 @@
<version>5.8.24</version> <version>5.8.24</version>
</dependency> </dependency>
<!-- SpringSecurity --> <!-- minio -->
<dependency> <dependency>
<groupId>org.springframework.boot</groupId> <groupId>io.minio</groupId>
<artifactId>spring-boot-starter-security</artifactId> <artifactId>minio</artifactId>
<version>8.4.5</version> <!-- 使用最新版本 -->
</dependency> </dependency>
</dependencies> </dependencies>
<build> <build>

@ -0,0 +1,32 @@
package com.luojia_channel.modules.user.controller;
import com.luojia_channel.common.domain.Result;
import com.luojia_channel.modules.user.dto.UserChangeInfoDTO;
import com.luojia_channel.modules.user.service.UserInfoService;
import lombok.RequiredArgsConstructor;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
@RestController
@RequestMapping("/user/info")
@RequiredArgsConstructor
public class UserInfoController {
private final UserInfoService userInfoService;
@PostMapping("/update")
public Result<Void> updateInfo(@RequestBody UserChangeInfoDTO userChangeInfoDTO){
userInfoService.updateInfo(userChangeInfoDTO);
return Result.success();
}
@PostMapping("/password")
public Result<Void> updatePassword(@RequestParam String password){
userInfoService.updatePassword(password);
return Result.success();
}
@PostMapping("/avatar")
public Result<Void> updateAvatar(@RequestParam MultipartFile file){
// TODO 通过oss存储服务或者minio实现头像更新
return Result.success();
}
}

@ -5,6 +5,7 @@ import com.luojia_channel.common.domain.UserDTO;
import com.luojia_channel.modules.user.dto.UserLoginDTO; import com.luojia_channel.modules.user.dto.UserLoginDTO;
import com.luojia_channel.modules.user.dto.UserRegisterDTO; import com.luojia_channel.modules.user.dto.UserRegisterDTO;
import com.luojia_channel.modules.user.service.UserLoginService; import com.luojia_channel.modules.user.service.UserLoginService;
import jakarta.servlet.http.HttpServletRequest;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import org.springframework.web.bind.annotation.*; import org.springframework.web.bind.annotation.*;
@ -24,8 +25,8 @@ public class UserLoginController {
} }
@PostMapping("/logout") @PostMapping("/logout")
public Result logout(@RequestParam String accessToken){ public Result<Void> logout(HttpServletRequest request){
userLoginService.logout(accessToken); userLoginService.logout(request);
return Result.success(); return Result.success();
} }

@ -0,0 +1,20 @@
package com.luojia_channel.modules.user.dto;
import lombok.Data;
@Data
public class UserChangeInfoDTO {
private String username;
private String phone;
private String email;
private String studentId;
private String avatar;
private Integer gender;
private String college;
}

@ -44,6 +44,11 @@ public class User implements Serializable {
*/ */
private String studentId; private String studentId;
/**
* url
*/
private String avatar;
/** /**
* (012) * (012)
*/ */

@ -1,7 +1,11 @@
package com.luojia_channel.modules.user.service; package com.luojia_channel.modules.user.service;
import com.baomidou.mybatisplus.extension.service.IService; import com.baomidou.mybatisplus.extension.service.IService;
import com.luojia_channel.modules.user.dto.UserChangeInfoDTO;
import com.luojia_channel.modules.user.entity.User; import com.luojia_channel.modules.user.entity.User;
public interface UserInfoService extends IService<User> { public interface UserInfoService extends IService<User> {
void updateInfo(UserChangeInfoDTO userChangeInfoDTO);
void updatePassword(String password);
} }

@ -5,6 +5,7 @@ import com.luojia_channel.common.domain.UserDTO;
import com.luojia_channel.modules.user.dto.UserLoginDTO; import com.luojia_channel.modules.user.dto.UserLoginDTO;
import com.luojia_channel.modules.user.dto.UserRegisterDTO; import com.luojia_channel.modules.user.dto.UserRegisterDTO;
import com.luojia_channel.modules.user.entity.User; import com.luojia_channel.modules.user.entity.User;
import jakarta.servlet.http.HttpServletRequest;
public interface UserLoginService extends IService<User> { public interface UserLoginService extends IService<User> {
@ -12,7 +13,7 @@ public interface UserLoginService extends IService<User> {
UserDTO checkLogin(String accessToken, String refreshToken); UserDTO checkLogin(String accessToken, String refreshToken);
void logout(String accessToken); void logout(HttpServletRequest request);
UserDTO register(UserRegisterDTO userRegisterDTO); UserDTO register(UserRegisterDTO userRegisterDTO);
} }

@ -0,0 +1,58 @@
package com.luojia_channel.modules.user.service.impl;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.crypto.digest.BCrypt;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.luojia_channel.common.exception.UserException;
import com.luojia_channel.common.utils.UserContext;
import com.luojia_channel.modules.user.dto.UserChangeInfoDTO;
import com.luojia_channel.modules.user.entity.User;
import com.luojia_channel.modules.user.mapper.UserMapper;
import com.luojia_channel.modules.user.service.UserInfoService;
import com.luojia_channel.modules.user.utils.ValidateParameterUtil;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import java.time.LocalDateTime;
@Service
@RequiredArgsConstructor
public class UserInfoServiceImpl extends ServiceImpl<UserMapper, User> implements UserInfoService {
private final UserMapper userMapper;
private final ValidateParameterUtil validateParameterUtil;
@Override
public void updateInfo(UserChangeInfoDTO userChangeInfoDTO) {
Long userId = UserContext.getUserId();
User currentUser = userMapper.selectById(userId);
if(currentUser == null){
throw new UserException("用户不存在");
}
validateParameterUtil.validateFormats(userChangeInfoDTO, userId);
User user = BeanUtil.copyProperties(userChangeInfoDTO, User.class);
user.setId(userId);
user.setUpdateTime(LocalDateTime.now());
updateById(user);
}
@Override
public void updatePassword(String password) {
Long userId = UserContext.getUserId();
User user = userMapper.selectById(userId);
if(user == null){
throw new UserException("用户不存在");
}
if (!password.matches(ValidateParameterUtil.PASSWORD_REGEX)) {
throw new UserException("密码格式不符合要求");
}
if (BCrypt.checkpw(password, user.getPassword())) {
throw new UserException("修改密码不能与原密码相同");
}
String encodedPassword = BCrypt.hashpw(password, BCrypt.gensalt());
user.setPassword(encodedPassword);
user.setUpdateTime(LocalDateTime.now());
updateById(user);
}
}

@ -2,6 +2,7 @@ package com.luojia_channel.modules.user.service.impl;
import cn.hutool.core.bean.BeanUtil; import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.StrUtil; import cn.hutool.core.util.StrUtil;
import cn.hutool.crypto.digest.BCrypt;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers; import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
@ -16,8 +17,8 @@ import com.luojia_channel.modules.user.service.UserLoginService;
import com.luojia_channel.common.utils.JWTUtil; import com.luojia_channel.common.utils.JWTUtil;
import com.luojia_channel.common.utils.RedisUtil; import com.luojia_channel.common.utils.RedisUtil;
import com.luojia_channel.modules.user.utils.ValidateParameterUtil; import com.luojia_channel.modules.user.utils.ValidateParameterUtil;
import jakarta.servlet.http.HttpServletRequest;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional; import org.springframework.transaction.annotation.Transactional;
@ -37,7 +38,6 @@ public class UserLoginServiceImpl extends ServiceImpl<UserMapper, User> implemen
private final RedisUtil redisUtil; private final RedisUtil redisUtil;
private final JWTUtil jwtUtil; private final JWTUtil jwtUtil;
private final ValidateParameterUtil validateParameterUtil; private final ValidateParameterUtil validateParameterUtil;
private final PasswordEncoder passwordEncoder;
/** /**
* *
@ -92,7 +92,7 @@ public class UserLoginServiceImpl extends ServiceImpl<UserMapper, User> implemen
String userFlag = userLoginDTO.getUserFlag(); String userFlag = userLoginDTO.getUserFlag();
String password = userLoginDTO.getPassword(); String password = userLoginDTO.getPassword();
User user = getUserByFlag(userFlag); User user = getUserByFlag(userFlag);
if (!passwordEncoder.matches(password, user.getPassword())) { if (!BCrypt.checkpw(password, user.getPassword())) {
throw new UserException("密码错误"); throw new UserException("密码错误");
} }
UserDTO userDTO = UserDTO.builder() UserDTO userDTO = UserDTO.builder()
@ -116,11 +116,14 @@ public class UserLoginServiceImpl extends ServiceImpl<UserMapper, User> implemen
/** /**
* *
* @param accessToken
*/ */
@Override @Override
public void logout(String accessToken) { public void logout(HttpServletRequest request) {
String accessToken = request.getHeader("Authorization");
Long userId = UserContext.getUserId(); Long userId = UserContext.getUserId();
if(userId == null){
throw new UserException("用户不存在");
}
// 删除refreshToken // 删除refreshToken
String refreshKey = REFRESH_TOKEN_PREFIX + userId; String refreshKey = REFRESH_TOKEN_PREFIX + userId;
redisUtil.delete(refreshKey); redisUtil.delete(refreshKey);
@ -142,10 +145,10 @@ public class UserLoginServiceImpl extends ServiceImpl<UserMapper, User> implemen
@Transactional(rollbackFor = Exception.class) @Transactional(rollbackFor = Exception.class)
public UserDTO register(UserRegisterDTO userRegisterDTO) { public UserDTO register(UserRegisterDTO userRegisterDTO) {
// 校验注册参数 // 校验注册参数
validateParameterUtil.validateUser(userRegisterDTO); validateParameterUtil.validateRegisterUser(userRegisterDTO);
User user = BeanUtil.copyProperties(userRegisterDTO, User.class); User user = BeanUtil.copyProperties(userRegisterDTO, User.class);
// 加密 // 加密
String encodedPassword = passwordEncoder.encode(userRegisterDTO.getPassword()); String encodedPassword = BCrypt.hashpw(userRegisterDTO.getPassword(), BCrypt.gensalt());
user.setPassword(encodedPassword); user.setPassword(encodedPassword);
user.setCreateTime(LocalDateTime.now()); user.setCreateTime(LocalDateTime.now());
user.setUpdateTime(LocalDateTime.now()); user.setUpdateTime(LocalDateTime.now());

@ -3,6 +3,7 @@ package com.luojia_channel.modules.user.utils;
import cn.hutool.core.util.StrUtil; import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.toolkit.Wrappers; import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.luojia_channel.common.exception.UserException; import com.luojia_channel.common.exception.UserException;
import com.luojia_channel.modules.user.dto.UserChangeInfoDTO;
import com.luojia_channel.modules.user.dto.UserRegisterDTO; import com.luojia_channel.modules.user.dto.UserRegisterDTO;
import com.luojia_channel.modules.user.entity.User; import com.luojia_channel.modules.user.entity.User;
import com.luojia_channel.modules.user.mapper.UserMapper; import com.luojia_channel.modules.user.mapper.UserMapper;
@ -24,7 +25,7 @@ public class ValidateParameterUtil {
* *
* @param userRegisterDTO * @param userRegisterDTO
*/ */
public void validateUser(UserRegisterDTO userRegisterDTO) { public void validateRegisterUser(UserRegisterDTO userRegisterDTO) {
String username = userRegisterDTO.getUsername(); String username = userRegisterDTO.getUsername();
String password = userRegisterDTO.getPassword(); String password = userRegisterDTO.getPassword();
String phone = userRegisterDTO.getPhone(); String phone = userRegisterDTO.getPhone();
@ -69,11 +70,31 @@ public class ValidateParameterUtil {
if(!password.matches(PASSWORD_REGEX)){ if(!password.matches(PASSWORD_REGEX)){
throw new UserException("密码格式错误"); throw new UserException("密码格式错误");
} }
validateUserFlag(phone, email, studentId, null);
}
public void validateFormats(UserChangeInfoDTO userChangeInfoDTO, Long currentUserId){
String username = userChangeInfoDTO.getUsername();
String phone = userChangeInfoDTO.getPhone();
String email = userChangeInfoDTO.getEmail();
String studentId = userChangeInfoDTO.getStudentId();
// String college = userChangeInfoDTO.getCollege();
if (userMapper.exists(Wrappers.<User>lambdaQuery()
.eq(User::getUsername, userChangeInfoDTO.getUsername())
.ne(currentUserId != null, User::getId, currentUserId))) {
throw new UserException("用户名已被使用");
}
validateUserFlag(phone, email, studentId, currentUserId);
}
private void validateUserFlag(String phone, String email, String studentId, Long currentUserId) {
if(StrUtil.isNotBlank(phone)){ if(StrUtil.isNotBlank(phone)){
if(!phone.matches(PHONE_REGEX)) if(!phone.matches(PHONE_REGEX))
throw new UserException("手机号格式错误"); throw new UserException("手机号格式错误");
if (userMapper.exists(Wrappers.<User>lambdaQuery() if (userMapper.exists(Wrappers.<User>lambdaQuery()
.eq(User::getPhone, phone))) { .eq(User::getPhone, phone)
.ne(currentUserId != null, User::getId, currentUserId))) {
throw new UserException("手机已存在"); throw new UserException("手机已存在");
} }
} }
@ -81,7 +102,8 @@ public class ValidateParameterUtil {
if(!email.matches(EMAIL_REGEX)) if(!email.matches(EMAIL_REGEX))
throw new UserException("邮箱格式错误"); throw new UserException("邮箱格式错误");
if (userMapper.exists(Wrappers.<User>lambdaQuery() if (userMapper.exists(Wrappers.<User>lambdaQuery()
.eq(User::getEmail, email))) { .eq(User::getEmail, email)
.ne(currentUserId != null, User::getId, currentUserId))) {
throw new UserException("邮箱已存在"); throw new UserException("邮箱已存在");
} }
} }
@ -89,7 +111,8 @@ public class ValidateParameterUtil {
if(!studentId.matches(STUDENTID_REGEX)) if(!studentId.matches(STUDENTID_REGEX))
throw new UserException("学号格式错误"); throw new UserException("学号格式错误");
if (userMapper.exists(Wrappers.<User>lambdaQuery() if (userMapper.exists(Wrappers.<User>lambdaQuery()
.eq(User::getStudentId, studentId))) { .eq(User::getStudentId, studentId)
.ne(currentUserId != null, User::getId, currentUserId))) {
throw new UserException("学号已存在"); throw new UserException("学号已存在");
} }
} }

@ -1,4 +1,5 @@
DROP TABLE IF EXISTS `user`;
CREATE TABLE `user` ( CREATE TABLE `user` (
`id` BIGINT PRIMARY KEY AUTO_INCREMENT COMMENT '主键ID', `id` BIGINT PRIMARY KEY AUTO_INCREMENT COMMENT '主键ID',
`username` VARCHAR(50) NOT NULL COMMENT '用户名', `username` VARCHAR(50) NOT NULL COMMENT '用户名',
@ -7,6 +8,7 @@ CREATE TABLE `user` (
`phone` VARCHAR(20) UNIQUE COMMENT '注册手机号', `phone` VARCHAR(20) UNIQUE COMMENT '注册手机号',
`email` VARCHAR(100) UNIQUE COMMENT '邮箱', `email` VARCHAR(100) UNIQUE COMMENT '邮箱',
`student_id` VARCHAR(20) UNIQUE COMMENT '学号', `student_id` VARCHAR(20) UNIQUE COMMENT '学号',
`avatar` VARCHAR(255) COMMENT '头像URL',
`gender` TINYINT DEFAULT 0 COMMENT '性别0未知1男2女', `gender` TINYINT DEFAULT 0 COMMENT '性别0未知1男2女',
`create_time` DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', `create_time` DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`update_time` DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', `update_time` DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',

@ -1,4 +1,5 @@
DROP TABLE IF EXISTS `user`;
CREATE TABLE `user` ( CREATE TABLE `user` (
`id` BIGINT PRIMARY KEY AUTO_INCREMENT COMMENT '主键ID', `id` BIGINT PRIMARY KEY AUTO_INCREMENT COMMENT '主键ID',
`username` VARCHAR(50) NOT NULL COMMENT '用户名', `username` VARCHAR(50) NOT NULL COMMENT '用户名',
@ -7,6 +8,7 @@ CREATE TABLE `user` (
`phone` VARCHAR(20) UNIQUE COMMENT '注册手机号', `phone` VARCHAR(20) UNIQUE COMMENT '注册手机号',
`email` VARCHAR(100) UNIQUE COMMENT '邮箱', `email` VARCHAR(100) UNIQUE COMMENT '邮箱',
`student_id` VARCHAR(20) UNIQUE COMMENT '学号', `student_id` VARCHAR(20) UNIQUE COMMENT '学号',
`avatar` VARCHAR(255) COMMENT '头像URL',
`gender` TINYINT DEFAULT 0 COMMENT '性别0未知1男2女', `gender` TINYINT DEFAULT 0 COMMENT '性别0未知1男2女',
`create_time` DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', `create_time` DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`update_time` DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', `update_time` DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',

@ -1,2 +0,0 @@
# software_teamwork

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save