完成了用户controller

This commit is contained in:
chen-xin-zhi 2024-10-27 18:39:56 +08:00
parent 93262400a6
commit b87bfaaaca
22 changed files with 749 additions and 7 deletions

19
pom.xml
View File

@ -117,6 +117,12 @@
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<!-- aop-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
<!-- <dependency>-->
<!-- <groupId>org.apache.commons</groupId>-->
<!-- <artifactId>commons-collections4</artifactId>-->
@ -128,6 +134,19 @@
<!-- <artifactId>ansj_seg</artifactId>-->
<!-- <version>5.1.1</version>-->
<!-- </dependency>-->
<!-- 图形验证码-->
<dependency>
<groupId>com.github.whvcse</groupId>
<artifactId>easy-captcha</artifactId>
<version>1.6.2</version>
</dependency>
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>5.8.26</version>
</dependency>
</dependencies>
<build>

View File

@ -0,0 +1,18 @@
package com.cultural.heritage.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* 权限校验
*/
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface AuthCheck {
/**
* 必须有某个角色
*/
String mustRole() default "";
}

View File

@ -0,0 +1,69 @@
package com.cultural.heritage.aop;
import com.cultural.heritage.annotation.AuthCheck;
import com.cultural.heritage.common.ErrorCode;
import com.cultural.heritage.constant.UserConstant;
import com.cultural.heritage.exception.BusinessException;
import com.cultural.heritage.model.entity.User;
import com.cultural.heritage.model.enums.UserRoleEnum;
import com.cultural.heritage.service.userinfo.UserService;
import io.micrometer.common.util.StringUtils;
import jakarta.annotation.Resource;
import jakarta.servlet.http.HttpServletRequest;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
/**
* 权限校验AOP
*/
@Aspect
@Component
public class AuthInterceptor {
@Resource
private UserService userService;
/**
* 执行拦截
*/
@Around("@annotation(authCheck)")
public Object doInterceptor(ProceedingJoinPoint joinPoint, AuthCheck authCheck) throws Throwable {
String mustRole = authCheck.mustRole();
RequestAttributes requestAttributes = RequestContextHolder.currentRequestAttributes();
HttpServletRequest request = ((ServletRequestAttributes) requestAttributes).getRequest();
//当前登录用户
User loginUser = userService.getLoginUser(request);
//必须有该权限才通过
if (StringUtils.isNotBlank(mustRole)) {
UserRoleEnum mustUserRoleEnum = UserRoleEnum.getEnumByValues(mustRole);
if(mustUserRoleEnum == null) {
throw new BusinessException(ErrorCode.NO_AUTH_ERROR);
}
String userRole = loginUser.getUserRole();
//如果被封号直接拒绝
if (UserRoleEnum.BAN.equals(mustUserRoleEnum)) {
throw new BusinessException(ErrorCode.NO_AUTH_ERROR);
}
//必须有BOSS权限
if (UserRoleEnum.BOSS.equals(mustUserRoleEnum)) {
if (!mustRole.equals(userRole)) {
throw new BusinessException(ErrorCode.NO_AUTH_ERROR);
}
}
//必须有管理员权限
if (UserRoleEnum.ADMIN.equals(mustUserRoleEnum)) {
if (!mustRole.equals(userRole) && !userRole.equals(UserConstant.BOSS_ROLE)) {
throw new BusinessException(ErrorCode.NO_AUTH_ERROR);
}
}
}
//通过权限校验放行
return joinPoint.proceed();
}
}

View File

