feat: 用户可以用邮箱或者用户名登录,修改部分缺陷

This commit is contained in:
Bunny 2024-10-27 17:27:04 +08:00
parent deb521abcd
commit d08946ec5e
34 changed files with 407 additions and 171 deletions

View File

@ -1,5 +1,7 @@
package cn.bunny.common.service.utils; package cn.bunny.common.service.utils;
import cn.bunny.common.service.exception.BunnyException;
import cn.bunny.dao.pojo.result.ResultCodeEnum;
import io.jsonwebtoken.*; import io.jsonwebtoken.*;
import io.micrometer.common.lang.Nullable; import io.micrometer.common.lang.Nullable;
import org.springframework.util.StringUtils; import org.springframework.util.StringUtils;
@ -184,16 +186,16 @@ public class JwtHelper {
* 根据用户名和ID创建token * 根据用户名和ID创建token
* *
* @param userId 用户ID * @param userId 用户ID
* @param userName 用户名 * @param username 用户名
* @param day 过期时间 * @param day 过期时间
* @return token值 * @return token值
*/ */
public static String createToken(Long userId, String userName, Integer day) { public static String createToken(Long userId, String username, Integer day) {
return Jwts.builder() return Jwts.builder()
.setSubject(subject) .setSubject(subject)
.setExpiration(new Date(System.currentTimeMillis() + tokenExpiration * day)) .setExpiration(new Date(System.currentTimeMillis() + tokenExpiration * day))
.claim("userId", userId) .claim("userId", userId)
.claim("userName", userName) .claim("username", username)
.setId(UUID.randomUUID().toString()) .setId(UUID.randomUUID().toString())
.signWith(SignatureAlgorithm.HS256, tokenSignKey) .signWith(SignatureAlgorithm.HS256, tokenSignKey)
.compressWith(CompressionCodecs.GZIP) .compressWith(CompressionCodecs.GZIP)
@ -208,14 +210,14 @@ public class JwtHelper {
*/ */
public static Map<String, Object> getMapByToken(String token) { public static Map<String, Object> getMapByToken(String token) {
try { try {
if (!StringUtils.hasText(token)) return null; if (!StringUtils.hasText(token)) throw new BunnyException(ResultCodeEnum.TOKEN_PARSING_FAILED);
Claims claims = Jwts.parser().setSigningKey(tokenSignKey).parseClaimsJws(token).getBody(); Claims claims = Jwts.parser().setSigningKey(tokenSignKey).parseClaimsJws(token).getBody();
// body 值转为map // body 值转为map
return new HashMap<>(claims); return new HashMap<>(claims);
} catch (Exception exception) { } catch (Exception exception) {
return null; throw new BunnyException(ResultCodeEnum.TOKEN_PARSING_FAILED);
} }
} }
@ -228,14 +230,14 @@ public class JwtHelper {
*/ */
public static Map<String, Object> getMapByToken(String token, String signKey) { public static Map<String, Object> getMapByToken(String token, String signKey) {
try { try {
if (!StringUtils.hasText(token)) return null; if (!StringUtils.hasText(token)) throw new BunnyException(ResultCodeEnum.TOKEN_PARSING_FAILED);
Jws<Claims> claimsJws = Jwts.parser().setSigningKey(signKey).parseClaimsJws(token); Jws<Claims> claimsJws = Jwts.parser().setSigningKey(signKey).parseClaimsJws(token);
Claims body = claimsJws.getBody(); Claims body = claimsJws.getBody();
// body 值转为map // body 值转为map
return new HashMap<>(body); return new HashMap<>(body);
} catch (Exception exception) { } catch (Exception exception) {
return null; throw new BunnyException(ResultCodeEnum.TOKEN_PARSING_FAILED);
} }
} }
@ -252,14 +254,14 @@ public class JwtHelper {
@Nullable @Nullable
private static String getSubjectByTokenHandler(String token, String tokenSignKey) { private static String getSubjectByTokenHandler(String token, String tokenSignKey) {
try { try {
if (!StringUtils.hasText(token)) return null; if (!StringUtils.hasText(token)) throw new BunnyException(ResultCodeEnum.TOKEN_PARSING_FAILED);
Jws<Claims> claimsJws = Jwts.parser().setSigningKey(tokenSignKey).parseClaimsJws(token); Jws<Claims> claimsJws = Jwts.parser().setSigningKey(tokenSignKey).parseClaimsJws(token);
Claims body = claimsJws.getBody(); Claims body = claimsJws.getBody();
return body.getSubject(); return body.getSubject();
} catch (Exception exception) { } catch (Exception exception) {
return null; throw new BunnyException(ResultCodeEnum.TOKEN_PARSING_FAILED);
} }
} }
@ -281,14 +283,14 @@ public class JwtHelper {
*/ */
public static Long getUserId(String token) { public static Long getUserId(String token) {
try { try {
if (!StringUtils.hasText(token)) return null; if (!StringUtils.hasText(token)) throw new BunnyException(ResultCodeEnum.TOKEN_PARSING_FAILED);
Jws<Claims> claimsJws = Jwts.parser().setSigningKey(tokenSignKey).parseClaimsJws(token); Jws<Claims> claimsJws = Jwts.parser().setSigningKey(tokenSignKey).parseClaimsJws(token);
Claims claims = claimsJws.getBody(); Claims claims = claimsJws.getBody();
return Long.valueOf(String.valueOf(claims.get("userId"))); return Long.valueOf(String.valueOf(claims.get("userId")));
} catch (Exception exception) { } catch (Exception exception) {
return null; throw new BunnyException(ResultCodeEnum.TOKEN_PARSING_FAILED);
} }
} }
@ -304,9 +306,9 @@ public class JwtHelper {
Jws<Claims> claimsJws = Jwts.parser().setSigningKey(tokenSignKey).parseClaimsJws(token); Jws<Claims> claimsJws = Jwts.parser().setSigningKey(tokenSignKey).parseClaimsJws(token);
Claims claims = claimsJws.getBody(); Claims claims = claimsJws.getBody();
return (String) claims.get("userName"); return (String) claims.get("username");
} catch (Exception exception) { } catch (Exception exception) {
return null; throw new BunnyException(ResultCodeEnum.TOKEN_PARSING_FAILED);
} }
} }

View File

@ -21,10 +21,10 @@ public class AdminUserAddDto {
@NotNull(message = "用户名不能为空") @NotNull(message = "用户名不能为空")
private String username; private String username;
@Schema(name = "nickName", title = "昵称") @Schema(name = "nickname", title = "昵称")
@NotBlank(message = "昵称不能为空") @NotBlank(message = "昵称不能为空")
@NotNull(message = "昵称不能为空") @NotNull(message = "昵称不能为空")
private String nickName; private String nickname;
@Schema(name = "email", title = "邮箱") @Schema(name = "email", title = "邮箱")
@NotBlank(message = "邮箱不能为空") @NotBlank(message = "邮箱不能为空")

View File

@ -18,8 +18,8 @@ public class AdminUserDto {
@Schema(name = "username", title = "用户名") @Schema(name = "username", title = "用户名")
private String username; private String username;
@Schema(name = "nickName", title = "昵称") @Schema(name = "nickname", title = "昵称")
private String nickName; private String nickname;
@Schema(name = "email", title = "邮箱") @Schema(name = "email", title = "邮箱")
private String email; private String email;

View File

@ -16,15 +16,10 @@ import lombok.NoArgsConstructor;
@Schema(name = "AdminUserUpdateByLocalUserDto对象", title = "更新本地用户信息", description = "更新本地用户信息") @Schema(name = "AdminUserUpdateByLocalUserDto对象", title = "更新本地用户信息", description = "更新本地用户信息")
public class AdminUserUpdateByLocalUserDto { public class AdminUserUpdateByLocalUserDto {
@Schema(name = "username", title = "用户名") @Schema(name = "nickname", title = "昵称")
@NotBlank(message = "用户名不能为空")
@NotNull(message = "用户名不能为空")
private String username;
@Schema(name = "nickName", title = "昵称")
@NotBlank(message = "昵称不能为空") @NotBlank(message = "昵称不能为空")
@NotNull(message = "昵称不能为空") @NotNull(message = "昵称不能为空")
private String nickName; private String nickname;
@Schema(name = "email", title = "邮箱") @Schema(name = "email", title = "邮箱")
@NotBlank(message = "邮箱不能为空") @NotBlank(message = "邮箱不能为空")

View File

@ -24,10 +24,10 @@ public class AdminUserUpdateDto {
@NotNull(message = "用户名不能为空") @NotNull(message = "用户名不能为空")
private String username; private String username;
@Schema(name = "nickName", title = "昵称") @Schema(name = "nickname", title = "昵称")
@NotBlank(message = "昵称不能为空") @NotBlank(message = "昵称不能为空")
@NotNull(message = "昵称不能为空") @NotNull(message = "昵称不能为空")
private String nickName; private String nickname;
@Schema(name = "email", title = "邮箱") @Schema(name = "email", title = "邮箱")
@NotBlank(message = "邮箱不能为空") @NotBlank(message = "邮箱不能为空")

View File

@ -25,8 +25,8 @@ public class AdminUser extends BaseEntity {
@Schema(name = "username", title = "用户名") @Schema(name = "username", title = "用户名")
private String username; private String username;
@Schema(name = "nickName", title = "昵称") @Schema(name = "nickname", title = "昵称")
private String nickName; private String nickname;
@Schema(name = "email", title = "邮箱") @Schema(name = "email", title = "邮箱")
private String email; private String email;

View File

@ -55,7 +55,7 @@ public enum ResultCodeEnum {
SESSION_EXPIRATION(208, "会话过期"), SESSION_EXPIRATION(208, "会话过期"),
// 封禁 209 // 封禁 209
FAIL_NO_ACCESS_DENIED_USER_LOCKED(209, "该账户封禁"), FAIL_NO_ACCESS_DENIED_USER_LOCKED(209, "该账户封禁"),
THE_SAME_USER_HAS_LOGGED_IN(209, "相同用户已登录"), THE_SAME_USER_HAS_LOGGED_IN(209, "相同用户已登录"),
// 提示错误 // 提示错误
@ -71,6 +71,7 @@ public enum ResultCodeEnum {
FAIL_NO_ACCESS_DENIED(403, "无权访问"), FAIL_NO_ACCESS_DENIED(403, "无权访问"),
FAIL_NO_ACCESS_DENIED_USER_OFFLINE(403, "用户强制下线"), FAIL_NO_ACCESS_DENIED_USER_OFFLINE(403, "用户强制下线"),
LOGGED_IN_FROM_ANOTHER_DEVICE(403, "没有权限访问"), LOGGED_IN_FROM_ANOTHER_DEVICE(403, "没有权限访问"),
TOKEN_PARSING_FAILED(403, "token解析失败"),
// 系统错误 500 // 系统错误 500
UNKNOWN_EXCEPTION(500, "服务异常"), UNKNOWN_EXCEPTION(500, "服务异常"),

View File

@ -0,0 +1,37 @@
package cn.bunny.dao.view;
import com.baomidou.mybatisplus.annotation.TableName;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Getter;
import lombok.Setter;
import lombok.experimental.Accessors;
@Setter
@Getter
@Accessors(chain = true)
@TableName("sys_role_power")
@Schema(name = "ViewRolePower对象", title = "角色权限关系视图", description = "角色权限关系视图")
public class ViewRolePower {
@Schema(name = "roleId", title = "角色ID")
private Long roleId;
@Schema(name = "roleCode", title = "角色代码")
private String roleCode;
@Schema(name = "description", title = "描述")
private String description;
@Schema(name = "parentId", title = "父级id")
private Long parentId;
@Schema(name = "parentId", title = "权限编码")
private String powerCode;
@Schema(name = "powerName", title = "权限名称")
private String powerName;
@Schema(name = "requestUrl", title = "请求路径")
private String requestUrl;
}

View File

@ -0,0 +1,58 @@
package cn.bunny.dao.view;
import com.baomidou.mybatisplus.annotation.TableName;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Getter;
import lombok.Setter;
import lombok.experimental.Accessors;
@Getter
@Setter
@Accessors(chain = true)
@TableName("sys_router_role")
@Schema(name = "RouterRoleViewRouterRole象", title = "路由角色关系视图", description = "路由角色关系视图")
public class ViewRouterRole {
@Schema(name = "routerId", title = "路由ID")
private Long routerId;
@Schema(name = "parentId", title = "父级id")
private Long parentId;
@Schema(name = "path", title = "在项目中路径")
private String path;
@Schema(name = "component", title = "组件位置")
private String component;
@Schema(name = "frameSrc", title = "frame路径")
private String frameSrc;
@Schema(name = "routeName", title = "路由名称")
private String routeName;
@Schema(name = "title", title = "路由title")
private String title;
@Schema(name = "menuType", title = "菜单类型")
private Integer menuType;
@Schema(name = "icon", title = "图标")
private String icon;
@Schema(name = "routerRank", title = "等级")
private Integer routerRank;
@Schema(name = "visible", title = "是否显示")
private Boolean visible;
@Schema(name = "roleId", title = "角色ID")
private Long roleId;
@Schema(name = "roleCode", title = "角色代码")
private String roleCode;
@Schema(name = "description", title = "描述")
private String description;
}

View File

@ -1,4 +1,4 @@
package cn.bunny.dao.entity.system; package cn.bunny.dao.view;
import cn.bunny.dao.entity.BaseEntity; import cn.bunny.dao.entity.BaseEntity;
import com.baomidou.mybatisplus.annotation.TableName; import com.baomidou.mybatisplus.annotation.TableName;
@ -20,13 +20,13 @@ import lombok.experimental.Accessors;
@Accessors(chain = true) @Accessors(chain = true)
@TableName("sys_user") @TableName("sys_user")
@Schema(name = "AdminUserAndDept对象", title = "用户信息和部门Id", description = "用户信息和部门Id") @Schema(name = "AdminUserAndDept对象", title = "用户信息和部门Id", description = "用户信息和部门Id")
public class AdminUserAndDept extends BaseEntity { public class ViewUserDept extends BaseEntity {
@Schema(name = "username", title = "用户名") @Schema(name = "username", title = "用户名")
private String username; private String username;
@Schema(name = "nickName", title = "昵称") @Schema(name = "nickname", title = "昵称")
private String nickName; private String nickname;
@Schema(name = "email", title = "邮箱") @Schema(name = "email", title = "邮箱")
private String email; private String email;

View File

@ -17,8 +17,8 @@ public class AdminUserVo extends BaseVo {
@Schema(name = "username", title = "用户名") @Schema(name = "username", title = "用户名")
private String username; private String username;
@Schema(name = "nickName", title = "昵称") @Schema(name = "nickname", title = "昵称")
private String nickName; private String nickname;
@Schema(name = "email", title = "邮箱") @Schema(name = "email", title = "邮箱")
private String email; private String email;

View File

@ -17,6 +17,7 @@ import java.util.List;
@Builder @Builder
@Schema(name = "LoginVo对象", title = "登录成功返回内容", description = "登录成功返回内容") @Schema(name = "LoginVo对象", title = "登录成功返回内容", description = "登录成功返回内容")
public class LoginVo extends BaseVo { public class LoginVo extends BaseVo {
@Schema(name = "nickname", title = "昵称") @Schema(name = "nickname", title = "昵称")
private String nickname; private String nickname;
@ -65,4 +66,7 @@ public class LoginVo extends BaseVo {
@Schema(name = "powerList", title = "权限列表") @Schema(name = "powerList", title = "权限列表")
private List<String> permissions = new ArrayList<>(); private List<String> permissions = new ArrayList<>();
@Schema(name = "readMeDay", title = "记住我多久")
private Long readMeDay;
} }

View File

@ -12,8 +12,8 @@ import lombok.*;
@Schema(name = "LoginVo对象", title = "登录成功返回内容", description = "登录成功返回内容") @Schema(name = "LoginVo对象", title = "登录成功返回内容", description = "登录成功返回内容")
public class UserVo extends BaseVo { public class UserVo extends BaseVo {
@Schema(name = "nickName", title = "昵称") @Schema(name = "nickname", title = "昵称")
private String nickName; private String nickname;
@Schema(name = "username", title = "用户名") @Schema(name = "username", title = "用户名")
private String username; private String username;

View File

@ -6,6 +6,7 @@ import cn.bunny.dao.pojo.result.PageResult;
import cn.bunny.dao.pojo.result.Result; import cn.bunny.dao.pojo.result.Result;
import cn.bunny.dao.pojo.result.ResultCodeEnum; import cn.bunny.dao.pojo.result.ResultCodeEnum;
import cn.bunny.dao.vo.system.user.AdminUserVo; import cn.bunny.dao.vo.system.user.AdminUserVo;
import cn.bunny.dao.vo.system.user.LoginVo;
import cn.bunny.dao.vo.system.user.RefreshTokenVo; import cn.bunny.dao.vo.system.user.RefreshTokenVo;
import cn.bunny.dao.vo.system.user.UserVo; import cn.bunny.dao.vo.system.user.UserVo;
import cn.bunny.services.service.UserService; import cn.bunny.services.service.UserService;
@ -44,8 +45,8 @@ public class UserController {
@Operation(summary = "获取本地登录用户信息", description = "获取本地登录用户信息") @Operation(summary = "获取本地登录用户信息", description = "获取本地登录用户信息")
@GetMapping("noManage/getUserinfo") @GetMapping("noManage/getUserinfo")
public Mono<Result<UserVo>> getUserinfo() { public Mono<Result<LoginVo>> getUserinfo() {
UserVo vo = userService.getUserinfo(); LoginVo vo = userService.getUserinfo();
return Mono.just(Result.success(vo)); return Mono.just(Result.success(vo));
} }

View File

@ -35,7 +35,6 @@ import java.util.regex.Matcher;
import java.util.regex.Pattern; import java.util.regex.Pattern;
@Component @Component
@Transactional
public class UserFactory { public class UserFactory {
@Autowired @Autowired
private PowerMapper powerMapper; private PowerMapper powerMapper;
@ -55,17 +54,18 @@ public class UserFactory {
@Autowired @Autowired
private MinioUtil minioUtil; private MinioUtil minioUtil;
public LoginVo buildUserVo(AdminUser user, long readMeDay) { @Transactional
// 创建token public LoginVo buildLoginUserVo(AdminUser user, long readMeDay) {
Long userId = user.getId(); Long userId = user.getId();
String email = user.getEmail(); String email = user.getEmail();
String token = JwtHelper.createToken(userId, email, (int) readMeDay); String username = user.getUsername();
// 获取IP地址 // 使用用户名创建token
String token = JwtHelper.createToken(userId, username, (int) readMeDay);
// 获取IP地址并更新用户登录信息
String ipAddr = IpUtil.getCurrentUserIpAddress().getIpAddr(); String ipAddr = IpUtil.getCurrentUserIpAddress().getIpAddr();
String ipRegion = IpUtil.getCurrentUserIpAddress().getIpRegion(); String ipRegion = IpUtil.getCurrentUserIpAddress().getIpRegion();
// 更新用户登录信息
setUpdateUser(userId, ipAddr, ipRegion); setUpdateUser(userId, ipAddr, ipRegion);
// 将用户登录保存在用户登录日志表中 // 将用户登录保存在用户登录日志表中
@ -74,8 +74,8 @@ public class UserFactory {
// 设置用户返回信息 // 设置用户返回信息
LoginVo loginVo = setLoginVo(user, token, readMeDay, ipAddr, ipRegion); LoginVo loginVo = setLoginVo(user, token, readMeDay, ipAddr, ipRegion);
// 将信息保存在Redis中 // 将信息保存在Redis中一定要确保用户名是唯一的
redisTemplate.opsForValue().set(RedisUserConstant.getAdminLoginInfoPrefix(email), loginVo, readMeDay, TimeUnit.DAYS); redisTemplate.opsForValue().set(RedisUserConstant.getAdminLoginInfoPrefix(username), loginVo, readMeDay, TimeUnit.DAYS);
// 将Redis中验证码删除 // 将Redis中验证码删除
redisTemplate.delete(RedisUserConstant.getAdminUserEmailCodePrefix(email)); redisTemplate.delete(RedisUserConstant.getAdminUserEmailCodePrefix(email));
@ -83,6 +83,20 @@ public class UserFactory {
return loginVo; return loginVo;
} }
public void buildUserVo(AdminUser user, long readMeDay) {
Long userId = user.getId();
String username = user.getUsername();
// 使用用户名创建token
String token = JwtHelper.createToken(userId, username, (int) readMeDay);
// 设置用户返回信息
LoginVo loginVo = setLoginVo(user, token, readMeDay, user.getIpAddress(), user.getIpRegion());
// 将信息保存在Redis中一定要确保用户名是唯一的
redisTemplate.opsForValue().set(RedisUserConstant.getAdminLoginInfoPrefix(username), loginVo, readMeDay, TimeUnit.DAYS);
}
/** /**
* * 设置更新用户设置内容 * * 设置更新用户设置内容
@ -90,9 +104,10 @@ public class UserFactory {
public LoginVo setLoginVo(AdminUser user, String token, long readMeDay, String ipAddr, String ipRegion) { public LoginVo setLoginVo(AdminUser user, String token, long readMeDay, String ipAddr, String ipRegion) {
Long userId = user.getId(); Long userId = user.getId();
// 判断用户是否有头像如果没有头像设置默认头像 // 判断用户是否有头像如果没有头像设置默认头像并且用户头像不能和默认头像相同
String avatar = user.getAvatar(); String avatar = user.getAvatar();
avatar = StringUtils.hasText(avatar) ? minioUtil.getObjectNameFullPath(avatar) : UserConstant.USER_AVATAR; String userAvatar = UserConstant.USER_AVATAR;
avatar = StringUtils.hasText(avatar) && !avatar.equals(userAvatar) ? minioUtil.getObjectNameFullPath(avatar) : userAvatar;
// 查找用户橘色 // 查找用户橘色
List<String> roles = new ArrayList<>(roleMapper.selectListByUserId(userId).stream().map(Role::getRoleCode).toList()); List<String> roles = new ArrayList<>(roleMapper.selectListByUserId(userId).stream().map(Role::getRoleCode).toList());
@ -113,7 +128,7 @@ public class UserFactory {
// 构建返回对象设置用户需要内容 // 构建返回对象设置用户需要内容
LoginVo loginVo = new LoginVo(); LoginVo loginVo = new LoginVo();
BeanUtils.copyProperties(user, loginVo); BeanUtils.copyProperties(user, loginVo);
loginVo.setNickname(user.getNickName()); loginVo.setNickname(user.getNickname());
loginVo.setAvatar(avatar); loginVo.setAvatar(avatar);
loginVo.setToken(token); loginVo.setToken(token);
loginVo.setRefreshToken(token); loginVo.setRefreshToken(token);
@ -122,7 +137,9 @@ public class UserFactory {
loginVo.setRoles(roles); loginVo.setRoles(roles);
loginVo.setPermissions(permissions); loginVo.setPermissions(permissions);
loginVo.setUpdateUser(userId); loginVo.setUpdateUser(userId);
loginVo.setPersonDescription(user.getSummary());
loginVo.setExpires(expires); loginVo.setExpires(expires);
loginVo.setReadMeDay(readMeDay);
return loginVo; return loginVo;
} }
@ -132,6 +149,7 @@ public class UserFactory {
* *
* @param userId 用户ID * @param userId 用户ID
*/ */
@Transactional
public void setUpdateUser(Long userId, String ipAddr, String ipRegion) { public void setUpdateUser(Long userId, String ipAddr, String ipRegion) {
// 设置用户IP地址并更新用户信息 // 设置用户IP地址并更新用户信息
AdminUser updateUser = new AdminUser(); AdminUser updateUser = new AdminUser();
@ -148,7 +166,11 @@ public class UserFactory {
* @return 整理好的头像内容 * @return 整理好的头像内容
*/ */
public String checkUserAvatar(String avatar) { public String checkUserAvatar(String avatar) {
if (!StringUtils.hasText(avatar)) return null; // 如果用户没有头像或者用户头像和默认头像相同返回默认头像
String userAvatar = UserConstant.USER_AVATAR;
if (!StringUtils.hasText(avatar) || avatar.equals(userAvatar)) return userAvatar;
// 替换前端发送的host前缀将其删除只保留路径名称
String regex = "^https?://.*?/(.*)"; String regex = "^https?://.*?/(.*)";
Pattern pattern = Pattern.compile(regex); Pattern pattern = Pattern.compile(regex);
Matcher matcher = pattern.matcher(avatar); Matcher matcher = pattern.matcher(avatar);

View File

@ -46,11 +46,4 @@ public interface PowerMapper extends BaseMapper<Power> {
@NotNull @NotNull
List<Power> selectListByUserId(long userId); List<Power> selectListByUserId(long userId);
/**
* * 根据权限码查询可以访问URL
*
* @param powerCodes 权限码
* @return 权限列表
*/
List<Power> selectListByPowerCodes(List<String> powerCodes);
} }

View File

@ -1,7 +1,7 @@
package cn.bunny.services.mapper; package cn.bunny.services.mapper;
import cn.bunny.dao.entity.system.Power;
import cn.bunny.dao.entity.system.RolePower; import cn.bunny.dao.entity.system.RolePower;
import cn.bunny.dao.view.ViewRolePower;
import com.baomidou.mybatisplus.core.mapper.BaseMapper; import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.apache.ibatis.annotations.Mapper; import org.apache.ibatis.annotations.Mapper;
@ -41,10 +41,9 @@ public interface RolePowerMapper extends BaseMapper<RolePower> {
List<RolePower> selectPowerListByRoleId(Long roleId); List<RolePower> selectPowerListByRoleId(Long roleId);
/** /**
* * 根据角色id列表获取权限内容 * 查看所有角色关联的权限
* *
* @param roleIds 角色id列表 * @return 角色权限关系视图
* @return 已选择的权限列表
*/ */
List<Power> selectPowerListByRoleIds(List<Long> roleIds); List<ViewRolePower> viewRolePowerWithAll();
} }

View File

@ -1,6 +1,7 @@
package cn.bunny.services.mapper; package cn.bunny.services.mapper;
import cn.bunny.dao.entity.system.RouterRole; import cn.bunny.dao.entity.system.RouterRole;
import cn.bunny.dao.view.ViewRouterRole;
import com.baomidou.mybatisplus.core.mapper.BaseMapper; import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.apache.ibatis.annotations.Mapper; import org.apache.ibatis.annotations.Mapper;
@ -30,4 +31,11 @@ public interface RouterRoleMapper extends BaseMapper<RouterRole> {
* @param roleIds 角色id列表 * @param roleIds 角色id列表
*/ */
void deleteBatchIdsByRoleIdsWithPhysics(List<Long> roleIds); void deleteBatchIdsByRoleIdsWithPhysics(List<Long> roleIds);
/**
* 查看所有路由关联角色
*
* @return 路由角色关系视图列表
*/
List<ViewRouterRole> viewRouterRolesWithAll();
} }

View File

@ -2,7 +2,7 @@ package cn.bunny.services.mapper;
import cn.bunny.dao.dto.system.user.AdminUserDto; import cn.bunny.dao.dto.system.user.AdminUserDto;
import cn.bunny.dao.entity.system.AdminUser; import cn.bunny.dao.entity.system.AdminUser;
import cn.bunny.dao.entity.system.AdminUserAndDept; import cn.bunny.dao.view.ViewUserDept;
import com.baomidou.mybatisplus.core.mapper.BaseMapper; import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.baomidou.mybatisplus.core.metadata.IPage; import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
@ -29,7 +29,7 @@ public interface UserMapper extends BaseMapper<AdminUser> {
* @param dto 用户信息查询表单 * @param dto 用户信息查询表单
* @return 用户信息分页结果 * @return 用户信息分页结果
*/ */
IPage<AdminUserAndDept> selectListByPage(@Param("page") Page<AdminUser> pageParams, @Param("dto") AdminUserDto dto); IPage<ViewUserDept> selectListByPage(@Param("page") Page<AdminUser> pageParams, @Param("dto") AdminUserDto dto);
/** /**
* 物理删除用户信息 * 物理删除用户信息

View File

@ -38,7 +38,7 @@ public class CustomCheckIsAdmin {
boolean isAdmin = roleList.stream().anyMatch(role -> role.equals("admin")); boolean isAdmin = roleList.stream().anyMatch(role -> role.equals("admin"));
// 判断是否是 admin // 判断是否是 admin
if (!isIdAdmin || !isAdmin) { if (isIdAdmin || isAdmin) {
roleList.add("admin"); roleList.add("admin");
permissions.add("*"); permissions.add("*");
permissions.add("*::*"); permissions.add("*::*");

View File

@ -41,9 +41,11 @@ public class NoTokenAuthenticationFilter extends OncePerRequestFilter {
return; return;
} }
// 查找 Redis // 解析JWT中的用户名
String username = JwtHelper.getUsername(token); String username = JwtHelper.getUsername(token);
Long userId = JwtHelper.getUserId(token); Long userId = JwtHelper.getUserId(token);
// 查找 Redis
Object loginVoObject = redisTemplate.opsForValue().get(RedisUserConstant.getAdminLoginInfoPrefix(username)); Object loginVoObject = redisTemplate.opsForValue().get(RedisUserConstant.getAdminLoginInfoPrefix(username));
LoginVo loginVo = JSON.parseObject(JSON.toJSONString(loginVoObject), LoginVo.class); LoginVo loginVo = JSON.parseObject(JSON.toJSONString(loginVoObject), LoginVo.class);

View File

@ -34,11 +34,9 @@ public class TokenAuthenticationFilter extends OncePerRequestFilter {
*/ */
private UsernamePasswordAuthenticationToken getAuthentication() { private UsernamePasswordAuthenticationToken getAuthentication() {
// 请求头是否有token // 请求头是否有token
LoginVo LoginVo = BaseContext.getLoginVo(); LoginVo loginVo = BaseContext.getLoginVo();
String username = loginVo.getUsername();
// 通过username从redis获取权限数据 List<String> roleList = loginVo.getRoles();
String username = LoginVo.getUsername();
List<String> roleList = LoginVo.getRoles();
// 角色列表 // 角色列表
List<SimpleGrantedAuthority> authList = roleList.stream().map(SimpleGrantedAuthority::new).toList(); List<SimpleGrantedAuthority> authList = roleList.stream().map(SimpleGrantedAuthority::new).toList();

View File

@ -2,6 +2,7 @@ package cn.bunny.services.security.filter;
import cn.bunny.dao.dto.system.user.LoginDto; import cn.bunny.dao.dto.system.user.LoginDto;
import cn.bunny.dao.pojo.constant.RedisUserConstant;
import cn.bunny.dao.pojo.result.Result; import cn.bunny.dao.pojo.result.Result;
import cn.bunny.dao.pojo.result.ResultCodeEnum; import cn.bunny.dao.pojo.result.ResultCodeEnum;
import cn.bunny.dao.vo.system.user.LoginVo; import cn.bunny.dao.vo.system.user.LoginVo;
@ -58,21 +59,25 @@ public class TokenLoginFilterService extends UsernamePasswordAuthenticationFilte
try { try {
loginDto = objectMapper.readValue(request.getInputStream(), LoginDto.class); loginDto = objectMapper.readValue(request.getInputStream(), LoginDto.class);
String emailCode = loginDto.getEmailCode().toLowerCase(); String emailCode = loginDto.getEmailCode();
String username = loginDto.getUsername(); String username = loginDto.getUsername();
String password = loginDto.getPassword(); String password = loginDto.getPassword();
// Object redisEmailCode = redisTemplate.opsForValue().get(RedisUserConstant.getAdminUserEmailCodePrefix(username)); // 如果有邮箱验证码表示是邮箱登录
// if (redisEmailCode == null) { if (StringUtils.hasText(emailCode)) {
// out(response, Result.error(ResultCodeEnum.EMAIL_CODE_EMPTY)); emailCode = emailCode.toLowerCase();
// return null; Object redisEmailCode = redisTemplate.opsForValue().get(RedisUserConstant.getAdminUserEmailCodePrefix(username));
// } if (redisEmailCode == null) {
out(response, Result.error(ResultCodeEnum.EMAIL_CODE_EMPTY));
return null;
}
// 判断用户邮箱验证码是否和Redis中发送的验证码 // 判断用户邮箱验证码是否和Redis中发送的验证码
// if (!emailCode.equals(redisEmailCode.toString().toLowerCase())) { if (!emailCode.equals(redisEmailCode.toString().toLowerCase())) {
// out(response, Result.error(ResultCodeEnum.EMAIL_CODE_NOT_MATCHING)); out(response, Result.error(ResultCodeEnum.EMAIL_CODE_NOT_MATCHING));
// return null; return null;
// } }
}
Authentication authenticationToken = new UsernamePasswordAuthenticationToken(username, password); Authentication authenticationToken = new UsernamePasswordAuthenticationToken(username, password);
return getAuthenticationManager().authenticate(authenticationToken); return getAuthenticationManager().authenticate(authenticationToken);
@ -87,7 +92,8 @@ public class TokenLoginFilterService extends UsernamePasswordAuthenticationFilte
@Override @Override
protected void successfulAuthentication(HttpServletRequest request, HttpServletResponse response, FilterChain chain, Authentication auth) { protected void successfulAuthentication(HttpServletRequest request, HttpServletResponse response, FilterChain chain, Authentication auth) {
// 获取登录返回信息 // 获取登录返回信息
LoginVo loginVo = customUserDetailsService.login(loginDto); LoginVo loginVo = customUserDetailsService.login(loginDto, response);
if (loginVo == null) return;
// 判断用户是否禁用 // 判断用户是否禁用
if (loginVo.getStatus()) { if (loginVo.getStatus()) {

View File

@ -2,6 +2,7 @@ package cn.bunny.services.security.service;
import cn.bunny.dao.dto.system.user.LoginDto; import cn.bunny.dao.dto.system.user.LoginDto;
import cn.bunny.dao.vo.system.user.LoginVo; import cn.bunny.dao.vo.system.user.LoginVo;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.security.core.userdetails.UserDetails; import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService; import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException; import org.springframework.security.core.userdetails.UsernameNotFoundException;
@ -19,5 +20,5 @@ public interface CustomUserDetailsService extends UserDetailsService {
* @param loginDto 登录参数 * @param loginDto 登录参数
* @return 登录后结果返回 * @return 登录后结果返回
*/ */
LoginVo login(LoginDto loginDto); LoginVo login(LoginDto loginDto, HttpServletResponse response);
} }

View File

@ -3,12 +3,14 @@ package cn.bunny.services.security.service.impl;
import cn.bunny.common.service.exception.BunnyException; import cn.bunny.common.service.exception.BunnyException;
import cn.bunny.dao.dto.system.user.LoginDto; import cn.bunny.dao.dto.system.user.LoginDto;
import cn.bunny.dao.entity.system.AdminUser; import cn.bunny.dao.entity.system.AdminUser;
import cn.bunny.dao.pojo.result.Result;
import cn.bunny.dao.pojo.result.ResultCodeEnum; import cn.bunny.dao.pojo.result.ResultCodeEnum;
import cn.bunny.dao.vo.system.user.LoginVo; import cn.bunny.dao.vo.system.user.LoginVo;
import cn.bunny.services.factory.UserFactory; import cn.bunny.services.factory.UserFactory;
import cn.bunny.services.mapper.UserMapper; import cn.bunny.services.mapper.UserMapper;
import cn.bunny.services.security.custom.CustomUser; import cn.bunny.services.security.custom.CustomUser;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.authority.AuthorityUtils; import org.springframework.security.core.authority.AuthorityUtils;
import org.springframework.security.core.userdetails.UserDetails; import org.springframework.security.core.userdetails.UserDetails;
@ -16,6 +18,8 @@ import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import org.springframework.util.DigestUtils; import org.springframework.util.DigestUtils;
import static cn.bunny.common.service.utils.ResponseUtil.out;
@Component @Component
public class CustomUserDetailsServiceImpl implements cn.bunny.services.security.service.CustomUserDetailsService { public class CustomUserDetailsServiceImpl implements cn.bunny.services.security.service.CustomUserDetailsService {
@ -40,7 +44,7 @@ public class CustomUserDetailsServiceImpl implements cn.bunny.services.security.
// 根据邮箱查询用户名 // 根据邮箱查询用户名
AdminUser adminUser = userMapper.selectOne(queryWrapper); AdminUser adminUser = userMapper.selectOne(queryWrapper);
if (adminUser == null) throw new UsernameNotFoundException("用户不存在"); if (adminUser == null) throw new UsernameNotFoundException(ResultCodeEnum.USER_IS_EMPTY.getMessage());
return new CustomUser(adminUser, AuthorityUtils.createAuthorityList()); return new CustomUser(adminUser, AuthorityUtils.createAuthorityList());
} }
@ -53,22 +57,28 @@ public class CustomUserDetailsServiceImpl implements cn.bunny.services.security.
* @return 登录后结果返回 * @return 登录后结果返回
*/ */
@Override @Override
public LoginVo login(LoginDto loginDto) { public LoginVo login(LoginDto loginDto, HttpServletResponse response) {
String username = loginDto.getUsername(); String username = loginDto.getUsername();
String password = loginDto.getPassword(); String password = loginDto.getPassword();
Long readMeDay = loginDto.getReadMeDay(); Long readMeDay = loginDto.getReadMeDay();
// 查询用户相关内容 // 查询用户相关内容
LambdaQueryWrapper<AdminUser> queryWrapper = new LambdaQueryWrapper<AdminUser>() LambdaQueryWrapper<AdminUser> queryWrapper = new LambdaQueryWrapper<AdminUser>()
.eq(AdminUser::getEmail, username) .eq(AdminUser::getUsername, username)
.or() .or()
.eq(AdminUser::getUsername, username); .eq(AdminUser::getEmail, username);
AdminUser user = userMapper.selectOne(queryWrapper); AdminUser user = userMapper.selectOne(queryWrapper);
// 判断用户是否为空
if (user == null) {
out(response, Result.error(ResultCodeEnum.LOGIN_ERROR));
return null;
}
// 对登录密码进行md5加密判断是否与数据库中一致 // 对登录密码进行md5加密判断是否与数据库中一致
String md5Password = DigestUtils.md5DigestAsHex(password.getBytes()); String md5Password = DigestUtils.md5DigestAsHex(password.getBytes());
if (!user.getPassword().equals(md5Password)) throw new BunnyException(ResultCodeEnum.LOGIN_ERROR); if (!user.getPassword().equals(md5Password)) throw new BunnyException(ResultCodeEnum.LOGIN_ERROR);
return userFactory.buildUserVo(user, readMeDay); return userFactory.buildLoginUserVo(user, readMeDay);
} }
} }

View File

@ -4,6 +4,7 @@ import cn.bunny.dao.dto.system.user.*;
import cn.bunny.dao.entity.system.AdminUser; import cn.bunny.dao.entity.system.AdminUser;
import cn.bunny.dao.pojo.result.PageResult; import cn.bunny.dao.pojo.result.PageResult;
import cn.bunny.dao.vo.system.user.AdminUserVo; import cn.bunny.dao.vo.system.user.AdminUserVo;
import cn.bunny.dao.vo.system.user.LoginVo;
import cn.bunny.dao.vo.system.user.RefreshTokenVo; import cn.bunny.dao.vo.system.user.RefreshTokenVo;
import cn.bunny.dao.vo.system.user.UserVo; import cn.bunny.dao.vo.system.user.UserVo;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
@ -121,7 +122,7 @@ public interface UserService extends IService<AdminUser> {
* *
* @return 用户信息 * @return 用户信息
*/ */
UserVo getUserinfo(); LoginVo getUserinfo();
/** /**
* * 更新本地用户信息 * * 更新本地用户信息

View File

@ -6,18 +6,20 @@ import cn.bunny.dao.dto.system.router.RouterAddDto;
import cn.bunny.dao.dto.system.router.RouterManageDto; import cn.bunny.dao.dto.system.router.RouterManageDto;
import cn.bunny.dao.dto.system.router.RouterUpdateByIdWithRankDto; import cn.bunny.dao.dto.system.router.RouterUpdateByIdWithRankDto;
import cn.bunny.dao.dto.system.router.RouterUpdateDto; import cn.bunny.dao.dto.system.router.RouterUpdateDto;
import cn.bunny.dao.entity.system.Power;
import cn.bunny.dao.entity.system.Role; import cn.bunny.dao.entity.system.Role;
import cn.bunny.dao.entity.system.Router; import cn.bunny.dao.entity.system.Router;
import cn.bunny.dao.pojo.result.PageResult; import cn.bunny.dao.pojo.result.PageResult;
import cn.bunny.dao.pojo.result.ResultCodeEnum; import cn.bunny.dao.pojo.result.ResultCodeEnum;
import cn.bunny.dao.view.ViewRolePower;
import cn.bunny.dao.view.ViewRouterRole;
import cn.bunny.dao.vo.system.router.RouterManageVo; import cn.bunny.dao.vo.system.router.RouterManageVo;
import cn.bunny.dao.vo.system.router.RouterMeta; import cn.bunny.dao.vo.system.router.RouterMeta;
import cn.bunny.dao.vo.system.router.UserRouterVo; import cn.bunny.dao.vo.system.router.UserRouterVo;
import cn.bunny.services.factory.RouterServiceFactory; import cn.bunny.services.factory.RouterServiceFactory;
import cn.bunny.services.mapper.PowerMapper;
import cn.bunny.services.mapper.RoleMapper; import cn.bunny.services.mapper.RoleMapper;
import cn.bunny.services.mapper.RolePowerMapper;
import cn.bunny.services.mapper.RouterMapper; import cn.bunny.services.mapper.RouterMapper;
import cn.bunny.services.mapper.RouterRoleMapper;
import cn.bunny.services.security.custom.CustomCheckIsAdmin; import cn.bunny.services.security.custom.CustomCheckIsAdmin;
import cn.bunny.services.service.RouterService; import cn.bunny.services.service.RouterService;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
@ -31,9 +33,8 @@ import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional; import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils; import org.springframework.util.StringUtils;
import java.util.ArrayList; import java.util.*;
import java.util.Comparator; import java.util.stream.Collectors;
import java.util.List;
/** /**
* <p> * <p>
@ -53,7 +54,10 @@ public class RouterServiceImpl extends ServiceImpl<RouterMapper, Router> impleme
private RoleMapper roleMapper; private RoleMapper roleMapper;
@Autowired @Autowired
private PowerMapper powerMapper; private RouterRoleMapper routerRoleMapper;
@Autowired
private RolePowerMapper rolePowerMapper;
/** /**
* * 获取路由内容 * * 获取路由内容
@ -66,35 +70,68 @@ public class RouterServiceImpl extends ServiceImpl<RouterMapper, Router> impleme
Long userId = BaseContext.getUserId(); Long userId = BaseContext.getUserId();
// 查询角色信息 // 查询角色信息
List<Role> roleList = roleMapper.selectListByUserId(userId); List<Role> roleList;
List<String> roleCodeList = roleList.stream().map(Role::getRoleCode).toList(); List<String> userRoleCodeList;
if (userId.equals(1L)) {
userRoleCodeList = List.of("admin");
} else {
roleList = roleMapper.selectListByUserId(userId);
userRoleCodeList = roleList.stream().map(Role::getRoleCode).toList();
}
// 如果没有分配角色直接返回空数组 // 如果没有分配角色直接返回空数组
if (roleCodeList.isEmpty()) return new ArrayList<>(); if (userRoleCodeList.isEmpty()) return new ArrayList<>();
// 根据角色列表查询权限信息
List<Power> powerList = powerMapper.selectListByUserId(userId);
List<String> powerCodeList = powerList.stream().map(Power::getPowerCode).toList();
// 路由列表根据用户角色判断
List<Router> routerList;
// 返回路由列表 // 返回路由列表
List<UserRouterVo> list = new ArrayList<>(); List<UserRouterVo> list = new ArrayList<>();
// 查询用户角色判断是否是管理员角色 // 查询用户角色判断是否是管理员角色
boolean isAdmin = CustomCheckIsAdmin.checkAdmin(roleCodeList); boolean isAdmin = CustomCheckIsAdmin.checkAdmin(userRoleCodeList);
if (isAdmin) routerList = list();
else { // 查询路由和角色对应关系
List<Long> routerIds = baseMapper.selectListByUserId(userId); List<ViewRouterRole> routerRoleList = routerRoleMapper.viewRouterRolesWithAll();
routerList = baseMapper.selectParentListByRouterId(routerIds); Map<Long, List<String>> routerIdWithRoleCodeMap = routerRoleList.stream()
} .collect(Collectors.groupingBy(
ViewRouterRole::getRouterId,
Collectors.mapping(ViewRouterRole::getRoleCode, Collectors.toUnmodifiableList())
));
// 角色和权限对应关系
List<ViewRolePower> rolePowerList = rolePowerMapper.viewRolePowerWithAll();
Map<String, Set<String>> roleCodeWithPowerCodeMap = rolePowerList.stream()
.collect(Collectors.groupingBy(
ViewRolePower::getRoleCode,
Collectors.mapping(ViewRolePower::getPowerCode, Collectors.toUnmodifiableSet())
));
// 查询所有路由内容
List<Router> routerList = list();
// 构建返回路由列表 // 构建返回路由列表
List<UserRouterVo> routerVoList = routerList.stream() List<UserRouterVo> routerVoList = routerList.stream()
.sorted(Comparator.comparing(Router::getRouterRank)) .sorted(Comparator.comparing(Router::getRouterRank))
.filter(Router::getVisible) .filter(Router::getVisible)
.map(router -> { .map(router -> {
// 角色码列表
List<String> roleCodeList;
// 权限码列表
List<String> powerCodeList;
// 判断是否是admin
if (isAdmin) {
roleCodeList = userRoleCodeList;
powerCodeList = List.of("*", "*::*", "*::*::*");
} else {
roleCodeList = routerIdWithRoleCodeMap.getOrDefault(router.getId(), Collections.emptyList());
powerCodeList = roleCodeList.stream()
.map(roleCodeWithPowerCodeMap::get)
.filter(Objects::nonNull)
.flatMap(Set::stream)
.collect(Collectors.toUnmodifiableSet())
.stream().toList();
}
// 复制对象 // 复制对象
UserRouterVo routerVo = new UserRouterVo(); UserRouterVo routerVo = new UserRouterVo();
BeanUtils.copyProperties(router, routerVo); BeanUtils.copyProperties(router, routerVo);

View File

@ -1,9 +1,15 @@
package cn.bunny.services.service.impl; package cn.bunny.services.service.impl;
import cn.bunny.common.service.context.BaseContext;
import cn.bunny.common.service.exception.BunnyException; import cn.bunny.common.service.exception.BunnyException;
import cn.bunny.dao.dto.system.user.AssignRolesToUsersDto; import cn.bunny.dao.dto.system.user.AssignRolesToUsersDto;
import cn.bunny.dao.entity.system.AdminUser;
import cn.bunny.dao.entity.system.UserRole; import cn.bunny.dao.entity.system.UserRole;
import cn.bunny.dao.pojo.constant.RedisUserConstant;
import cn.bunny.dao.pojo.result.ResultCodeEnum; import cn.bunny.dao.pojo.result.ResultCodeEnum;
import cn.bunny.dao.vo.system.user.LoginVo;
import cn.bunny.services.factory.UserFactory;
import cn.bunny.services.mapper.UserMapper;
import cn.bunny.services.mapper.UserRoleMapper; import cn.bunny.services.mapper.UserRoleMapper;
import cn.bunny.services.service.UserRoleService; import cn.bunny.services.service.UserRoleService;
import com.baomidou.mybatisplus.core.toolkit.Wrappers; import com.baomidou.mybatisplus.core.toolkit.Wrappers;
@ -14,6 +20,7 @@ import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional; import org.springframework.transaction.annotation.Transactional;
import java.util.List; import java.util.List;
import java.util.concurrent.TimeUnit;
/** /**
* <p> * <p>
@ -31,8 +38,13 @@ public class UserRoleServiceImpl extends ServiceImpl<UserRoleMapper, UserRole> i
private UserRoleMapper userRoleMapper; private UserRoleMapper userRoleMapper;
@Autowired @Autowired
private RedisTemplate<String, Object> redisTemplate; private UserFactory userFactory;
@Autowired
private UserMapper userMapper;
@Autowired
private RedisTemplate<String, Object> redisTemplate;
/** /**
* * 根据用户id获取角色列表 * * 根据用户id获取角色列表
@ -58,6 +70,12 @@ public class UserRoleServiceImpl extends ServiceImpl<UserRoleMapper, UserRole> i
Long userId = dto.getUserId(); Long userId = dto.getUserId();
List<Long> roleIds = dto.getRoleIds(); List<Long> roleIds = dto.getRoleIds();
// 查询当前用户
AdminUser adminUser = userMapper.selectOne(Wrappers.<AdminUser>lambdaQuery().eq(AdminUser::getId, userId));
if (adminUser == null) {
throw new BunnyException(ResultCodeEnum.USER_IS_EMPTY);
}
// 删除这个用户下所有已经分配好的角色内容 // 删除这个用户下所有已经分配好的角色内容
baseMapper.deleteBatchIdsByUserIdsWithPhysics(List.of(userId)); baseMapper.deleteBatchIdsByUserIdsWithPhysics(List.of(userId));
@ -69,5 +87,14 @@ public class UserRoleServiceImpl extends ServiceImpl<UserRoleMapper, UserRole> i
return userRole; return userRole;
}).toList(); }).toList();
saveBatch(roleList); saveBatch(roleList);
// 获取记住我时间
LoginVo loginVo = BaseContext.getLoginVo();
Long readMeDay = loginVo != null ? loginVo.getReadMeDay() : RedisUserConstant.REDIS_EXPIRATION_TIME;
// 重新设置Redis中的用户存储信息vo对象
String username = adminUser.getUsername();
loginVo = userFactory.buildLoginUserVo(adminUser, readMeDay);
redisTemplate.opsForValue().set(RedisUserConstant.getAdminLoginInfoPrefix(username), loginVo, readMeDay, TimeUnit.DAYS);
} }
} }

View File

@ -8,12 +8,16 @@ import cn.bunny.common.service.utils.minio.MinioUtil;
import cn.bunny.dao.dto.system.files.FileUploadDto; import cn.bunny.dao.dto.system.files.FileUploadDto;
import cn.bunny.dao.dto.system.user.*; import cn.bunny.dao.dto.system.user.*;
import cn.bunny.dao.entity.log.UserLoginLog; import cn.bunny.dao.entity.log.UserLoginLog;
import cn.bunny.dao.entity.system.*; import cn.bunny.dao.entity.system.AdminUser;
import cn.bunny.dao.entity.system.EmailTemplate;
import cn.bunny.dao.entity.system.Role;
import cn.bunny.dao.entity.system.UserDept;
import cn.bunny.dao.pojo.constant.MinioConstant; import cn.bunny.dao.pojo.constant.MinioConstant;
import cn.bunny.dao.pojo.constant.RedisUserConstant; import cn.bunny.dao.pojo.constant.RedisUserConstant;
import cn.bunny.dao.pojo.enums.EmailTemplateEnums; import cn.bunny.dao.pojo.enums.EmailTemplateEnums;
import cn.bunny.dao.pojo.result.PageResult; import cn.bunny.dao.pojo.result.PageResult;
import cn.bunny.dao.pojo.result.ResultCodeEnum; import cn.bunny.dao.pojo.result.ResultCodeEnum;
import cn.bunny.dao.view.ViewUserDept;
import cn.bunny.dao.vo.system.files.FileInfoVo; import cn.bunny.dao.vo.system.files.FileInfoVo;
import cn.bunny.dao.vo.system.user.AdminUserVo; import cn.bunny.dao.vo.system.user.AdminUserVo;
import cn.bunny.dao.vo.system.user.LoginVo; import cn.bunny.dao.vo.system.user.LoginVo;
@ -136,7 +140,7 @@ public class UserServiceImpl extends ServiceImpl<UserMapper, AdminUser> implemen
if (adminUser == null) throw new BunnyException(ResultCodeEnum.FAIL_REQUEST_NOT_AUTH); if (adminUser == null) throw new BunnyException(ResultCodeEnum.FAIL_REQUEST_NOT_AUTH);
if (adminUser.getStatus()) throw new BunnyException(ResultCodeEnum.FAIL_NO_ACCESS_DENIED_USER_LOCKED); if (adminUser.getStatus()) throw new BunnyException(ResultCodeEnum.FAIL_NO_ACCESS_DENIED_USER_LOCKED);
LoginVo buildUserVo = userFactory.buildUserVo(adminUser, dto.getReadMeDay()); LoginVo buildUserVo = userFactory.buildLoginUserVo(adminUser, dto.getReadMeDay());
RefreshTokenVo refreshTokenVo = new RefreshTokenVo(); RefreshTokenVo refreshTokenVo = new RefreshTokenVo();
BeanUtils.copyProperties(buildUserVo, refreshTokenVo); BeanUtils.copyProperties(buildUserVo, refreshTokenVo);
@ -148,20 +152,22 @@ public class UserServiceImpl extends ServiceImpl<UserMapper, AdminUser> implemen
*/ */
@Override @Override
public void logout() { public void logout() {
// 获取上下文对象中的用户ID和用户token
LoginVo loginVo = BaseContext.getLoginVo(); LoginVo loginVo = BaseContext.getLoginVo();
Long id = loginVo.getId(); String token = loginVo.getToken();
Long userId = BaseContext.getUserId();
// 获取IP地址 // 获取IP地址
String ipAddr = IpUtil.getCurrentUserIpAddress().getIpAddr(); String ipAddr = IpUtil.getCurrentUserIpAddress().getIpAddr();
String ipRegion = IpUtil.getCurrentUserIpAddress().getIpRegion(); String ipRegion = IpUtil.getCurrentUserIpAddress().getIpRegion();
// 查询用户信息 // 查询用户信息
AdminUser adminUser = getOne(Wrappers.<AdminUser>lambdaQuery().eq(AdminUser::getId, id)); AdminUser adminUser = getOne(Wrappers.<AdminUser>lambdaQuery().eq(AdminUser::getId, userId));
UserLoginLog userLoginLog = userFactory.setUserLoginLog(adminUser, loginVo.getToken(), ipAddr, ipRegion, "logout"); UserLoginLog userLoginLog = userFactory.setUserLoginLog(adminUser, token, ipAddr, ipRegion, "logout");
userLoginLogMapper.insert(userLoginLog); userLoginLogMapper.insert(userLoginLog);
// 删除Redis中用户信息 // 删除Redis中用户信息
redisTemplate.delete(RedisUserConstant.getAdminLoginInfoPrefix(loginVo.getUsername())); redisTemplate.delete(RedisUserConstant.getAdminLoginInfoPrefix(adminUser.getUsername()));
} }
/** /**
@ -210,7 +216,7 @@ public class UserServiceImpl extends ServiceImpl<UserMapper, AdminUser> implemen
throw new BunnyException(ResultCodeEnum.UPDATE_NEW_PASSWORD_SAME_AS_OLD_PASSWORD); throw new BunnyException(ResultCodeEnum.UPDATE_NEW_PASSWORD_SAME_AS_OLD_PASSWORD);
// 删除Redis中登录用户信息 // 删除Redis中登录用户信息
redisTemplate.delete(RedisUserConstant.getAdminLoginInfoPrefix(adminUser.getEmail())); redisTemplate.delete(RedisUserConstant.getAdminLoginInfoPrefix(adminUser.getUsername()));
// 更新用户密码 // 更新用户密码
adminUser = new AdminUser(); adminUser = new AdminUser();
@ -256,8 +262,7 @@ public class UserServiceImpl extends ServiceImpl<UserMapper, AdminUser> implemen
// 根据id查询用户登录前缀 // 根据id查询用户登录前缀
AdminUser adminUser = getOne(Wrappers.<AdminUser>lambdaQuery().eq(AdminUser::getId, id)); AdminUser adminUser = getOne(Wrappers.<AdminUser>lambdaQuery().eq(AdminUser::getId, id));
String email = adminUser.getEmail(); String adminLoginInfoPrefix = RedisUserConstant.getAdminLoginInfoPrefix(adminUser.getUsername());
String adminLoginInfoPrefix = RedisUserConstant.getAdminLoginInfoPrefix(email);
// 将用户登录保存在用户登录日志表中 // 将用户登录保存在用户登录日志表中
UserLoginLog userLoginLog = new UserLoginLog(); UserLoginLog userLoginLog = new UserLoginLog();
@ -310,19 +315,8 @@ public class UserServiceImpl extends ServiceImpl<UserMapper, AdminUser> implemen
* @return 用户信息 * @return 用户信息
*/ */
@Override @Override
public UserVo getUserinfo() { public LoginVo getUserinfo() {
// 查询当前用户信息 return BaseContext.getLoginVo();
Long userId = BaseContext.getUserId();
AdminUser adminUser = getOne(Wrappers.<AdminUser>lambdaQuery().eq(AdminUser::getId, userId));
// 赋值对象
UserVo userVo = new UserVo();
BeanUtils.copyProperties(adminUser, userVo);
// 设置用户头像内容
String avatar = adminUser.getAvatar();
if (StringUtils.hasText(avatar)) userVo.setAvatar(minioUtil.getObjectNameFullPath(avatar));
return userVo;
} }
/** /**
@ -333,20 +327,24 @@ public class UserServiceImpl extends ServiceImpl<UserMapper, AdminUser> implemen
@Override @Override
public void updateAdminUserByLocalUser(AdminUserUpdateByLocalUserDto dto) { public void updateAdminUserByLocalUser(AdminUserUpdateByLocalUserDto dto) {
Long userId = BaseContext.getUserId(); Long userId = BaseContext.getUserId();
LoginVo loginVo = BaseContext.getLoginVo();
// 判断是否存在这个用户 // 判断是否存在这个用户
AdminUser adminUser = getOne(Wrappers.<AdminUser>lambdaQuery().eq(AdminUser::getId, userId)); AdminUser user = getOne(Wrappers.<AdminUser>lambdaQuery().eq(AdminUser::getId, userId));
if (adminUser == null) throw new BunnyException(ResultCodeEnum.USER_IS_EMPTY); if (user == null) throw new BunnyException(ResultCodeEnum.USER_IS_EMPTY);
// 检查用户头像 // 检查用户头像
dto.setAvatar(userFactory.checkUserAvatar(dto.getAvatar())); dto.setAvatar(userFactory.checkUserAvatar(dto.getAvatar()));
// 更新用户 // 更新用户
adminUser = new AdminUser(); AdminUser adminUser = new AdminUser();
adminUser.setId(userId); adminUser.setId(userId);
BeanUtils.copyProperties(dto, adminUser); BeanUtils.copyProperties(dto, adminUser);
updateById(adminUser); updateById(adminUser);
// 重新生成用户信息到Redis中
BeanUtils.copyProperties(dto, user);
userFactory.buildUserVo(user, loginVo.getReadMeDay());
} }
/** /**
@ -371,15 +369,13 @@ public class UserServiceImpl extends ServiceImpl<UserMapper, AdminUser> implemen
if (dbPassword.equals(password)) throw new BunnyException(ResultCodeEnum.NEW_PASSWORD_SAME_OLD_PASSWORD); if (dbPassword.equals(password)) throw new BunnyException(ResultCodeEnum.NEW_PASSWORD_SAME_OLD_PASSWORD);
// 删除Redis中登录用户信息 // 删除Redis中登录用户信息
redisTemplate.delete(RedisUserConstant.getAdminLoginInfoPrefix(adminUser.getEmail())); redisTemplate.delete(RedisUserConstant.getAdminLoginInfoPrefix(adminUser.getUsername()));
// 更新用户密码 // 更新用户密码
adminUser = new AdminUser(); adminUser = new AdminUser();
adminUser.setId(userId); adminUser.setId(userId);
adminUser.setPassword(password); adminUser.setPassword(password);
updateById(adminUser); updateById(adminUser);
} }
/** /**
@ -392,7 +388,7 @@ public class UserServiceImpl extends ServiceImpl<UserMapper, AdminUser> implemen
@Override @Override
public PageResult<AdminUserVo> getAdminUserList(Page<AdminUser> pageParams, AdminUserDto dto) { public PageResult<AdminUserVo> getAdminUserList(Page<AdminUser> pageParams, AdminUserDto dto) {
// 分页查询菜单图标 // 分页查询菜单图标
IPage<AdminUserAndDept> page = baseMapper.selectListByPage(pageParams, dto); IPage<ViewUserDept> page = baseMapper.selectListByPage(pageParams, dto);
List<AdminUserVo> voList = page.getRecords().stream() List<AdminUserVo> voList = page.getRecords().stream()
.map(adminUser -> { .map(adminUser -> {
@ -419,17 +415,29 @@ public class UserServiceImpl extends ServiceImpl<UserMapper, AdminUser> implemen
} }
/** /**
* 添加用户信息 * * 添加用户信息
* 需要确认用户名-username是唯一的
* 需要确认邮箱-email是唯一的
* *
* @param dto 用户信息添加 * @param dto 用户信息添加
*/ */
@Override @Override
public void addAdminUser(@Valid AdminUserAddDto dto) { public void addAdminUser(@Valid AdminUserAddDto dto) {
AdminUser adminUser = getOne(Wrappers.<AdminUser>lambdaQuery()
.eq(AdminUser::getEmail, dto.getEmail())
.or()
.eq(AdminUser::getUsername, dto.getUsername()));
// 确保邮箱和用户名不能重复
if (adminUser != null) {
throw new BunnyException(ResultCodeEnum.ALREADY_USER_EXCEPTION);
}
// 对密码加密 // 对密码加密
String md5Password = DigestUtils.md5DigestAsHex(dto.getPassword().getBytes()); String md5Password = DigestUtils.md5DigestAsHex(dto.getPassword().getBytes());
// 保存数据 // 保存数据
AdminUser adminUser = new AdminUser(); adminUser = new AdminUser();
BeanUtils.copyProperties(dto, adminUser); BeanUtils.copyProperties(dto, adminUser);
adminUser.setPassword(md5Password); adminUser.setPassword(md5Password);
save(adminUser); save(adminUser);
@ -452,6 +460,16 @@ public class UserServiceImpl extends ServiceImpl<UserMapper, AdminUser> implemen
*/ */
@Override @Override
public void updateAdminUser(AdminUserUpdateDto dto) { public void updateAdminUser(AdminUserUpdateDto dto) {
AdminUser adminUser = getOne(Wrappers.<AdminUser>lambdaQuery()
.eq(AdminUser::getEmail, dto.getEmail())
.or()
.eq(AdminUser::getUsername, dto.getUsername()));
// 确保邮箱和用户名不能重复
if (adminUser != null) {
throw new BunnyException(ResultCodeEnum.ALREADY_USER_EXCEPTION);
}
// 部门Id // 部门Id
Long deptId = dto.getDeptId(); Long deptId = dto.getDeptId();
Long userId = dto.getId(); Long userId = dto.getId();
@ -461,7 +479,7 @@ public class UserServiceImpl extends ServiceImpl<UserMapper, AdminUser> implemen
if (adminUserList.isEmpty()) throw new BunnyException(ResultCodeEnum.DATA_NOT_EXIST); if (adminUserList.isEmpty()) throw new BunnyException(ResultCodeEnum.DATA_NOT_EXIST);
// 更新用户 // 更新用户
AdminUser adminUser = new AdminUser(); adminUser = new AdminUser();
BeanUtils.copyProperties(dto, adminUser); BeanUtils.copyProperties(dto, adminUser);
updateById(adminUser); updateById(adminUser);

View File

@ -47,7 +47,6 @@
and type_name like CONCAT('%',#{dto.typeName},'%') and type_name like CONCAT('%',#{dto.typeName},'%')
</if> </if>
</where> </where>
order by update_time
</select> </select>
</mapper> </mapper>

View File

@ -64,12 +64,4 @@
AND rp.power_id = p.id AND rp.power_id = p.id
AND u.id = #{userId} AND u.id = #{userId}
</select> </select>
<!-- 根据权限码返回权限列表 -->
<select id="selectListByPowerCodes" resultType="cn.bunny.dao.entity.system.Power">
SELECT * FROM sys_power WHERE power_code IN
<foreach collection="powerCodes" separator="," item="code" open="(" close=")">
#{code}
</foreach>
</select>
</mapper> </mapper>

View File

@ -46,15 +46,19 @@
where role_id = #{roleId} where role_id = #{roleId}
</select> </select>
<!-- 根据角色id列表获取权限内容 --> <!-- 查看所有角色关联的权限 -->
<select id="selectPowerListByRoleIds" resultType="cn.bunny.dao.entity.system.Power"> <select id="viewRolePowerWithAll" resultType="cn.bunny.dao.view.ViewRolePower">
SELECT power.* SELECT rp.power_id,
power.parent_id,
power.power_code,
power.power_name,
power.request_url,
rp.role_id,
role.role_code,
role.description
FROM sys_role_power rp FROM sys_role_power rp
LEFT JOIN sys_role role ON rp.role_id = role.id LEFT JOIN sys_role role ON rp.role_id = role.id
LEFT JOIN sys_power power ON rp.power_id = power.id AND rp.role_id in LEFT JOIN sys_power power ON rp.power_id = power.id
<foreach collection="roleIds" item="id" open="(" close=")" separator=",">
#{id}
</foreach>
</select> </select>
</mapper> </mapper>

View File

@ -39,4 +39,25 @@
</foreach> </foreach>
</delete> </delete>
<!-- 查看所有路由的角色 -->
<select id="viewRouterRolesWithAll" resultType="cn.bunny.dao.view.ViewRouterRole">
SELECT rr.router_id,
router.parent_id,
router.path,
router.component,
router.frame_src,
router.route_name,
router.title,
router.menu_type,
router.icon,
router.router_rank,
router.visible,
rr.role_id,
role.role_code,
role.description
FROM sys_router_role rr
LEFT JOIN sys_router router ON rr.router_id = router.id
LEFT JOIN sys_role role ON rr.role_id = role.id
</select>
</mapper> </mapper>

View File

@ -6,7 +6,7 @@
<resultMap id="BaseResultMap" type="cn.bunny.dao.entity.system.AdminUser"> <resultMap id="BaseResultMap" type="cn.bunny.dao.entity.system.AdminUser">
<id column="id" property="id"/> <id column="id" property="id"/>
<result column="username" property="username"/> <result column="username" property="username"/>
<result column="nick_name" property="nickName"/> <result column="nickname" property="nickname"/>
<result column="email" property="email"/> <result column="email" property="email"/>
<result column="phone" property="phone"/> <result column="phone" property="phone"/>
<result column="password" property="password"/> <result column="password" property="password"/>
@ -25,11 +25,11 @@
<!-- 通用查询结果列 --> <!-- 通用查询结果列 -->
<sql id="Base_Column_List"> <sql id="Base_Column_List">
id, username, nick_name, email, phone, password, avatar, sex, summary, ip_address, ip_region, status, create_user, create_time, update_time, update_user, is_deleted id, username, nickname, email, phone, password, avatar, sex, summary, ip_address, ip_region, status, create_user, create_time, update_time, update_user, is_deleted
</sql> </sql>
<!-- 分页查询用户信息内容 --> <!-- 分页查询用户信息内容 -->
<select id="selectListByPage" resultType="cn.bunny.dao.entity.system.AdminUserAndDept"> <select id="selectListByPage" resultType="cn.bunny.dao.view.ViewUserDept">
select select
user.*,user_dept.dept_id user.*,user_dept.dept_id
from sys_user user left join sys_user_dept user_dept on user.id = user_dept.user_id from sys_user user left join sys_user_dept user_dept on user.id = user_dept.user_id
@ -38,8 +38,8 @@
<if test="dto.username != null and dto.username != ''"> <if test="dto.username != null and dto.username != ''">
and username like CONCAT('%',#{dto.username},'%') and username like CONCAT('%',#{dto.username},'%')
</if> </if>
<if test="dto.nickName != null and dto.nickName != ''"> <if test="dto.nickname != null and dto.nickname != ''">
and nick_name like CONCAT('%',#{dto.nickName},'%') and nickname like CONCAT('%',#{dto.nickname},'%')
</if> </if>
<if test="dto.email != null and dto.email != ''"> <if test="dto.email != null and dto.email != ''">
and email like CONCAT('%',#{dto.email},'%') and email like CONCAT('%',#{dto.email},'%')
@ -72,7 +72,7 @@
<where> <where>
<if test="keyword != null and keyword != ''"> <if test="keyword != null and keyword != ''">
username like CONCAT('%', #{keyword}, '%') username like CONCAT('%', #{keyword}, '%')
or nick_name like CONCAT('%', #{keyword}, '%') or nickname like CONCAT('%', #{keyword}, '%')
or email like CONCAT('%', #{keyword}, '%') or email like CONCAT('%', #{keyword}, '%')
or phone like CONCAT('%', #{keyword}, '%') or phone like CONCAT('%', #{keyword}, '%')
</if> </if>