refactor(auth):重构认证服务,分离用户逻辑到独立服务
- 将用户相关业务迁移至用户模块,通过OpenFeign远程调用。
This commit is contained in:
@@ -1,11 +1,11 @@
|
||||
package com.hanserwei.hannote.auth;
|
||||
|
||||
import org.mybatis.spring.annotation.MapperScan;
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
import org.springframework.cloud.openfeign.EnableFeignClients;
|
||||
|
||||
@SpringBootApplication
|
||||
@MapperScan("com.hanserwei.hannote.auth.domain.mapper")
|
||||
@EnableFeignClients(basePackages = "com.hanserwei.hannote")
|
||||
public class HanNoteAuthApplication {
|
||||
|
||||
public static void main(String[] args) {
|
||||
|
||||
@@ -4,7 +4,7 @@ import com.hanserwei.framework.biz.operationlog.aspect.ApiOperationLog;
|
||||
import com.hanserwei.framework.common.response.Response;
|
||||
import com.hanserwei.hannote.auth.model.vo.user.UpdatePasswordReqVO;
|
||||
import com.hanserwei.hannote.auth.model.vo.user.UserLoginReqVO;
|
||||
import com.hanserwei.hannote.auth.service.UserService;
|
||||
import com.hanserwei.hannote.auth.service.AuthService;
|
||||
import jakarta.annotation.Resource;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
@@ -16,26 +16,26 @@ import org.springframework.web.bind.annotation.RestController;
|
||||
@RestController
|
||||
@Slf4j
|
||||
@RequiredArgsConstructor
|
||||
public class UserController {
|
||||
public class AuthController {
|
||||
|
||||
@Resource
|
||||
private UserService userService;
|
||||
private AuthService authService;
|
||||
|
||||
@PostMapping("/login")
|
||||
@ApiOperationLog(description = "用户登录/注册")
|
||||
public Response<String> loginAndRegister(@Validated @RequestBody UserLoginReqVO userLoginReqVO) {
|
||||
return userService.loginAndRegister(userLoginReqVO);
|
||||
return authService.loginAndRegister(userLoginReqVO);
|
||||
}
|
||||
|
||||
@PostMapping("/logout")
|
||||
@ApiOperationLog(description = "账号登出")
|
||||
public Response<?> logout() {
|
||||
return userService.logout();
|
||||
return authService.logout();
|
||||
}
|
||||
|
||||
@PostMapping("/password/update")
|
||||
@ApiOperationLog(description = "修改密码")
|
||||
public Response<?> updatePassword(@Validated @RequestBody UpdatePasswordReqVO updatePasswordReqVO) {
|
||||
return userService.updatePassword(updatePasswordReqVO);
|
||||
return authService.updatePassword(updatePasswordReqVO);
|
||||
}
|
||||
}
|
||||
@@ -1,91 +0,0 @@
|
||||
package com.hanserwei.hannote.auth.domain.dataobject;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.IdType;
|
||||
import com.baomidou.mybatisplus.annotation.TableField;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import java.util.Date;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
/**
|
||||
* 权限表
|
||||
*/
|
||||
@Data
|
||||
@AllArgsConstructor
|
||||
@NoArgsConstructor
|
||||
@TableName(value = "t_permission")
|
||||
public class PermissionDO {
|
||||
/**
|
||||
* 主键ID
|
||||
*/
|
||||
@TableId(value = "id", type = IdType.AUTO)
|
||||
private Long id;
|
||||
|
||||
/**
|
||||
* 父ID
|
||||
*/
|
||||
@TableField(value = "parent_id")
|
||||
private Long parentId;
|
||||
|
||||
/**
|
||||
* 权限名称
|
||||
*/
|
||||
@TableField(value = "`name`")
|
||||
private String name;
|
||||
|
||||
/**
|
||||
* 类型(1:目录 2:菜单 3:按钮)
|
||||
*/
|
||||
@TableField(value = "`type`")
|
||||
private Byte type;
|
||||
|
||||
/**
|
||||
* 菜单路由
|
||||
*/
|
||||
@TableField(value = "menu_url")
|
||||
private String menuUrl;
|
||||
|
||||
/**
|
||||
* 菜单图标
|
||||
*/
|
||||
@TableField(value = "menu_icon")
|
||||
private String menuIcon;
|
||||
|
||||
/**
|
||||
* 管理系统中的显示顺序
|
||||
*/
|
||||
@TableField(value = "sort")
|
||||
private Integer sort;
|
||||
|
||||
/**
|
||||
* 权限标识
|
||||
*/
|
||||
@TableField(value = "permission_key")
|
||||
private String permissionKey;
|
||||
|
||||
/**
|
||||
* 状态(0:启用;1:禁用)
|
||||
*/
|
||||
@TableField(value = "`status`")
|
||||
private Byte status;
|
||||
|
||||
/**
|
||||
* 创建时间
|
||||
*/
|
||||
@TableField(value = "create_time")
|
||||
private Date createTime;
|
||||
|
||||
/**
|
||||
* 更新时间
|
||||
*/
|
||||
@TableField(value = "update_time")
|
||||
private Date updateTime;
|
||||
|
||||
/**
|
||||
* 逻辑删除(0:未删除 1:已删除)
|
||||
*/
|
||||
@TableField(value = "is_deleted")
|
||||
private Boolean isDeleted;
|
||||
}
|
||||
@@ -1,73 +0,0 @@
|
||||
package com.hanserwei.hannote.auth.domain.dataobject;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.IdType;
|
||||
import com.baomidou.mybatisplus.annotation.TableField;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import java.util.Date;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
/**
|
||||
* 角色表
|
||||
*/
|
||||
@Data
|
||||
@AllArgsConstructor
|
||||
@NoArgsConstructor
|
||||
@TableName(value = "t_role")
|
||||
public class RoleDO {
|
||||
/**
|
||||
* 主键ID
|
||||
*/
|
||||
@TableId(value = "id", type = IdType.AUTO)
|
||||
private Long id;
|
||||
|
||||
/**
|
||||
* 角色名
|
||||
*/
|
||||
@TableField(value = "role_name")
|
||||
private String roleName;
|
||||
|
||||
/**
|
||||
* 角色唯一标识
|
||||
*/
|
||||
@TableField(value = "role_key")
|
||||
private String roleKey;
|
||||
|
||||
/**
|
||||
* 状态(0:启用 1:禁用)
|
||||
*/
|
||||
@TableField(value = "`status`")
|
||||
private Byte status;
|
||||
|
||||
/**
|
||||
* 管理系统中的显示顺序
|
||||
*/
|
||||
@TableField(value = "sort")
|
||||
private Integer sort;
|
||||
|
||||
/**
|
||||
* 备注
|
||||
*/
|
||||
@TableField(value = "remark")
|
||||
private String remark;
|
||||
|
||||
/**
|
||||
* 创建时间
|
||||
*/
|
||||
@TableField(value = "create_time")
|
||||
private Date createTime;
|
||||
|
||||
/**
|
||||
* 最后一次更新时间
|
||||
*/
|
||||
@TableField(value = "update_time")
|
||||
private Date updateTime;
|
||||
|
||||
/**
|
||||
* 逻辑删除(0:未删除 1:已删除)
|
||||
*/
|
||||
@TableField(value = "is_deleted")
|
||||
private Boolean isDeleted;
|
||||
}
|
||||
@@ -1,55 +0,0 @@
|
||||
package com.hanserwei.hannote.auth.domain.dataobject;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.IdType;
|
||||
import com.baomidou.mybatisplus.annotation.TableField;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import java.util.Date;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
/**
|
||||
* 用户权限表
|
||||
*/
|
||||
@Data
|
||||
@AllArgsConstructor
|
||||
@NoArgsConstructor
|
||||
@TableName(value = "t_role_permission_rel")
|
||||
public class RolePermissionDO {
|
||||
/**
|
||||
* 主键ID
|
||||
*/
|
||||
@TableId(value = "id", type = IdType.AUTO)
|
||||
private Long id;
|
||||
|
||||
/**
|
||||
* 角色ID
|
||||
*/
|
||||
@TableField(value = "role_id")
|
||||
private Long roleId;
|
||||
|
||||
/**
|
||||
* 权限ID
|
||||
*/
|
||||
@TableField(value = "permission_id")
|
||||
private Long permissionId;
|
||||
|
||||
/**
|
||||
* 创建时间
|
||||
*/
|
||||
@TableField(value = "create_time")
|
||||
private Date createTime;
|
||||
|
||||
/**
|
||||
* 更新时间
|
||||
*/
|
||||
@TableField(value = "update_time")
|
||||
private Date updateTime;
|
||||
|
||||
/**
|
||||
* 逻辑删除(0:未删除 1:已删除)
|
||||
*/
|
||||
@TableField(value = "is_deleted")
|
||||
private Boolean isDeleted;
|
||||
}
|
||||
@@ -1,107 +0,0 @@
|
||||
package com.hanserwei.hannote.auth.domain.dataobject;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.IdType;
|
||||
import com.baomidou.mybatisplus.annotation.TableField;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import java.time.LocalDate;
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
/**
|
||||
* 用户表
|
||||
*/
|
||||
@Data
|
||||
@Builder
|
||||
@AllArgsConstructor
|
||||
@NoArgsConstructor
|
||||
@TableName(value = "t_user")
|
||||
public class UserDO {
|
||||
/**
|
||||
* 主键ID
|
||||
*/
|
||||
@TableId(value = "id", type = IdType.ASSIGN_ID)
|
||||
private Long id;
|
||||
|
||||
/**
|
||||
* 小憨书号(唯一凭证)
|
||||
*/
|
||||
@TableField(value = "han_note_id")
|
||||
private String hanNoteId;
|
||||
|
||||
/**
|
||||
* 密码
|
||||
*/
|
||||
@TableField(value = "`password`")
|
||||
private String password;
|
||||
|
||||
/**
|
||||
* 昵称
|
||||
*/
|
||||
@TableField(value = "nickname")
|
||||
private String nickname;
|
||||
|
||||
/**
|
||||
* 头像
|
||||
*/
|
||||
@TableField(value = "avatar")
|
||||
private String avatar;
|
||||
|
||||
/**
|
||||
* 生日
|
||||
*/
|
||||
@TableField(value = "birthday")
|
||||
private LocalDate birthday;
|
||||
|
||||
/**
|
||||
* 背景图
|
||||
*/
|
||||
@TableField(value = "background_img")
|
||||
private String backgroundImg;
|
||||
|
||||
/**
|
||||
* 邮箱
|
||||
*/
|
||||
@TableField(value = "email")
|
||||
private String email;
|
||||
|
||||
/**
|
||||
* 性别(0:女 1:男)
|
||||
*/
|
||||
@TableField(value = "sex")
|
||||
private Integer sex;
|
||||
|
||||
/**
|
||||
* 状态(0:启用 1:禁用)
|
||||
*/
|
||||
@TableField(value = "`status`")
|
||||
private Integer status;
|
||||
|
||||
/**
|
||||
* 个人简介
|
||||
*/
|
||||
@TableField(value = "introduction")
|
||||
private String introduction;
|
||||
|
||||
/**
|
||||
* 创建时间
|
||||
*/
|
||||
@TableField(value = "create_time")
|
||||
private LocalDateTime createTime;
|
||||
|
||||
/**
|
||||
* 更新时间
|
||||
*/
|
||||
@TableField(value = "update_time")
|
||||
private LocalDateTime updateTime;
|
||||
|
||||
/**
|
||||
* 逻辑删除(0:未删除 1:已删除)
|
||||
*/
|
||||
@TableField(value = "is_deleted")
|
||||
private Boolean isDeleted;
|
||||
}
|
||||
@@ -1,58 +0,0 @@
|
||||
package com.hanserwei.hannote.auth.domain.dataobject;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.IdType;
|
||||
import com.baomidou.mybatisplus.annotation.TableField;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
/**
|
||||
* 用户角色表
|
||||
*/
|
||||
@Data
|
||||
@Builder
|
||||
@AllArgsConstructor
|
||||
@NoArgsConstructor
|
||||
@TableName(value = "t_user_role_rel")
|
||||
public class UserRoleDO {
|
||||
/**
|
||||
* 主键ID
|
||||
*/
|
||||
@TableId(value = "id", type = IdType.AUTO)
|
||||
private Long id;
|
||||
|
||||
/**
|
||||
* 用户ID
|
||||
*/
|
||||
@TableField(value = "user_id")
|
||||
private Long userId;
|
||||
|
||||
/**
|
||||
* 角色ID
|
||||
*/
|
||||
@TableField(value = "role_id")
|
||||
private Long roleId;
|
||||
|
||||
/**
|
||||
* 创建时间
|
||||
*/
|
||||
@TableField(value = "create_time")
|
||||
private LocalDateTime createTime;
|
||||
|
||||
/**
|
||||
* 更新时间
|
||||
*/
|
||||
@TableField(value = "update_time")
|
||||
private LocalDateTime updateTime;
|
||||
|
||||
/**
|
||||
* 逻辑删除(0:未删除 1:已删除)
|
||||
*/
|
||||
@TableField(value = "is_deleted")
|
||||
private Boolean isDeleted;
|
||||
}
|
||||
@@ -1,15 +0,0 @@
|
||||
package com.hanserwei.hannote.auth.domain.mapper;
|
||||
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import com.hanserwei.hannote.auth.domain.dataobject.PermissionDO;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public interface PermissionDOMapper extends BaseMapper<PermissionDO> {
|
||||
/**
|
||||
* 查询 APP 端所有被启用的权限
|
||||
*
|
||||
* @return 权限列表
|
||||
*/
|
||||
List<PermissionDO> selectAppEnabledList();
|
||||
}
|
||||
@@ -1,18 +0,0 @@
|
||||
package com.hanserwei.hannote.auth.domain.mapper;
|
||||
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import com.hanserwei.hannote.auth.domain.dataobject.RoleDO;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public interface RoleDOMapper extends BaseMapper<RoleDO> {
|
||||
|
||||
/**
|
||||
* 查询所有被启用的角色
|
||||
*
|
||||
* @return 角色列表
|
||||
*/
|
||||
List<RoleDO> selectEnabledList();
|
||||
|
||||
RoleDO selectByPrimaryKey(Long commonUserRoleId);
|
||||
}
|
||||
@@ -1,17 +0,0 @@
|
||||
package com.hanserwei.hannote.auth.domain.mapper;
|
||||
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import com.hanserwei.hannote.auth.domain.dataobject.RolePermissionDO;
|
||||
import org.apache.ibatis.annotations.Param;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public interface RolePermissionDOMapper extends BaseMapper<RolePermissionDO> {
|
||||
/**
|
||||
* 根据角色 ID 集合批量查询
|
||||
*
|
||||
* @param roleIds 角色 ID 集合
|
||||
* @return 角色权限关系
|
||||
*/
|
||||
List<RolePermissionDO> selectByRoleIds(@Param("roleIds") List<Long> roleIds);
|
||||
}
|
||||
@@ -1,7 +0,0 @@
|
||||
package com.hanserwei.hannote.auth.domain.mapper;
|
||||
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import com.hanserwei.hannote.auth.domain.dataobject.UserDO;
|
||||
|
||||
public interface UserDOMapper extends BaseMapper<UserDO> {
|
||||
}
|
||||
@@ -1,7 +0,0 @@
|
||||
package com.hanserwei.hannote.auth.domain.mapper;
|
||||
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import com.hanserwei.hannote.auth.domain.dataobject.UserRoleDO;
|
||||
|
||||
public interface UserRoleDOMapper extends BaseMapper<UserRoleDO> {
|
||||
}
|
||||
@@ -18,6 +18,7 @@ public enum ResponseCodeEnum implements BaseExceptionInterface {
|
||||
LOGIN_TYPE_ERROR("AUTH-20002", "登录类型错误"),
|
||||
USER_NOT_FOUND("AUTH-20003", "该用户不存在"),
|
||||
MAIL_OR_PASSWORD_ERROR("AUTH-20004", "邮箱号或密码错误"),
|
||||
LOGIN_FAIL("AUTH-20005", "登录失败"),
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,68 @@
|
||||
package com.hanserwei.hannote.auth.rpc;
|
||||
|
||||
import com.hanserwei.framework.common.response.Response;
|
||||
import com.hanserwei.hannote.user.api.UserFeignApi;
|
||||
import com.hanserwei.hannote.user.dto.req.FindUserByEmailReqDTO;
|
||||
import com.hanserwei.hannote.user.dto.req.RegisterUserReqDTO;
|
||||
import com.hanserwei.hannote.user.dto.req.UpdateUserPasswordReqDTO;
|
||||
import com.hanserwei.hannote.user.dto.resp.FindUserByEmailRspDTO;
|
||||
import jakarta.annotation.Resource;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
@Component
|
||||
public class UserRpcService {
|
||||
|
||||
@Resource
|
||||
private UserFeignApi userFeignApi;
|
||||
|
||||
/**
|
||||
* 用户注册
|
||||
*
|
||||
* @param email 邮箱
|
||||
* @return 用户ID
|
||||
*/
|
||||
public Long registerUser(String email) {
|
||||
RegisterUserReqDTO registerUserReqDTO = new RegisterUserReqDTO();
|
||||
registerUserReqDTO.setEmail(email);
|
||||
|
||||
Response<Long> response = userFeignApi.registerUser(registerUserReqDTO);
|
||||
|
||||
if (!response.isSuccess()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return response.getData();
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据邮箱号查询用户信息
|
||||
*
|
||||
* @param email 邮箱
|
||||
* @return 用户信息
|
||||
*/
|
||||
public FindUserByEmailRspDTO findUserByEmail(String email) {
|
||||
FindUserByEmailReqDTO findUserByEmailReqDTO = new FindUserByEmailReqDTO();
|
||||
findUserByEmailReqDTO.setEmail(email);
|
||||
|
||||
Response<FindUserByEmailRspDTO> response = userFeignApi.findByPhone(findUserByEmailReqDTO);
|
||||
|
||||
if (!response.isSuccess()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return response.getData();
|
||||
}
|
||||
|
||||
/**
|
||||
* 密码更新
|
||||
*
|
||||
* @param encodePassword 加密后的密码
|
||||
*/
|
||||
public void updatePassword(String encodePassword) {
|
||||
UpdateUserPasswordReqDTO updateUserPasswordReqDTO = new UpdateUserPasswordReqDTO();
|
||||
updateUserPasswordReqDTO.setEncodePassword(encodePassword);
|
||||
|
||||
userFeignApi.updatePassword(updateUserPasswordReqDTO);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,108 +0,0 @@
|
||||
package com.hanserwei.hannote.auth.runner;
|
||||
|
||||
import cn.hutool.core.collection.CollUtil;
|
||||
import com.google.common.collect.Lists;
|
||||
import com.google.common.collect.Maps;
|
||||
import com.hanserwei.framework.common.utils.JsonUtils;
|
||||
import com.hanserwei.hannote.auth.constant.RedisKeyConstants;
|
||||
import com.hanserwei.hannote.auth.domain.dataobject.PermissionDO;
|
||||
import com.hanserwei.hannote.auth.domain.dataobject.RoleDO;
|
||||
import com.hanserwei.hannote.auth.domain.dataobject.RolePermissionDO;
|
||||
import com.hanserwei.hannote.auth.domain.mapper.PermissionDOMapper;
|
||||
import com.hanserwei.hannote.auth.domain.mapper.RoleDOMapper;
|
||||
import com.hanserwei.hannote.auth.domain.mapper.RolePermissionDOMapper;
|
||||
import jakarta.annotation.Resource;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.boot.ApplicationArguments;
|
||||
import org.springframework.boot.ApplicationRunner;
|
||||
import org.springframework.data.redis.core.RedisTemplate;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@Slf4j
|
||||
@Component
|
||||
public class PushRolePermissions2RedisRunner implements ApplicationRunner {
|
||||
@Resource
|
||||
private RedisTemplate<String, String> redisTemplate;
|
||||
@Resource
|
||||
private RoleDOMapper roleDOMapper;
|
||||
@Resource
|
||||
private PermissionDOMapper permissionDOMapper;
|
||||
@Resource
|
||||
private RolePermissionDOMapper rolePermissionDOMapper;
|
||||
|
||||
// 权限同步标记 Key
|
||||
private static final String PUSH_PERMISSION_FLAG = "push.permission.flag";
|
||||
|
||||
@Override
|
||||
public void run(ApplicationArguments args) {
|
||||
try {
|
||||
// 是否能够同步数据: 原子操作,只有在键 PUSH_PERMISSION_FLAG 不存在时,才会设置该键的值为 "1",并设置过期时间为 1 天
|
||||
boolean canPushed = Boolean.TRUE.equals(redisTemplate.opsForValue().setIfAbsent(PUSH_PERMISSION_FLAG, "1", 1, TimeUnit.DAYS));
|
||||
|
||||
// 如果无法同步权限数据
|
||||
if (!canPushed) {
|
||||
log.warn("==> 角色权限数据已经同步至 Redis 中,不再同步...");
|
||||
return;
|
||||
}
|
||||
// 查询出所有角色
|
||||
List<RoleDO> roleDOS = roleDOMapper.selectEnabledList();
|
||||
|
||||
if (CollUtil.isNotEmpty(roleDOS)) {
|
||||
// 拿到所有角色的 ID
|
||||
List<Long> roleIds = roleDOS.stream().map(RoleDO::getId).toList();
|
||||
|
||||
// 根据角色 ID, 批量查询出所有角色对应的权限
|
||||
List<RolePermissionDO> rolePermissionDOS = rolePermissionDOMapper.selectByRoleIds(roleIds);
|
||||
// 按角色 ID 分组, 每个角色 ID 对应多个权限 ID
|
||||
Map<Long, List<Long>> roleIdPermissionIdsMap = rolePermissionDOS.stream().collect(
|
||||
Collectors.groupingBy(RolePermissionDO::getRoleId,
|
||||
Collectors.mapping(RolePermissionDO::getPermissionId, Collectors.toList()))
|
||||
);
|
||||
|
||||
// 查询 APP 端所有被启用的权限
|
||||
List<PermissionDO> permissionDOS = permissionDOMapper.selectAppEnabledList();
|
||||
// 权限 ID - 权限 DO
|
||||
Map<Long, PermissionDO> permissionIdDOMap = permissionDOS.stream().collect(
|
||||
Collectors.toMap(PermissionDO::getId, permissionDO -> permissionDO)
|
||||
);
|
||||
|
||||
// 组织 角色ID-权限 关系
|
||||
Map<String, List<String>> roleKeyPermissionMap = Maps.newHashMap();
|
||||
|
||||
// 循环所有角色
|
||||
roleDOS.forEach(roleDO -> {
|
||||
// 当前角色 roleKey
|
||||
String roleKey = roleDO.getRoleKey();
|
||||
// 当前角色 ID
|
||||
Long roleId = roleDO.getId();
|
||||
// 当前角色 ID 对应的权限 ID 集合
|
||||
List<Long> permissionIds = roleIdPermissionIdsMap.get(roleId);
|
||||
if (CollUtil.isNotEmpty(permissionIds)) {
|
||||
List<String> permissionKeys = Lists.newArrayList();
|
||||
permissionIds.forEach(permissionId -> {
|
||||
// 根据权限 ID 获取具体的权限 DO 对象
|
||||
PermissionDO permissionDO = permissionIdDOMap.get(permissionId);
|
||||
permissionKeys.add(permissionDO.getPermissionKey());
|
||||
});
|
||||
roleKeyPermissionMap.put(roleKey, permissionKeys);
|
||||
}
|
||||
});
|
||||
|
||||
// 同步至 Redis 中,方便后续网关查询鉴权使用
|
||||
roleKeyPermissionMap.forEach((roleId, permissions) -> {
|
||||
String key = RedisKeyConstants.buildRolePermissionsKey(roleId);
|
||||
redisTemplate.opsForValue().set(key, JsonUtils.toJsonString(permissions));
|
||||
});
|
||||
}
|
||||
|
||||
log.info("==> 服务启动,成功同步角色权限数据到 Redis 中...");
|
||||
} catch (Exception e) {
|
||||
log.error("==> 同步角色权限数据到 Redis 中失败: ", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,12 +1,10 @@
|
||||
package com.hanserwei.hannote.auth.service;
|
||||
|
||||
import com.baomidou.mybatisplus.extension.service.IService;
|
||||
import com.hanserwei.framework.common.response.Response;
|
||||
import com.hanserwei.hannote.auth.domain.dataobject.UserDO;
|
||||
import com.hanserwei.hannote.auth.model.vo.user.UpdatePasswordReqVO;
|
||||
import com.hanserwei.hannote.auth.model.vo.user.UserLoginReqVO;
|
||||
|
||||
public interface UserService extends IService<UserDO> {
|
||||
public interface AuthService {
|
||||
|
||||
/**
|
||||
* 登录与注册
|
||||
@@ -0,0 +1,130 @@
|
||||
package com.hanserwei.hannote.auth.service.impl;
|
||||
|
||||
import cn.dev33.satoken.stp.SaTokenInfo;
|
||||
import cn.dev33.satoken.stp.StpUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import com.google.common.base.Preconditions;
|
||||
import com.hanserwei.framework.biz.context.holder.LoginUserContextHolder;
|
||||
import com.hanserwei.framework.common.exception.ApiException;
|
||||
import com.hanserwei.framework.common.response.Response;
|
||||
import com.hanserwei.hannote.auth.constant.RedisKeyConstants;
|
||||
import com.hanserwei.hannote.auth.enums.LoginTypeEnum;
|
||||
import com.hanserwei.hannote.auth.enums.ResponseCodeEnum;
|
||||
import com.hanserwei.hannote.auth.model.vo.user.UpdatePasswordReqVO;
|
||||
import com.hanserwei.hannote.auth.model.vo.user.UserLoginReqVO;
|
||||
import com.hanserwei.hannote.auth.rpc.UserRpcService;
|
||||
import com.hanserwei.hannote.auth.service.AuthService;
|
||||
import com.hanserwei.hannote.user.dto.resp.FindUserByEmailRspDTO;
|
||||
import jakarta.annotation.Resource;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.springframework.data.redis.core.RedisTemplate;
|
||||
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
|
||||
import org.springframework.security.crypto.password.PasswordEncoder;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
@Slf4j
|
||||
@Service
|
||||
@RequiredArgsConstructor
|
||||
public class AuthServiceImpl implements AuthService {
|
||||
|
||||
|
||||
private final RedisTemplate<String, Object> redisTemplate;
|
||||
private final UserRpcService userRpcService;
|
||||
@Resource(name = "authTaskExecutor")
|
||||
private ThreadPoolTaskExecutor authTaskExecutor;
|
||||
private final PasswordEncoder passwordEncoder;
|
||||
|
||||
@Override
|
||||
public Response<String> loginAndRegister(UserLoginReqVO reqVO) {
|
||||
Integer loginType = reqVO.getType();
|
||||
String email = reqVO.getEmail();
|
||||
LoginTypeEnum loginTypeEnum = LoginTypeEnum.valueOf(loginType);
|
||||
|
||||
Long userId = null;
|
||||
|
||||
//noinspection DataFlowIssue
|
||||
switch (loginTypeEnum) {
|
||||
case VERIFICATION_CODE:
|
||||
String verificationCode = reqVO.getCode();
|
||||
//校验参数是否为空
|
||||
Preconditions.checkArgument(StringUtils.isNotBlank(verificationCode), "验证码不能为空");
|
||||
|
||||
//构建验证码的RedisKey
|
||||
String key = RedisKeyConstants.buildVerificationCodeKey(email);
|
||||
// 查询存储在 Redis 中该用户的登录验证码
|
||||
String sentCode = (String) redisTemplate.opsForValue().get(key);
|
||||
// 判断用户提交的验证码,与 Redis 中的验证码是否一致
|
||||
if (!StrUtil.equals(verificationCode, sentCode)) {
|
||||
throw new ApiException(ResponseCodeEnum.VERIFICATION_CODE_ERROR);
|
||||
}
|
||||
// RPC: 调用用户服务,注册用户
|
||||
Long userIdTmp = userRpcService.registerUser(email);
|
||||
|
||||
// 若调用用户服务,返回的用户 ID 为空,则提示登录失败
|
||||
if (Objects.isNull(userIdTmp)) {
|
||||
throw new ApiException(ResponseCodeEnum.LOGIN_FAIL);
|
||||
}
|
||||
|
||||
userId = userIdTmp;
|
||||
break;
|
||||
case PASSWORD:
|
||||
String password = reqVO.getPassword();
|
||||
|
||||
// RPC: 调用用户服务,通过手机号查询用户
|
||||
FindUserByEmailRspDTO findUserByEmailRspDTO = userRpcService.findUserByEmail(email);
|
||||
|
||||
// 判断该手机号是否注册
|
||||
if (Objects.isNull(findUserByEmailRspDTO)) {
|
||||
throw new ApiException(ResponseCodeEnum.USER_NOT_FOUND);
|
||||
}
|
||||
|
||||
// 拿到密文密码
|
||||
String encodePassword = findUserByEmailRspDTO.getPassword();
|
||||
|
||||
// 匹配密码是否一致
|
||||
boolean isPasswordCorrect = passwordEncoder.matches(password, encodePassword);
|
||||
|
||||
// 如果不正确,则抛出业务异常,提示用户名或者密码不正确
|
||||
if (!isPasswordCorrect) {
|
||||
throw new ApiException(ResponseCodeEnum.MAIL_OR_PASSWORD_ERROR);
|
||||
}
|
||||
|
||||
userId = findUserByEmailRspDTO.getId();
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
// SaToken 登录用户,并返回 token 令牌
|
||||
StpUtil.login(userId);
|
||||
|
||||
SaTokenInfo tokenInfo = StpUtil.getTokenInfo();
|
||||
|
||||
return Response.success(tokenInfo.getTokenValue());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Response<?> logout() {
|
||||
Long userId = LoginUserContextHolder.getUserId();
|
||||
authTaskExecutor.submit(() -> {
|
||||
Long userId2 = LoginUserContextHolder.getUserId();
|
||||
log.info("==> 异步线程中获取 userId: {}", userId2);
|
||||
});
|
||||
StpUtil.logout(userId);
|
||||
return Response.success();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Response<?> updatePassword(UpdatePasswordReqVO updatePasswordReqVO) {
|
||||
// 新密码
|
||||
String newPassword = updatePasswordReqVO.getNewPassword();
|
||||
// 加密后的密码
|
||||
String encodePassword = passwordEncoder.encode(newPassword);
|
||||
// RPC: 调用用户服务:更新密码
|
||||
userRpcService.updatePassword(encodePassword);
|
||||
return Response.success();
|
||||
}
|
||||
}
|
||||
@@ -1,196 +0,0 @@
|
||||
package com.hanserwei.hannote.auth.service.impl;
|
||||
|
||||
import cn.dev33.satoken.stp.SaTokenInfo;
|
||||
import cn.dev33.satoken.stp.StpUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||
import com.google.common.base.Preconditions;
|
||||
import com.hanserwei.framework.biz.context.holder.LoginUserContextHolder;
|
||||
import com.hanserwei.framework.common.enums.DeletedEnum;
|
||||
import com.hanserwei.framework.common.enums.StatusEnum;
|
||||
import com.hanserwei.framework.common.exception.ApiException;
|
||||
import com.hanserwei.framework.common.response.Response;
|
||||
import com.hanserwei.framework.common.utils.JsonUtils;
|
||||
import com.hanserwei.hannote.auth.constant.RedisKeyConstants;
|
||||
import com.hanserwei.hannote.auth.constant.RoleConstants;
|
||||
import com.hanserwei.hannote.auth.domain.dataobject.RoleDO;
|
||||
import com.hanserwei.hannote.auth.domain.dataobject.UserDO;
|
||||
import com.hanserwei.hannote.auth.domain.dataobject.UserRoleDO;
|
||||
import com.hanserwei.hannote.auth.domain.mapper.RoleDOMapper;
|
||||
import com.hanserwei.hannote.auth.domain.mapper.UserDOMapper;
|
||||
import com.hanserwei.hannote.auth.domain.mapper.UserRoleDOMapper;
|
||||
import com.hanserwei.hannote.auth.enums.LoginTypeEnum;
|
||||
import com.hanserwei.hannote.auth.enums.ResponseCodeEnum;
|
||||
import com.hanserwei.hannote.auth.model.vo.user.UpdatePasswordReqVO;
|
||||
import com.hanserwei.hannote.auth.model.vo.user.UserLoginReqVO;
|
||||
import com.hanserwei.hannote.auth.service.UserService;
|
||||
import jakarta.annotation.Resource;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.springframework.data.redis.core.RedisTemplate;
|
||||
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
|
||||
import org.springframework.security.crypto.password.PasswordEncoder;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.support.TransactionTemplate;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
|
||||
@Slf4j
|
||||
@Service
|
||||
@RequiredArgsConstructor
|
||||
public class UserServiceImpl extends ServiceImpl<UserDOMapper, UserDO> implements UserService {
|
||||
|
||||
|
||||
private final RedisTemplate<String, Object> redisTemplate;
|
||||
private final UserRoleDOMapper userRoleDOMapper;
|
||||
private final TransactionTemplate transactionTemplate;
|
||||
private final RoleDOMapper roleDOMapper;
|
||||
@Resource(name = "authTaskExecutor")
|
||||
private ThreadPoolTaskExecutor authTaskExecutor;
|
||||
private final PasswordEncoder passwordEncoder;
|
||||
|
||||
@Override
|
||||
public Response<String> loginAndRegister(UserLoginReqVO reqVO) {
|
||||
Integer loginType = reqVO.getType();
|
||||
String email = reqVO.getEmail();
|
||||
LoginTypeEnum loginTypeEnum = LoginTypeEnum.valueOf(loginType);
|
||||
|
||||
Long userId = null;
|
||||
|
||||
//noinspection DataFlowIssue
|
||||
switch (loginTypeEnum) {
|
||||
case VERIFICATION_CODE:
|
||||
String verificationCode = reqVO.getCode();
|
||||
//校验参数是否为空
|
||||
Preconditions.checkArgument(StringUtils.isNotBlank(verificationCode), "验证码不能为空");
|
||||
|
||||
//构建验证码的RedisKey
|
||||
String key = RedisKeyConstants.buildVerificationCodeKey(email);
|
||||
// 查询存储在 Redis 中该用户的登录验证码
|
||||
String sentCode = (String) redisTemplate.opsForValue().get(key);
|
||||
// 判断用户提交的验证码,与 Redis 中的验证码是否一致
|
||||
if (!StrUtil.equals(verificationCode, sentCode)) {
|
||||
throw new ApiException(ResponseCodeEnum.VERIFICATION_CODE_ERROR);
|
||||
}
|
||||
//通过邮箱查询用户
|
||||
UserDO userDO = this.getOne(new QueryWrapper<UserDO>().eq("email", email));
|
||||
log.info("==> 用户是否注册, email: {}, userDO: {}", email, JsonUtils.toJsonString(userDO));
|
||||
// 判断是否注册
|
||||
if (Objects.isNull(userDO)) {
|
||||
// 若此用户还没有注册,系统自动注册该用户
|
||||
userId = registerUser(email);
|
||||
} else {
|
||||
// 已注册,则获取其用户 ID
|
||||
userId = userDO.getId();
|
||||
}
|
||||
break;
|
||||
case PASSWORD:
|
||||
String password = reqVO.getPassword();
|
||||
// 根据邮箱号查询
|
||||
UserDO userDO1 = this.getOne(new QueryWrapper<UserDO>().eq("email", email));
|
||||
if (Objects.isNull(userDO1)){
|
||||
throw new ApiException(ResponseCodeEnum.USER_NOT_FOUND);
|
||||
}
|
||||
// 拿到密文密码
|
||||
String encodePassword = userDO1.getPassword();
|
||||
boolean isPasswordCorrect = passwordEncoder.matches(password, encodePassword);
|
||||
if (!isPasswordCorrect) {
|
||||
throw new ApiException(ResponseCodeEnum.MAIL_OR_PASSWORD_ERROR);
|
||||
}
|
||||
userId = userDO1.getId();
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
// SaToken 登录用户,并返回 token 令牌
|
||||
StpUtil.login(userId);
|
||||
|
||||
SaTokenInfo tokenInfo = StpUtil.getTokenInfo();
|
||||
|
||||
return Response.success(tokenInfo.getTokenValue());
|
||||
}
|
||||
|
||||
public Long registerUser(String email) {
|
||||
return transactionTemplate.execute(status -> {
|
||||
try {
|
||||
// 获取全局自增的小憨书ID
|
||||
Long hanNoteId = redisTemplate.opsForValue().increment(RedisKeyConstants.HAN_NOTE_ID_GENERATOR_KEY);
|
||||
UserDO userDO = UserDO.builder()
|
||||
.hanNoteId(String.valueOf(hanNoteId)) // 自动生成小红书号 ID
|
||||
.nickname("小憨憨" + hanNoteId) // 自动生成昵称, 如:小憨憨10000
|
||||
.status(StatusEnum.ENABLE.getValue()) // 状态为启用
|
||||
.email(email)
|
||||
.createTime(LocalDateTime.now())
|
||||
.updateTime(LocalDateTime.now())
|
||||
.isDeleted(DeletedEnum.NO.getValue()) // 逻辑删除
|
||||
.build();
|
||||
|
||||
// 添加入库
|
||||
this.save(userDO);
|
||||
|
||||
// 获取入库的用户ID
|
||||
Long userId = userDO.getId();
|
||||
|
||||
// 添加默认用户角色
|
||||
UserRoleDO userRoleDO = UserRoleDO.builder()
|
||||
.userId(userId)
|
||||
.roleId(RoleConstants.COMMON_USER_ROLE_ID)
|
||||
.createTime(LocalDateTime.now())
|
||||
.updateTime(LocalDateTime.now())
|
||||
.isDeleted(DeletedEnum.NO.getValue())
|
||||
.build();
|
||||
userRoleDOMapper.insert(userRoleDO);
|
||||
|
||||
RoleDO roleDO = roleDOMapper.selectByPrimaryKey(RoleConstants.COMMON_USER_ROLE_ID);
|
||||
|
||||
// 将该用户的角色 ID 存入 Redis 中,指定初始容量为 1,这样可以减少在扩容时的性能开销
|
||||
List<String> roles = new ArrayList<>(1);
|
||||
roles.add(roleDO.getRoleKey());
|
||||
|
||||
String userRolesKey = RedisKeyConstants.buildUserRoleKey(userId);
|
||||
redisTemplate.opsForValue().set(userRolesKey, JsonUtils.toJsonString(roles));
|
||||
|
||||
return userId;
|
||||
} catch (Exception e) {
|
||||
status.setRollbackOnly(); // 标记事务为回滚
|
||||
log.error("==> 系统注册用户异常: ", e);
|
||||
return null;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public Response<?> logout() {
|
||||
Long userId = LoginUserContextHolder.getUserId();
|
||||
authTaskExecutor.submit(() -> {
|
||||
Long userId2 = LoginUserContextHolder.getUserId();
|
||||
log.info("==> 异步线程中获取 userId: {}", userId2);
|
||||
});
|
||||
StpUtil.logout(userId);
|
||||
return Response.success();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Response<?> updatePassword(UpdatePasswordReqVO updatePasswordReqVO) {
|
||||
// 新密码
|
||||
String newPassword = updatePasswordReqVO.getNewPassword();
|
||||
// 加密后的密码
|
||||
String encodePassword = passwordEncoder.encode(newPassword);
|
||||
// 获取用户ID
|
||||
Long userId = LoginUserContextHolder.getUserId();
|
||||
|
||||
UserDO userDO = UserDO.builder()
|
||||
.id(userId)
|
||||
.password(encodePassword)
|
||||
.updateTime(LocalDateTime.now())
|
||||
.build();
|
||||
// 更新用户密码
|
||||
this.updateById(userDO);
|
||||
return Response.success();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user