解决验证码校验问题和 filter异常处理问题
This commit is contained in:
parent
5193598bb4
commit
c90255f04f
|
|
@ -0,0 +1,98 @@
|
|||
package com.ruoyi.web.admin.filter;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
|
||||
import javax.servlet.ReadListener;
|
||||
import javax.servlet.ServletInputStream;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
|
||||
import org.springframework.web.util.ContentCachingRequestWrapper;
|
||||
|
||||
/**
|
||||
* @author 1763113879@qq.com
|
||||
* @version V2.1
|
||||
* @since 2.1.0 2023/11/16 14:59
|
||||
*/
|
||||
//继承ContentCachingRequestWrapper
|
||||
public class ContentCachingRequestWrapperNew extends ContentCachingRequestWrapper {
|
||||
|
||||
//原子变量,用来区分首次读取还是非首次
|
||||
private AtomicBoolean isFirst = new AtomicBoolean(true);
|
||||
|
||||
public ContentCachingRequestWrapperNew(HttpServletRequest request) {
|
||||
super(request);
|
||||
}
|
||||
|
||||
public ContentCachingRequestWrapperNew(HttpServletRequest request, int contentCacheLimit) {
|
||||
super(request, contentCacheLimit);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ServletInputStream getInputStream() throws IOException {
|
||||
|
||||
if(isFirst.get()){
|
||||
//首次读取直接调父类的方法,这一次执行完之后 缓存流中有数据了
|
||||
//后续读取就读缓存流里的。
|
||||
isFirst.set(false);
|
||||
return super.getInputStream();
|
||||
}
|
||||
|
||||
//用缓存流构建一个新的输入流
|
||||
return new ServletInputStreamNew(super.getContentAsByteArray());
|
||||
}
|
||||
|
||||
//参考自 DelegatingServletInputStream
|
||||
class ServletInputStreamNew extends ServletInputStream{
|
||||
|
||||
private InputStream sourceStream;
|
||||
|
||||
private boolean finished = false;
|
||||
|
||||
|
||||
|
||||
public ServletInputStreamNew(byte [] bytes) {
|
||||
//构建一个普通的输入流
|
||||
this.sourceStream = new ByteArrayInputStream(bytes);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public int read() throws IOException {
|
||||
int data = this.sourceStream.read();
|
||||
if (data == -1) {
|
||||
this.finished = true;
|
||||
}
|
||||
return data;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int available() throws IOException {
|
||||
return this.sourceStream.available();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() throws IOException {
|
||||
super.close();
|
||||
this.sourceStream.close();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isFinished() {
|
||||
return this.finished;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isReady() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setReadListener(ReadListener readListener) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,5 +1,6 @@
|
|||
package com.ruoyi.web.admin.filter;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.IOException;
|
||||
|
||||
import javax.servlet.FilterChain;
|
||||
|
|
@ -10,16 +11,18 @@ import javax.servlet.http.HttpServletResponse;
|
|||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Qualifier;
|
||||
import org.springframework.core.annotation.Order;
|
||||
import org.springframework.http.server.reactive.ServerHttpRequest;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.web.filter.OncePerRequestFilter;
|
||||
import org.springframework.web.servlet.HandlerExceptionResolver;
|
||||
|
||||
import com.alibaba.fastjson2.JSON;
|
||||
import com.alibaba.fastjson2.JSONObject;
|
||||
import com.ruoyi.common.core.constant.CacheConstants;
|
||||
import com.ruoyi.common.core.constant.SecurityConstants;
|
||||
import com.ruoyi.common.core.constant.TokenConstants;
|
||||
import com.ruoyi.common.core.context.SecurityContextHolder;
|
||||
import com.ruoyi.common.core.exception.InnerAuthException;
|
||||
import com.ruoyi.common.core.exception.ServiceException;
|
||||
import com.ruoyi.common.core.utils.JwtUtils;
|
||||
import com.ruoyi.common.core.utils.ServletUtils;
|
||||
|
|
@ -29,7 +32,9 @@ import com.ruoyi.common.security.auth.AuthUtil;
|
|||
import com.ruoyi.common.security.service.TokenService;
|
||||
import com.ruoyi.system.api.model.LoginUser;
|
||||
import com.ruoyi.web.admin.config.CustomHttpServletRequest;
|
||||
import com.ruoyi.web.admin.config.properties.CaptchaProperties;
|
||||
import com.ruoyi.web.admin.config.properties.IgnoreWhiteProperties;
|
||||
import com.ruoyi.web.admin.service.ValidateCodeService;
|
||||
|
||||
import io.jsonwebtoken.Claims;
|
||||
|
||||
|
|
@ -54,6 +59,22 @@ public class JwtAuthenticationTokenFilter extends OncePerRequestFilter {
|
|||
@Autowired
|
||||
private TokenService tokenService;
|
||||
|
||||
@Autowired
|
||||
private ValidateCodeService validateCodeService;
|
||||
|
||||
@Autowired
|
||||
private CaptchaProperties captchaProperties;
|
||||
|
||||
private static final String CODE = "code";
|
||||
|
||||
private static final String UUID = "uuid";
|
||||
|
||||
private final static String[] VALIDATE_URL = new String[] {"/auth/login", "/auth/register"};
|
||||
|
||||
@Autowired
|
||||
@Qualifier("handlerExceptionResolver")
|
||||
private HandlerExceptionResolver resolver;
|
||||
|
||||
@Override
|
||||
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain)
|
||||
throws ServletException, IOException {
|
||||
|
|
@ -66,6 +87,27 @@ public class JwtAuthenticationTokenFilter extends OncePerRequestFilter {
|
|||
}
|
||||
|
||||
String requestURI = request.getRequestURI();
|
||||
|
||||
// 非登录/注册请求或验证码关闭,不处理
|
||||
if (StringUtils.equalsAnyIgnoreCase(requestURI, VALIDATE_URL) && captchaProperties.getEnabled()) {
|
||||
|
||||
//,HttpServletRequst中的body内容只会读取一次,但是可能某些情境下可能会读取多次,替换request
|
||||
ContentCachingRequestWrapperNew wrappedRequest = new ContentCachingRequestWrapperNew(request);
|
||||
try {
|
||||
String rspStr = resolveBodyFromRequest(wrappedRequest);
|
||||
JSONObject obj = JSON.parseObject(rspStr);
|
||||
validateCodeService.checkCaptcha(obj.getString(CODE), obj.getString(UUID));
|
||||
} catch (Exception e) {
|
||||
// throw new ServiceException(e.getMessage());
|
||||
resolver.resolveException(request, response, null, e);
|
||||
return;
|
||||
|
||||
}
|
||||
|
||||
|
||||
request = wrappedRequest;
|
||||
}
|
||||
|
||||
// 跳过不需要验证的路径
|
||||
if (!StringUtils.matches(requestURI, ignoreWhite.getWhites())) {
|
||||
|
||||
|
|
@ -83,7 +125,6 @@ public class JwtAuthenticationTokenFilter extends OncePerRequestFilter {
|
|||
boolean islogin = redisService.hasKey(getTokenKey(userkey));
|
||||
if (!islogin) {
|
||||
throw new ServiceException("登录状态已过期");
|
||||
|
||||
}
|
||||
String userid = JwtUtils.getUserId(claims);
|
||||
String username = JwtUtils.getUserName(claims);
|
||||
|
|
@ -136,10 +177,8 @@ public class JwtAuthenticationTokenFilter extends OncePerRequestFilter {
|
|||
return token;
|
||||
}
|
||||
|
||||
private void addHeader(CustomHttpServletRequest customHttpServletRequest, String name, Object value)
|
||||
{
|
||||
if (value == null)
|
||||
{
|
||||
private void addHeader(CustomHttpServletRequest customHttpServletRequest, String name, Object value) {
|
||||
if (value == null) {
|
||||
return;
|
||||
}
|
||||
String valueStr = value.toString();
|
||||
|
|
@ -147,6 +186,24 @@ public class JwtAuthenticationTokenFilter extends OncePerRequestFilter {
|
|||
customHttpServletRequest.addHeader(name, valueEncode);
|
||||
}
|
||||
|
||||
private String resolveBodyFromRequest(HttpServletRequest request) throws IOException {
|
||||
|
||||
// 直接从HttpServletRequest的Reader流中获取RequestBody
|
||||
BufferedReader reader = request.getReader();
|
||||
StringBuilder builder = new StringBuilder();
|
||||
String line = reader.readLine();
|
||||
while (line != null) {
|
||||
builder.append(line);
|
||||
line = reader.readLine();
|
||||
}
|
||||
reader.close();
|
||||
String reqBody = builder.toString();
|
||||
return reqBody;
|
||||
|
||||
// String requestBody = new String(request.getContentAsByteArray());
|
||||
// return requestBody;
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,35 @@
|
|||
package com.ruoyi.web.admin.handler;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.web.bind.annotation.ExceptionHandler;
|
||||
import org.springframework.web.bind.annotation.RestControllerAdvice;
|
||||
|
||||
import com.ruoyi.common.core.exception.CaptchaException;
|
||||
import com.ruoyi.common.core.web.domain.AjaxResult;
|
||||
|
||||
/**
|
||||
* 全局异常处理器
|
||||
*
|
||||
* @author ruoyi
|
||||
*/
|
||||
@RestControllerAdvice
|
||||
public class GlobalAdminWebExceptionHandler
|
||||
{
|
||||
private static final Logger log = LoggerFactory.getLogger(GlobalAdminWebExceptionHandler.class);
|
||||
|
||||
|
||||
/**
|
||||
* 验证码异常
|
||||
*/
|
||||
@ExceptionHandler(CaptchaException.class)
|
||||
public AjaxResult handleCaptchaException(CaptchaException e, HttpServletRequest request)
|
||||
{
|
||||
String requestURI = request.getRequestURI();
|
||||
log.error("请求地址'{}'", requestURI, e.getMessage());
|
||||
return AjaxResult.error(e.getMessage());
|
||||
}
|
||||
|
||||
}
|
||||
Loading…
Reference in New Issue