From 98d4870be3b7e3af07d6b795d686f3a3258d3268 Mon Sep 17 00:00:00 2001 From: ronger Date: Fri, 10 Dec 2021 11:27:25 +0800 Subject: [PATCH] =?UTF-8?q?:lock:=20=E5=AE=89=E5=85=A8=E9=97=AE=E9=A2=98?= =?UTF-8?q?=E5=A4=84=E7=90=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../forest/config/BaseExceptionHandler.java | 15 +-- .../core/service/security/SecurityAspect.java | 109 ++++++++++++++++++ .../annotation/SecurityInterceptor.java | 12 ++ .../jwt/aop/RestAuthTokenInterceptor.java | 2 +- .../web/api/exception/BaseApiException.java | 1 + .../web/api/user/UserInfoController.java | 7 ++ 6 files changed, 138 insertions(+), 8 deletions(-) create mode 100644 src/main/java/com/rymcu/forest/core/service/security/SecurityAspect.java create mode 100644 src/main/java/com/rymcu/forest/core/service/security/annotation/SecurityInterceptor.java diff --git a/src/main/java/com/rymcu/forest/config/BaseExceptionHandler.java b/src/main/java/com/rymcu/forest/config/BaseExceptionHandler.java index a73714f..632a1ad 100644 --- a/src/main/java/com/rymcu/forest/config/BaseExceptionHandler.java +++ b/src/main/java/com/rymcu/forest/config/BaseExceptionHandler.java @@ -7,6 +7,7 @@ import com.rymcu.forest.core.result.GlobalResult; import com.rymcu.forest.core.result.ResultCode; import com.rymcu.forest.enumerate.TransactionCode; import com.rymcu.forest.web.api.exception.BaseApiException; +import org.apache.commons.lang.StringUtils; import org.apache.shiro.authz.UnauthenticatedException; import org.apache.shiro.authz.UnauthorizedException; import org.slf4j.Logger; @@ -39,9 +40,9 @@ public class BaseExceptionHandler { if (isAjax(request)) { GlobalResult result = new GlobalResult(); if (ex instanceof BaseApiException) { - result.setCode(401); - result.setMessage("用户未登录"); - logger.info("用户未登录"); + result.setCode(((BaseApiException) ex).getCode()); + result.setMessage(((BaseApiException) ex).getExtraMessage()); + logger.info(result.getMessage()); } else if (ex instanceof UnauthenticatedException) { result.setCode(1000001); result.setMessage("token错误"); @@ -88,8 +89,8 @@ public class BaseExceptionHandler { FastJsonJsonView view = new FastJsonJsonView(); Map attributes = new HashMap(2); if (ex instanceof BaseApiException) { - attributes.put("code", "401"); - attributes.put("message", "用户未登录"); + attributes.put("code", ((BaseApiException) ex).getCode()); + attributes.put("message", ((BaseApiException) ex).getExtraMessage()); } else if (ex instanceof UnauthenticatedException) { attributes.put("code", "1000001"); attributes.put("message", "token错误"); @@ -138,8 +139,8 @@ public class BaseExceptionHandler { String requestedWith = request.getHeader("x-requested-with"); if (requestedWith != null && "XMLHttpRequest".equalsIgnoreCase(requestedWith)) { return true; - } else { - return false; } + String contentType = request.getContentType(); + return StringUtils.isNotBlank(contentType) && contentType.contains("application/json"); } } diff --git a/src/main/java/com/rymcu/forest/core/service/security/SecurityAspect.java b/src/main/java/com/rymcu/forest/core/service/security/SecurityAspect.java new file mode 100644 index 0000000..b107a82 --- /dev/null +++ b/src/main/java/com/rymcu/forest/core/service/security/SecurityAspect.java @@ -0,0 +1,109 @@ +package com.rymcu.forest.core.service.security; + +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONObject; +import com.rymcu.forest.dto.TokenUser; +import com.rymcu.forest.jwt.def.JwtConstants; +import com.rymcu.forest.util.UserUtils; +import com.rymcu.forest.web.api.exception.BaseApiException; +import com.rymcu.forest.web.api.exception.ErrorCode; +import org.apache.commons.lang.StringUtils; +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.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.stereotype.Component; +import org.springframework.web.context.request.RequestContextHolder; +import org.springframework.web.context.request.ServletRequestAttributes; +import org.springframework.web.servlet.HandlerMapping; + +import javax.servlet.http.HttpServletRequest; +import java.util.Enumeration; +import java.util.HashMap; +import java.util.Map; +import java.util.Objects; + +/** + * 检查用户修改信息权限 + * + * @author ronger + */ +@Aspect +@Component +public class SecurityAspect { + + Logger logger = LoggerFactory.getLogger(SecurityAspect.class); + + @Pointcut("@annotation(com.rymcu.forest.core.service.security.annotation.SecurityInterceptor)") + public void pointCut() { + } + + /** + * 检查用户修改信息权限 + * + * @param joinPoint 连接点 + * @return 方法执行结果 + * @throws Throwable 调用出错 + */ + @Before(value = "pointCut()") + public void doBefore(JoinPoint joinPoint) throws BaseApiException { + logger.info("检查用户修改信息权限 start ..."); + HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest(); + String idUser = ""; + if (isAjax(request)) { + Object[] objects = joinPoint.getArgs(); + JSONObject jsonObject = JSONObject.parseObject(JSON.toJSONString(objects[0])); + if (Objects.nonNull(jsonObject)) { + idUser = jsonObject.getString("idUser"); + } + } else { + Map params = getParams(request); + if (params.isEmpty()) { + params = (Map) request.getAttribute(HandlerMapping.URI_TEMPLATE_VARIABLES_ATTRIBUTE); + } else { + params.putAll((Map) request.getAttribute(HandlerMapping.URI_TEMPLATE_VARIABLES_ATTRIBUTE)); + } + idUser = (String) params.get("idUser"); + } + if (Objects.nonNull(idUser)) { + String authHeader = request.getHeader(JwtConstants.AUTHORIZATION); + if (StringUtils.isNotBlank(authHeader)) { + TokenUser tokenUser = UserUtils.getTokenUser(authHeader); + if (Objects.nonNull(tokenUser)) { + if (!idUser.equals(tokenUser.getIdUser().toString())) { + throw new BaseApiException(ErrorCode.ACCESS_DENIED); + } + } else { + throw new BaseApiException(ErrorCode.ACCESS_DENIED); + } + } + } else { + throw new BaseApiException(ErrorCode.ACCESS_DENIED); + } + logger.info("检查用户修改信息权限 end ..."); + } + + private Map getParams(HttpServletRequest request) { + Map paramsMap = new HashMap<>(10); + Enumeration paraNames = request.getParameterNames(); + while (paraNames.hasMoreElements()) { + String key = paraNames.nextElement(); + if ("password".equals(key)) { + continue; + } + paramsMap.put(key, request.getParameter(key)); + } + return paramsMap; + } + + private boolean isAjax(HttpServletRequest request) { + String requestedWith = request.getHeader("x-requested-with"); + if (requestedWith != null && "XMLHttpRequest".equalsIgnoreCase(requestedWith)) { + return true; + } + String contentType = request.getContentType(); + return StringUtils.isNotBlank(contentType) && contentType.contains("application/json"); + } +} diff --git a/src/main/java/com/rymcu/forest/core/service/security/annotation/SecurityInterceptor.java b/src/main/java/com/rymcu/forest/core/service/security/annotation/SecurityInterceptor.java new file mode 100644 index 0000000..83d3441 --- /dev/null +++ b/src/main/java/com/rymcu/forest/core/service/security/annotation/SecurityInterceptor.java @@ -0,0 +1,12 @@ +package com.rymcu.forest.core.service.security.annotation; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; + +/** + * 安全拦截器 + * @author ronger + */ +@Retention(RetentionPolicy.RUNTIME) +public @interface SecurityInterceptor { +} diff --git a/src/main/java/com/rymcu/forest/jwt/aop/RestAuthTokenInterceptor.java b/src/main/java/com/rymcu/forest/jwt/aop/RestAuthTokenInterceptor.java index 52132eb..256a0e8 100644 --- a/src/main/java/com/rymcu/forest/jwt/aop/RestAuthTokenInterceptor.java +++ b/src/main/java/com/rymcu/forest/jwt/aop/RestAuthTokenInterceptor.java @@ -66,10 +66,10 @@ public class RestAuthTokenInterceptor implements HandlerInterceptor { request.setAttribute(JwtConstants.CURRENT_TOKEN_CLAIMS, claims); //如果token验证成功,将token对应的用户id存在request中,便于之后注入 request.setAttribute(JwtConstants.CURRENT_USER_NAME, model.getUsername()); + String uri = request.getRequestURI(); // 判断是否为后台接口或财政划转接口 String adminApi = "/admin"; String transactionApi = "/transaction"; - String uri = request.getRequestURI(); if (uri.contains(adminApi) || uri.contains(transactionApi)) { // 判断管理员权限 boolean hasPermission = userMapper.hasAdminPermission(model.getUsername()); diff --git a/src/main/java/com/rymcu/forest/web/api/exception/BaseApiException.java b/src/main/java/com/rymcu/forest/web/api/exception/BaseApiException.java index 5140c70..13a32ad 100644 --- a/src/main/java/com/rymcu/forest/web/api/exception/BaseApiException.java +++ b/src/main/java/com/rymcu/forest/web/api/exception/BaseApiException.java @@ -2,6 +2,7 @@ package com.rymcu.forest.web.api.exception; /** * 服务(业务)异常如“ 账号或密码错误 ”,该异常只做INFO级别的日志记录 @see WebMvcConfigurer + * @author ronger */ public class BaseApiException extends Exception { diff --git a/src/main/java/com/rymcu/forest/web/api/user/UserInfoController.java b/src/main/java/com/rymcu/forest/web/api/user/UserInfoController.java index 4b74209..c657376 100644 --- a/src/main/java/com/rymcu/forest/web/api/user/UserInfoController.java +++ b/src/main/java/com/rymcu/forest/web/api/user/UserInfoController.java @@ -2,6 +2,7 @@ package com.rymcu.forest.web.api.user; import com.rymcu.forest.core.result.GlobalResult; import com.rymcu.forest.core.result.GlobalResultGenerator; +import com.rymcu.forest.core.service.security.annotation.SecurityInterceptor; import com.rymcu.forest.dto.*; import com.rymcu.forest.entity.UserExtend; import com.rymcu.forest.service.UserService; @@ -21,36 +22,42 @@ public class UserInfoController { private UserService userService; @GetMapping("/detail/{idUser}") + @SecurityInterceptor public GlobalResult detail(@PathVariable Integer idUser) { Map map = userService.findUserInfo(idUser); return GlobalResultGenerator.genSuccessResult(map); } @GetMapping("/check-nickname") + @SecurityInterceptor public GlobalResult checkNickname(@RequestParam Integer idUser, @RequestParam String nickname) { Map map = userService.checkNickname(idUser,nickname); return GlobalResultGenerator.genSuccessResult(map); } @PatchMapping("/update") + @SecurityInterceptor public GlobalResult updateUserInfo(@RequestBody UserInfoDTO user) { Map map = userService.updateUserInfo(user); return GlobalResultGenerator.genSuccessResult(map); } @PatchMapping("/update-extend") + @SecurityInterceptor public GlobalResult updateUserExtend(@RequestBody UserExtend userExtend) { Map map = userService.updateUserExtend(userExtend); return GlobalResultGenerator.genSuccessResult(map); } @PatchMapping("/update-email") + @SecurityInterceptor public GlobalResult updateEmail(@RequestBody ChangeEmailDTO changeEmailDTO) { Map map = userService.updateEmail(changeEmailDTO); return GlobalResultGenerator.genSuccessResult(map); } @PatchMapping("/update-password") + @SecurityInterceptor public GlobalResult updatePassword(@RequestBody UpdatePasswordDTO updatePasswordDTO) { Map map = userService.updatePassword(updatePasswordDTO); return GlobalResultGenerator.genSuccessResult(map);