临时提交
This commit is contained in:
@@ -1,16 +1,9 @@
|
||||
package com.genersoft.iot.vmp.conf.security;
|
||||
|
||||
import cn.hutool.core.util.CharsetUtil;
|
||||
import cn.hutool.core.util.HexUtil;
|
||||
import cn.hutool.crypto.SmUtil;
|
||||
import cn.hutool.crypto.symmetric.SM4;
|
||||
import com.alibaba.fastjson2.JSON;
|
||||
import com.alibaba.fastjson2.JSONObject;
|
||||
import com.genersoft.iot.vmp.conf.UserSetting;
|
||||
import com.genersoft.iot.vmp.conf.security.dto.JwtUser;
|
||||
import com.genersoft.iot.vmp.storager.dao.dto.Role;
|
||||
import com.genersoft.iot.vmp.storager.dao.dto.User;
|
||||
import com.genersoft.iot.vmp.web.custom.conf.SyTokenManager;
|
||||
import jakarta.servlet.FilterChain;
|
||||
import jakarta.servlet.ServletException;
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
@@ -18,7 +11,6 @@ import jakarta.servlet.http.HttpServletResponse;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
|
||||
import org.springframework.security.core.context.SecurityContextHolder;
|
||||
import org.springframework.stereotype.Component;
|
||||
@@ -26,11 +18,7 @@ import org.springframework.web.filter.OncePerRequestFilter;
|
||||
import org.springframework.web.util.ContentCachingRequestWrapper;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.time.Instant;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.TreeSet;
|
||||
|
||||
/**
|
||||
* jwt token 过滤器
|
||||
@@ -48,30 +36,19 @@ public class JwtAuthenticationFilter extends OncePerRequestFilter {
|
||||
|
||||
|
||||
@Override
|
||||
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws IOException, ServletException {
|
||||
|
||||
protected void doFilterInternal(HttpServletRequest servletRequest, HttpServletResponse response, FilterChain chain) throws IOException, ServletException {
|
||||
ContentCachingRequestWrapper request = new ContentCachingRequestWrapper(servletRequest);
|
||||
// 忽略登录请求的token验证
|
||||
String requestURI = request.getRequestURI();
|
||||
if ((requestURI.startsWith("/doc.html") || requestURI.startsWith("/swagger-ui") ) && !userSetting.getDocEnable()) {
|
||||
response.setStatus(HttpServletResponse.SC_NOT_FOUND);
|
||||
return;
|
||||
}
|
||||
|
||||
if (requestURI.equalsIgnoreCase("/api/user/login")) {
|
||||
chain.doFilter(request, response);
|
||||
return;
|
||||
}
|
||||
if (requestURI.startsWith("/api/sy")) {
|
||||
|
||||
// 包装原始请求,缓存请求体
|
||||
ContentCachingRequestWrapper wrappedRequest = new ContentCachingRequestWrapper(request);
|
||||
if (signCheck(wrappedRequest)) {
|
||||
// 使用参数签名方式校验
|
||||
UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken(null, null, new ArrayList<>() );
|
||||
SecurityContextHolder.getContext().setAuthentication(token);
|
||||
chain.doFilter(wrappedRequest, response);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (!userSetting.getInterfaceAuthentication()) {
|
||||
UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken(null, null, new ArrayList<>() );
|
||||
@@ -134,88 +111,4 @@ public class JwtAuthenticationFilter extends OncePerRequestFilter {
|
||||
SecurityContextHolder.getContext().setAuthentication(token);
|
||||
chain.doFilter(request, response);
|
||||
}
|
||||
|
||||
private boolean signCheck(ContentCachingRequestWrapper request) {
|
||||
try {
|
||||
String sign = request.getParameter("sign");
|
||||
String appKey = request.getParameter("appKey");
|
||||
String accessToken = request.getParameter("accessToken");
|
||||
String timestampStr = request.getParameter("timestamp");
|
||||
|
||||
if (sign == null || appKey == null || accessToken == null || timestampStr == null) {
|
||||
log.info("[SY-接口验签] 缺少关键参数:sign/appKey/accessToken/timestamp ");
|
||||
return false;
|
||||
}
|
||||
if (SyTokenManager.INSTANCE.appMap.get(appKey) == null) {
|
||||
log.info("[SY-接口验签] appKey {} 对应的 secret 不存在", appKey);
|
||||
return false;
|
||||
}
|
||||
|
||||
Map<String, String[]> parameterMap = request.getParameterMap();
|
||||
// 参数排序
|
||||
Set<String> paramKeys = new TreeSet<>(parameterMap.keySet());
|
||||
|
||||
// 拼接签名信息
|
||||
// 参数拼接
|
||||
StringBuilder beforeSign = new StringBuilder();
|
||||
for (String paramKey : paramKeys) {
|
||||
if (paramKey.equals("sign")) {
|
||||
continue;
|
||||
}
|
||||
beforeSign.append(paramKey).append(parameterMap.get(paramKey)[0]);
|
||||
}
|
||||
// 如果是post请求的json消息,拼接body字符串
|
||||
if (request.getContentLength() > 0
|
||||
&& request.getMethod().equalsIgnoreCase("POST")
|
||||
&& request.getContentType().equalsIgnoreCase(MediaType.APPLICATION_JSON_VALUE)) {
|
||||
// 读取body内容
|
||||
byte[] requestBodyBytes = request.getContentAsByteArray();
|
||||
|
||||
if (requestBodyBytes.length > 0) {
|
||||
String requestBody = new String(requestBodyBytes, request.getCharacterEncoding());
|
||||
beforeSign.append(requestBody);
|
||||
}
|
||||
}
|
||||
beforeSign.append(SyTokenManager.INSTANCE.appMap.get(appKey));
|
||||
// 生成签名
|
||||
String buildSign = SmUtil.sm3(beforeSign.toString());
|
||||
if (!buildSign.equals(sign)) {
|
||||
log.info("[SY-接口验签] 失败, 加密前内容: {}", beforeSign);
|
||||
return false;
|
||||
}
|
||||
// 验证请求时间戳
|
||||
long timestamp = Long.parseLong(timestampStr);
|
||||
Instant timeInstant = Instant.ofEpochMilli(timestamp + SyTokenManager.INSTANCE.expires * 60 * 1000);
|
||||
if (timeInstant.isBefore(Instant.now())) {
|
||||
log.info("[SY-接口验签] 时间戳已经过期");
|
||||
return false;
|
||||
}
|
||||
// accessToken校验
|
||||
if (accessToken.equals(SyTokenManager.INSTANCE.adminToken)) {
|
||||
log.info("[SY-接口验签] adminToken已经默认放行");
|
||||
return true;
|
||||
}else {
|
||||
// 对token进行解密
|
||||
SM4 sm4 = SmUtil.sm4(HexUtil.decodeHex(SyTokenManager.INSTANCE.sm4Key));
|
||||
String decryptStr = sm4.decryptStr(accessToken, CharsetUtil.CHARSET_UTF_8);
|
||||
if (decryptStr == null) {
|
||||
log.info("[SY-接口验签] accessToken解密失败");
|
||||
return false;
|
||||
}
|
||||
JSONObject jsonObject = JSON.parseObject(decryptStr);
|
||||
Long expirationTime = jsonObject.getLong("expirationTime");
|
||||
if (expirationTime < System.currentTimeMillis()) {
|
||||
log.info("[SY-接口验签] accessToken 已经过期");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}catch (Exception e) {
|
||||
log.info("[SY-接口验签] 读取body失败", e);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user