@ -0,0 +1,61 @@
package com.cultural.heritage.aopTest;
import jakarta.servlet.http.HttpServletRequest;
import lombok.extern.log4j.Log4j;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import java.lang.reflect.Method;
import java.util.Set;
@Component
@Aspect
@Slf4j
public class AopConfig {
@Pointcut("@annotation(com.cultural.heritage.aopTest.HasRole)")
public void pointcut(){}
@Before("pointcut()")
public void before(JoinPoint joinPoint) {
System.out.println("before-----------------");
//获取到HttpServletRequest
RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();
ServletRequestAttributes servletRequestAttributes = (ServletRequestAttributes) requestAttributes;
HttpServletRequest request = servletRequestAttributes.getRequest();
String username = request.getParameter("username");
//获取当前用户角色的集合
Set<String> userRoles = CacheManager.USER_ROLE_MAP.get(username);
//获取当前请求的方法的签名
MethodSignature signature = (MethodSignature) joinPoint.getSignature();
//反射获取当前被调用的方法
Method method = signature.getMethod();
//判断当前方法是否有hasRole注解
//如果有判断用户是否具有注解属性中要求的角色
//如果没有hasRole注解那么说明方法不需要判断用户的角色可以匿名访问
HasRole hasRole = method.getDeclaredAnnotation(HasRole.class);
System.out.println("hasRole:" + hasRole.value());
System.out.println("userRoles:" + userRoles);
log.info("----------------");
if(!userRoles.contains(hasRole.value())) {
throw new RuntimeException("用户没有访问的权限");
}
}
}

View File

@ -0,0 +1,31 @@
package com.cultural.heritage.aopTest;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("/aop")
public class AopController {
//调用这个方法需要用户具有admin的角色
@HasRole("admin")
@GetMapping("query1")
public String query1() {
return "query1 需要 admin 角色";
}
//调用这个方法需要用户具有user的角色
@HasRole("user")
@GetMapping("query2")
public String query2() {
return "query2 需要 user 角色";
}
// 任何用户都可以访问
@GetMapping("query3")
public String query3() {
return "query3 可以匿名访问";
}
}

View File

@ -0,0 +1,22 @@
package com.cultural.heritage.aopTest;
import com.google.common.collect.Sets;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
public class CacheManager {
public static final Map<String, Set<String>> USER_ROLE_MAP = new HashMap<>();
static {
//用户zhangsan具有user和admin两个角色
Set<String> roleSet1 = Sets.newHashSet("admin", "user");
USER_ROLE_MAP.put("zhangsan", roleSet1);
Set<String> roleSet2 = Sets.newHashSet("user");
USER_ROLE_MAP.put("lisi", roleSet2);
}
}

View File

@ -0,0 +1,12 @@
package com.cultural.heritage.aopTest;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface HasRole {
String value();
}

View File

