🔒 安全问题处理

This commit is contained in:
ronger 2021-12-10 11:27:25 +08:00
parent 67f7615a18
commit 98d4870be3
6 changed files with 138 additions and 8 deletions

View File

@ -7,6 +7,7 @@ import com.rymcu.forest.core.result.GlobalResult;
import com.rymcu.forest.core.result.ResultCode; import com.rymcu.forest.core.result.ResultCode;
import com.rymcu.forest.enumerate.TransactionCode; import com.rymcu.forest.enumerate.TransactionCode;
import com.rymcu.forest.web.api.exception.BaseApiException; 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.UnauthenticatedException;
import org.apache.shiro.authz.UnauthorizedException; import org.apache.shiro.authz.UnauthorizedException;
import org.slf4j.Logger; import org.slf4j.Logger;
@ -39,9 +40,9 @@ public class BaseExceptionHandler {
if (isAjax(request)) { if (isAjax(request)) {
GlobalResult result = new GlobalResult(); GlobalResult result = new GlobalResult();
if (ex instanceof BaseApiException) { if (ex instanceof BaseApiException) {
result.setCode(401); result.setCode(((BaseApiException) ex).getCode());
result.setMessage("用户未登录"); result.setMessage(((BaseApiException) ex).getExtraMessage());
logger.info("用户未登录"); logger.info(result.getMessage());
} else if (ex instanceof UnauthenticatedException) { } else if (ex instanceof UnauthenticatedException) {
result.setCode(1000001); result.setCode(1000001);
result.setMessage("token错误"); result.setMessage("token错误");
@ -88,8 +89,8 @@ public class BaseExceptionHandler {
FastJsonJsonView view = new FastJsonJsonView(); FastJsonJsonView view = new FastJsonJsonView();
Map<String, Object> attributes = new HashMap(2); Map<String, Object> attributes = new HashMap(2);
if (ex instanceof BaseApiException) { if (ex instanceof BaseApiException) {
attributes.put("code", "401"); attributes.put("code", ((BaseApiException) ex).getCode());
attributes.put("message", "用户未登录"); attributes.put("message", ((BaseApiException) ex).getExtraMessage());
} else if (ex instanceof UnauthenticatedException) { } else if (ex instanceof UnauthenticatedException) {
attributes.put("code", "1000001"); attributes.put("code", "1000001");
attributes.put("message", "token错误"); attributes.put("message", "token错误");
@ -138,8 +139,8 @@ public class BaseExceptionHandler {
String requestedWith = request.getHeader("x-requested-with"); String requestedWith = request.getHeader("x-requested-with");
if (requestedWith != null && "XMLHttpRequest".equalsIgnoreCase(requestedWith)) { if (requestedWith != null && "XMLHttpRequest".equalsIgnoreCase(requestedWith)) {
return true; return true;
} else { }
return false; String contentType = request.getContentType();
} return StringUtils.isNotBlank(contentType) && contentType.contains("application/json");
} }
} }

View File

@ -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<String, String> getParams(HttpServletRequest request) {
Map<String, String> paramsMap = new HashMap<>(10);
Enumeration<String> 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");
}
}

View File

@ -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 {
}

View File

@ -66,10 +66,10 @@ public class RestAuthTokenInterceptor implements HandlerInterceptor {
request.setAttribute(JwtConstants.CURRENT_TOKEN_CLAIMS, claims); request.setAttribute(JwtConstants.CURRENT_TOKEN_CLAIMS, claims);
//如果token验证成功将token对应的用户id存在request中便于之后注入 //如果token验证成功将token对应的用户id存在request中便于之后注入
request.setAttribute(JwtConstants.CURRENT_USER_NAME, model.getUsername()); request.setAttribute(JwtConstants.CURRENT_USER_NAME, model.getUsername());
String uri = request.getRequestURI();
// 判断是否为后台接口或财政划转接口 // 判断是否为后台接口或财政划转接口
String adminApi = "/admin"; String adminApi = "/admin";
String transactionApi = "/transaction"; String transactionApi = "/transaction";
String uri = request.getRequestURI();
if (uri.contains(adminApi) || uri.contains(transactionApi)) { if (uri.contains(adminApi) || uri.contains(transactionApi)) {
// 判断管理员权限 // 判断管理员权限
boolean hasPermission = userMapper.hasAdminPermission(model.getUsername()); boolean hasPermission = userMapper.hasAdminPermission(model.getUsername());

View File

@ -2,6 +2,7 @@ package com.rymcu.forest.web.api.exception;
/** /**
* 服务业务异常如 账号或密码错误 该异常只做INFO级别的日志记录 @see WebMvcConfigurer * 服务业务异常如 账号或密码错误 该异常只做INFO级别的日志记录 @see WebMvcConfigurer
* @author ronger
*/ */
public class BaseApiException extends Exception { public class BaseApiException extends Exception {

View File

@ -2,6 +2,7 @@ package com.rymcu.forest.web.api.user;
import com.rymcu.forest.core.result.GlobalResult; import com.rymcu.forest.core.result.GlobalResult;
import com.rymcu.forest.core.result.GlobalResultGenerator; 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.dto.*;
import com.rymcu.forest.entity.UserExtend; import com.rymcu.forest.entity.UserExtend;
import com.rymcu.forest.service.UserService; import com.rymcu.forest.service.UserService;
@ -21,36 +22,42 @@ public class UserInfoController {
private UserService userService; private UserService userService;
@GetMapping("/detail/{idUser}") @GetMapping("/detail/{idUser}")
@SecurityInterceptor
public GlobalResult detail(@PathVariable Integer idUser) { public GlobalResult detail(@PathVariable Integer idUser) {
Map map = userService.findUserInfo(idUser); Map map = userService.findUserInfo(idUser);
return GlobalResultGenerator.genSuccessResult(map); return GlobalResultGenerator.genSuccessResult(map);
} }
@GetMapping("/check-nickname") @GetMapping("/check-nickname")
@SecurityInterceptor
public GlobalResult checkNickname(@RequestParam Integer idUser, @RequestParam String nickname) { public GlobalResult checkNickname(@RequestParam Integer idUser, @RequestParam String nickname) {
Map map = userService.checkNickname(idUser,nickname); Map map = userService.checkNickname(idUser,nickname);
return GlobalResultGenerator.genSuccessResult(map); return GlobalResultGenerator.genSuccessResult(map);
} }
@PatchMapping("/update") @PatchMapping("/update")
@SecurityInterceptor
public GlobalResult updateUserInfo(@RequestBody UserInfoDTO user) { public GlobalResult updateUserInfo(@RequestBody UserInfoDTO user) {
Map map = userService.updateUserInfo(user); Map map = userService.updateUserInfo(user);
return GlobalResultGenerator.genSuccessResult(map); return GlobalResultGenerator.genSuccessResult(map);
} }
@PatchMapping("/update-extend") @PatchMapping("/update-extend")
@SecurityInterceptor
public GlobalResult updateUserExtend(@RequestBody UserExtend userExtend) { public GlobalResult updateUserExtend(@RequestBody UserExtend userExtend) {
Map map = userService.updateUserExtend(userExtend); Map map = userService.updateUserExtend(userExtend);
return GlobalResultGenerator.genSuccessResult(map); return GlobalResultGenerator.genSuccessResult(map);
} }
@PatchMapping("/update-email") @PatchMapping("/update-email")
@SecurityInterceptor
public GlobalResult updateEmail(@RequestBody ChangeEmailDTO changeEmailDTO) { public GlobalResult updateEmail(@RequestBody ChangeEmailDTO changeEmailDTO) {
Map map = userService.updateEmail(changeEmailDTO); Map map = userService.updateEmail(changeEmailDTO);
return GlobalResultGenerator.genSuccessResult(map); return GlobalResultGenerator.genSuccessResult(map);
} }
@PatchMapping("/update-password") @PatchMapping("/update-password")
@SecurityInterceptor
public GlobalResult updatePassword(@RequestBody UpdatePasswordDTO updatePasswordDTO) { public GlobalResult updatePassword(@RequestBody UpdatePasswordDTO updatePasswordDTO) {
Map map = userService.updatePassword(updatePasswordDTO); Map map = userService.updatePassword(updatePasswordDTO);
return GlobalResultGenerator.genSuccessResult(map); return GlobalResultGenerator.genSuccessResult(map);