refactor: 重构安全架构,提取通用安全模块到common-security

- 将JwtAuthenticationFilter、JwtUtil、JwtProperties从auth服务移至common-security模块
- 新增common-security通用安全模块,提供JWT认证、权限验证等核心安全功能
- 重命名SecurityConfiguration为AuthSecurityConfiguration,使用common-security的filter
- 新增JacksonConfiguration配置类,统一JSON序列化配置
- 新增头像更新功能AvatarUpdateRequestDTO
- 移除冗余的UserLoginResponseDTO类
- 更新各服务模块的依赖配置以引入common-security模块
- 新增README.md项目说明文档

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
2026-01-12 01:54:21 +08:00
parent 8bd56a6001
commit a4575cebd4
47 changed files with 704 additions and 317 deletions

View File

@@ -3,6 +3,7 @@ package cn.meowrain.aioj.backend.userservice.controller;
import cn.meowrain.aioj.backend.framework.core.utils.ContextHolderUtils;
import cn.meowrain.aioj.backend.framework.core.web.Result;
import cn.meowrain.aioj.backend.framework.core.web.Results;
import cn.meowrain.aioj.backend.userservice.dto.req.AvatarUpdateRequestDTO;
import cn.meowrain.aioj.backend.userservice.dto.req.BindEmailRequest;
import cn.meowrain.aioj.backend.userservice.dto.req.EmailSendCodeRequestDTO;
import cn.meowrain.aioj.backend.userservice.dto.req.UserRegisterRequestDTO;
@@ -47,7 +48,7 @@ public class UserController {
@Operation(summary = "根据用户ID查询用户", description = "通过用户ID获取用户认证信息(内部接口)")
public Result<UserAuthRespDTO> getUserById(
@Parameter(description = "用户ID", required = true, example = "1")
@RequestParam("userId") String userid) {
@RequestParam("userId") Long userid) {
UserAuthRespDTO userAuthRespDTO = userService.findAuthInfoByUserId(userid);
return Results.success(userAuthRespDTO);
}
@@ -96,19 +97,20 @@ public class UserController {
return Results.success();
}
@Operation(summary = "个人资料管理", description = "更新个人资料")
@Operation(summary = "个人资料管理-更新个人资料", description = "更新个人资料")
@PutMapping("/profile")
public Result<Void> updateUserProfile() {
return Results.success();
}
@Operation(summary = "个人资料管理", description = "上传/更新头像")
@PostMapping("/avatar")
public Result<Void> uploadAvatar(@RequestParam("file") MultipartFile file) {
@Operation(summary = "个人资料管理-上传/更新头像", description = "上传/更新头像")
@PutMapping("/avatar")
public Result<Void> setProfileAvatar(@Parameter(description = "文件id", required = true) @RequestBody AvatarUpdateRequestDTO dto) {
userService.setProfileAvatar(dto.getFileId());
return Results.success();
}
@Operation(summary = "个人资料管理",description = "修改密码")
@Operation(summary = "个人资料管理-修改密码",description = "修改密码")
public Result<Void> changePassword() {
return Results.success();
}

View File

@@ -46,7 +46,7 @@ public class User implements Serializable {
/**
* 用户头像
*/
private String userAvatar;
private Long userAvatar;
/**
* 用户简介

View File

@@ -0,0 +1,8 @@
package cn.meowrain.aioj.backend.userservice.dto.req;
import lombok.Data;
@Data
public class AvatarUpdateRequestDTO {
private Long fileId;
}

View File

@@ -3,6 +3,7 @@ package cn.meowrain.aioj.backend.userservice.dto.resp;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import java.io.Serializable;
import java.util.Date;
/**
@@ -10,84 +11,72 @@ import java.util.Date;
*/
@Data
@Schema(description = "用户认证响应体")
public class UserAuthRespDTO {
public class UserAuthRespDTO implements Serializable {
/**
* id
*/
@Schema(description = "用户ID", example = "1")
private Long id;
/**
* id
*/
private Long id;
/**
* 用户账号
*/
@Schema(description = "用户账号", example = "admin")
private String userAccount;
/**
* 用户账号
*/
private String userAccount;
/**
* 用户密码
*/
private String userPassword;
/**
* 开放平台id
*/
private String unionId;
/**
* 用户密码
*/
@Schema(description = "用户密码", example = "123456")
private String userPassword;
/**
* 公众号openId
*/
private String mpOpenId;
/**
* 开放平台id
*/
@Schema(description = "开放平台ID", example = "wx_union_id_123")
private String unionId;
/**
* 用户昵称
*/
private String userName;
/**
* 公众号openId
*/
@Schema(description = "公众号OpenID", example = "wx_openid_123")
private String mpOpenId;
/**
* 用户头像
*/
private Long userAvatar;
/**
* 用户昵称
*/
@Schema(description = "用户昵称", example = "张三")
private String userName;
/**
* 用户简介
*/
private String userProfile;
/**
* 用户头像
*/
@Schema(description = "用户头像URL", example = "https://example.com/avatar.jpg")
private String userAvatar;
/**
* 用户角色user/admin/ban
*/
private String userRole;
/**
* 用户简介
*/
@Schema(description = "用户简介", example = "这是我的个人简介")
private String userProfile;
/**
* 用户邮箱
*/
private String userEmail;
/**
* 用户角色user/admin/ban
*/
@Schema(description = "用户角色", example = "user", allowableValues = {"user", "admin", "ban"})
private String userRole;
/**
* 用户邮箱是否验证 0 未验证 1已验证
*/
private Integer userEmailVerified;
/**
* 用户邮箱
*/
@Schema(description = "用户邮箱", example = "user@example.com")
private String userEmail;
/**
* 创建时间
*/
private Date createTime;
/**
* 用户邮箱是否验证 0 未验证 1已验证
*/
@Schema(description = "用户邮箱是否验证", example = "1", allowableValues = {"0", "1"})
private Integer userEmailVerified;
/**
* 更新时间
*/
private Date updateTime;
/**
* 创建时间
*/
@Schema(description = "创建时间", example = "2025-01-01T00:00:00")
private Date createTime;
/**
* 更新时间
*/
@Schema(description = "更新时间", example = "2025-01-01T12:00:00")
private Date updateTime;
private static final long serialVersionUID = 1L;
}

View File

@@ -1,76 +0,0 @@
package cn.meowrain.aioj.backend.userservice.dto.resp;
import com.baomidou.mybatisplus.annotation.*;
import lombok.Data;
import java.io.Serializable;
import java.util.Date;
@Data
public class UserLoginResponseDTO implements Serializable {
/**
* id
*/
@TableId(type = IdType.ASSIGN_ID)
private Long id;
/**
* 用户账号
*/
private String userAccount;
/**
* 开放平台id
*/
private String unionId;
/**
* 公众号openId
*/
private String mpOpenId;
/**
* 用户昵称
*/
private String userName;
/**
* 用户头像
*/
private String userAvatar;
/**
* 用户简介
*/
private String userProfile;
/**
* 用户角色user/admin/ban
*/
private String userRole;
/**
* 创建时间
*/
private Date createTime;
/**
* 更新时间
*/
private Date updateTime;
/**
* 是否删除
*/
private Integer isDelete;
/**
* JWT令牌登录成功返回
*/
private String token;
private static final long serialVersionUID = 1L;
}

View File

@@ -26,7 +26,7 @@ public interface UserService extends IService<User> {
/**
* 根据用户id查找用户认证信息
*/
UserAuthRespDTO findAuthInfoByUserId(String userId);
UserAuthRespDTO findAuthInfoByUserId(Long userId);
/**
@@ -43,4 +43,11 @@ public interface UserService extends IService<User> {
* 解绑邮箱
*/
void unbindEmail(Long userId);
/**
* 设置用户头像
* @param fileId
* @return
*/
void setProfileAvatar(Long fileId);
}

View File

@@ -20,6 +20,7 @@ import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.dao.DuplicateKeyException;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.Date;
@@ -75,7 +76,7 @@ public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements Us
}
@Override
public UserAuthRespDTO findAuthInfoByUserId(String userId) {
public UserAuthRespDTO findAuthInfoByUserId(Long userId) {
User one = this.lambdaQuery().eq(User::getId, userId).one();
UserAuthRespDTO userAuthDTO = new UserAuthRespDTO();
if (one != null) {
@@ -100,7 +101,18 @@ public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements Us
@Override
public void unbindEmail(Long userId) {
User one = this.lambdaQuery().eq(User::getId, userId).one();
}
@Transactional(rollbackFor = Exception.class)
@Override
public void setProfileAvatar(Long fileId) {
Long currentUserId = ContextHolderUtils.getCurrentUserId();
User user = this.lambdaQuery().eq(User::getId, currentUserId).one();
user.setUserAvatar(fileId);
user.setUpdateTime(new Date());
this.updateById(user);
}
}

View File

@@ -4,7 +4,7 @@ spring:
profiles:
active: @env@
server:
port: 10010
port: 18082
servlet:
context-path: /api
error:
@@ -31,6 +31,14 @@ mybatis-plus:
configuration:
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
mapper-locations: classpath*:/mapper/**/*.xml
# JWT 配置(必须与 auth-service 保持一致)
jwt:
enabled: true
secret: "12345678901234567890123456789012" # 至少32字节
access-expire: 900000 # 15分钟
refresh-expire: 604800000 # 7天
aioj:
log:
enabled: true