@ -8,6 +8,7 @@ public enum ErrorCode {
SUCCESS(1,"ok"),
PARAMS_ERROR(40000,"请求参数错误"),
NOT_LOGIN_ERROR(40100,"未登录"),
NO_AUTH_ERROR(40101, "无权限"),
NOT_FOUND_ERROR(40400,"请求数据不存在"),
FORBIDDEN_ERROR(40300,"禁止访问"),
SYSTEM_ERROR(50000,"系统内部异常"),

View File

@ -16,4 +16,26 @@ public interface UserConstant {
* 用户登录键
*/
String USER_LOGIN_STATE = "feiyi";
/**
* 默认角色
*/
String DEFAULT_ROLE = "user";
/**
* 管理员角色
*/
String ADMIN_ROLE = "admin";
/**
* Boss
*/
String BOSS_ROLE = "boss";
/**
* 被封号
*/
String BAN_ROLE = "ban";
}

View File

@ -1,22 +1,42 @@
package com.cultural.heritage.controller.userinfo;
import cn.hutool.core.util.IdUtil;
import com.cultural.heritage.common.BaseResponse;
import com.cultural.heritage.common.ErrorCode;
import com.cultural.heritage.common.ResultUtils;
import com.cultural.heritage.constant.CommonConstant;
import com.cultural.heritage.constant.UserConstant;
import com.cultural.heritage.exception.BusinessException;
import com.cultural.heritage.exception.ThrowUtils;
import com.cultural.heritage.model.dto.CommonRequest;
import com.cultural.heritage.model.dto.user.UserAddRequest;
import com.cultural.heritage.model.dto.user.UserLoginRequest;
import com.cultural.heritage.model.dto.user.UserUpdateMyRequest;
import com.cultural.heritage.model.dto.user.UserUpdateRequest;
import com.cultural.heritage.model.entity.User;
import com.cultural.heritage.model.vo.UserVO;
import com.cultural.heritage.service.userinfo.UserService;
import com.wf.captcha.SpecCaptcha;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.annotation.Resource;
import jakarta.servlet.http.HttpServletRequest;
import lombok.extern.slf4j.Slf4j;
import org.apache.catalina.webresources.ExtractingRoot;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.context.annotation.Bean;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.util.DigestUtils;
import org.springframework.web.bind.annotation.*;
import javax.xml.transform.Result;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import static com.cultural.heritage.constant.UserConstant.SALT;
/**
* 用户接口
@ -32,6 +52,8 @@ public class UserController {
@Resource
private UserService userService;
@Resource
private RedisTemplate redisTemplate;
@GetMapping("/test")
public String test(){
@ -66,6 +88,8 @@ public class UserController {
/**
* 退出登录
* @param request http
* @return 是否退出登录成功
*/
@PostMapping("/logout")
public BaseResponse<Boolean> userLogout(HttpServletRequest request) {
@ -78,6 +102,118 @@ public class UserController {
/**
* 更新个人信息
* @param userUpdateMyRequest 更新请求体
* @param request http
* @return 是否更新成功
*/
@PostMapping("/update/my")
public BaseResponse<Boolean> updateMyUser(@RequestBody UserUpdateMyRequest userUpdateMyRequest, HttpServletRequest request) {
if (userUpdateMyRequest == null) {
throw new BusinessException(ErrorCode.PARAMS_ERROR);
}
User loginUser = userService.getLoginUser(request);
User user = new User();
BeanUtils.copyProperties(userUpdateMyRequest, user);
user.setId(loginUser.getId());
boolean result = userService.updateById(user);
ThrowUtils.throwIf(!result, ErrorCode.OPERATION_ERROR);
return ResultUtils.success(true);
}
/**
* 创建用户
* @param userAddRequest 用户添加请求体
* @return 添加用户的id
*/
@PostMapping("/add")
public BaseResponse<User> addUser(@RequestBody UserAddRequest userAddRequest) {
if (userAddRequest == null) {
throw new BusinessException(ErrorCode.PARAMS_ERROR);
}
User user = new User();
BeanUtils.copyProperties(userAddRequest, user);
String encryptPassword = DigestUtils.md5DigestAsHex((SALT + user.getUserPassword()).getBytes());
user.setUserPassword(encryptPassword);
boolean save = userService.save(user);
if (!save) {
throw new BusinessException(ErrorCode.SYSTEM_ERROR);
}
return ResultUtils.success(user, "添加用户成功");
}
/**
* 删除用户
* @param deleteRequest 用户删除请求体
* @return 是否删除
*/
@PostMapping("/delete")
public BaseResponse<Boolean> deleteUser(@RequestBody CommonRequest deleteRequest) {
if (deleteRequest == null || deleteRequest.getId() <= 0) {
throw new BusinessException(ErrorCode.PARAMS_ERROR);
}
boolean result = userService.removeById(deleteRequest.getId());
ThrowUtils.throwIf(!result, ErrorCode.OPERATION_ERROR);
return ResultUtils.success(true);
}
/**
* 更新用户
* @param userUpdateRequest 用户更新请求体
* @return 是否更新成功
*/
@PostMapping("/update")
public BaseResponse<Boolean> updateUser(@RequestBody UserUpdateRequest userUpdateRequest) {
if (userUpdateRequest == null || userUpdateRequest.getId() == null) {
throw new BusinessException(ErrorCode.PARAMS_ERROR);
}
User user = new User();
BeanUtils.copyProperties(userUpdateRequest, user);
boolean result = userService.updateById(user);
ThrowUtils.throwIf(!result, ErrorCode.OPERATION_ERROR);
return ResultUtils.success(true);
}
/**
* 根据 id 获取用户仅管理员
* @param id
* @return 用户信息
*/
@GetMapping("/get")
public BaseResponse<User> getUserById(long id) {
if (id <= 0) {
throw new BusinessException(ErrorCode.PARAMS_ERROR);
}
User user = userService.getById(id);
ThrowUtils.throwIf(user == null, ErrorCode.NOT_FOUND_ERROR);
return ResultUtils.success(user);
}
/**
* 图形验证码
* @return
*/
@GetMapping("/captcha")
public BaseResponse<Map> getCapthca(){
//设置生成的长宽还有数字位数
SpecCaptcha specCaptcha = new SpecCaptcha(130, 48, 4);
String code = specCaptcha.text().toLowerCase();
String uuid = IdUtil.simpleUUID();
redisTemplate.opsForValue().set(uuid,code,120, TimeUnit.SECONDS);
HashMap<String, String> map = new HashMap<>(3);
map.put("uuid",uuid);
map.put("code",code);
map.put("captcha",specCaptcha.toBase64());
return ResultUtils.success(map,"成功");
}

View File

@ -0,0 +1,18 @@
package com.cultural.heritage.model.dto;
import lombok.Data;
import java.io.Serial;
import java.io.Serializable;
@Data
public class CommonRequest implements Serializable {
/**
* id
*/
private Long id;
@Serial
private static final long serialVersionUID = -719221507292362303L;
}

View File

@ -0,0 +1,50 @@
package com.cultural.heritage.model.dto.user;
import lombok.Data;
import java.io.Serial;
import java.io.Serializable;
/**
* 用户创建请求
*/
@Data
public class UserAddRequest implements Serializable {
/**
* 用户昵称
*/
private String userName;
/**
* 账号
*/
private String userAccount;
/**
* 密码
*/
private String userPassword;
/**
* 用户头像
*/
private String userAvatar;
/**
* 手机号
*/
private String phone;
/**
* 用户角色 user, admin
*/
private String userRole;
@Serial
private static final long serialVersionUID = 1L;
}

View File

@ -0,0 +1,32 @@
package com.cultural.heritage.model.dto.user;
import lombok.Data;
import java.io.Serial;
import java.io.Serializable;
/**
* 用户更新个人信息请求
*/
@Data
public class UserUpdateMyRequest implements Serializable {
/**
* 用户昵称
*/
private String userName;
/**
* 用户头像
*/
private String userAvatar;
/**
* 手机号
*/
private String phone;
@Serial
private static final long serialVersionUID = 1L;
}

View File

@ -0,0 +1,45 @@
package com.cultural.heritage.model.dto.user;
import lombok.Data;
import java.io.Serial;
import java.io.Serializable;
@Data
public class UserUpdateRequest implements Serializable {
/**
* id
*/
private Long id;
/**
* 密码
*/
private String userPassword;
/**
* 用户名
*/
private String userName;
/**
* 头像
*/
private String userAvatar;
/**
* 手机号
*/
private String phone;
/**
* 用户角色
*/
private String userRole;
@Serial
private static final long serialVersionUID = -5057503930700700941L;
}

View File

@ -0,0 +1,52 @@
package com.cultural.heritage.model.enums;
import lombok.Getter;
import org.springframework.util.ObjectUtils;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
/**
* 用户角色枚举
*/
@Getter
public enum UserRoleEnum {
USER("用户", "user"),
ADMIN("管理员", "admin"),
BOSS("Boss", "boss"),
BAN("被封号", "ban");
private final String text;
private final String value;
UserRoleEnum(String text, String value) {
this.text = text;
this.value = value;
}
/**
* 获取值列表
*/
public static List<String> getValues() {
return Arrays.stream(values()).map(item -> item.value).collect(Collectors.toList());
}
/**
* 获取值列表
*/
public static UserRoleEnum getEnumByValues(String value) {
if (ObjectUtils.isEmpty(value)) {
return null;
}
for (UserRoleEnum anEnum : UserRoleEnum.values()) {
if(anEnum.value.equals(value)) {
return anEnum;
}
}
return null;
}
}

View File

@ -25,4 +25,9 @@ public interface UserService extends IService<User> {
* @return 是否退出成功
*/
boolean userLogout(HttpServletRequest request);
/**
* 获取当前登录用户
*/
User getLoginUser(HttpServletRequest request);
}

View File

@ -7,6 +7,7 @@ import com.cultural.heritage.constant.UserConstant;
import com.cultural.heritage.exception.BusinessException;
import com.cultural.heritage.mapper.UserMapper;
import com.cultural.heritage.model.entity.User;
import com.cultural.heritage.model.enums.UserRoleEnum;
import com.cultural.heritage.model.vo.UserVO;
import com.cultural.heritage.service.userinfo.UserService;
import jakarta.annotation.Resource;
@ -30,7 +31,9 @@ import static com.cultural.heritage.constant.UserConstant.USER_LOGIN_STATE;
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService {
/**
* 用户登录
*/
@Override
public UserVO userLogin(String userAccount, String userPassword, HttpServletRequest request) {
if(userAccount.length() < 4) {
@ -53,6 +56,7 @@ public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements Us
return this.getUserVO(user);
}
@Override
public UserVO getUserVO(User user) {
if (user == null) {
@ -61,14 +65,9 @@ public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements Us
UserVO userVO = new UserVO();
BeanUtils.copyProperties(user, userVO);
return userVO;
}
/**
*
* @param request
* @return
*/
@Override
public boolean userLogout(HttpServletRequest request) {
HttpSession session = request.getSession();
@ -79,4 +78,29 @@ public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements Us
return true;
}
/**
* 获取当前登录用户
*/
@Override
public User getLoginUser(HttpServletRequest request) {
HttpSession session = request.getSession();
Object userObj = session.getAttribute(USER_LOGIN_STATE);
User currentUser = (User) userObj;
if (currentUser == null || currentUser.getId() == null) {
throw new BusinessException(ErrorCode.NOT_LOGIN_ERROR);
}
//根据id进行查询
Long userId = currentUser.getId();
currentUser = this.getById(userId);
if (currentUser == null) {
throw new BusinessException(ErrorCode.NOT_LOGIN_ERROR);
}
//被封号
if (UserRoleEnum.BAN.getValue().equals(currentUser.getUserRole())) {
throw new BusinessException(ErrorCode.FORBIDDEN_ERROR);
}
return currentUser;
}
}

View File

@ -4,6 +4,12 @@ spring:
url: jdbc:mysql://123.249.108.160:3306/feiyi?serverTimezone=Asia/Shanghai
username: feiyi
password: 123456asd
data:
redis:
port: 6379
host: localhost
database: 0

View File

@ -0,0 +1,54 @@
package com.cultural.heritage.aop;
import jakarta.servlet.http.HttpServletRequest;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import java.lang.reflect.Method;
import java.util.Set;
@Component
@Aspect
public class AopConfig {
@Pointcut("@annotation(com.cultural.heritage.aop.HasRole)")
public void pointcut(){}
@Before("pointcut()")
public void before(JoinPoint joinPoint) {
System.out.println("before-----------------");
//获取到HttpServletRequest
RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();
ServletRequestAttributes servletRequestAttributes = (ServletRequestAttributes) requestAttributes;
HttpServletRequest request = servletRequestAttributes.getRequest();
String username = request.getParameter("username");
//获取当前用户角色的集合
Set<String> userRoles = CacheManager.USER_ROLE_MAP.get(username);
//获取当前请求的方法的签名
MethodSignature signature = (MethodSignature) joinPoint.getSignature();
//反射获取当前被调用的方法
Method method = signature.getMethod();
//判断当前方法是否有hasRole注解
//如果有判断用户是否具有注解属性中要求的角色
//如果没有hasRole注解那么说明方法不需要判断用户的角色可以匿名访问
HasRole hasRole = method.getDeclaredAnnotation(HasRole.class);
if (hasRole != null && (userRoles != null || !userRoles.contains(hasRole.value()))) {
throw new RuntimeException("用户没有访问的权限");
}
}
}

View File

@ -0,0 +1,31 @@
package com.cultural.heritage.aop;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("/aop")
public class AopController {
//调用这个方法需要用户具有admin的角色
@HasRole("admin")
@GetMapping("query1")
public String query1() {
return "query1 需要 admin 角色";
}
//调用这个方法需要用户具有user的角色
@HasRole("user")
@GetMapping("query2")
public String query2() {
return "query2 需要 user 角色";
}
// 任何用户都可以访问
@GetMapping("query3")
public String query3() {
return "query3 可以匿名访问";
}
}

View File

@ -0,0 +1,22 @@
package com.cultural.heritage.aop;
import com.google.common.collect.Sets;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
public class CacheManager {
public static final Map<String, Set<String>> USER_ROLE_MAP = new HashMap<>();
static {
//用户zhangsan具有user和admin两个角色
Set<String> roleSet1 = Sets.newHashSet("admin", "user");
USER_ROLE_MAP.put("zhangsan", roleSet1);
Set<String> roleSet2 = Sets.newHashSet("user");
USER_ROLE_MAP.put("lisi", roleSet2);
}
}

View File

@ -0,0 +1,12 @@
package com.cultural.heritage.aop;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface HasRole {
String value();
}