Compare commits

..

No commits in common. '077751021e1d853f218c177e90931d67cc44926b' and 'e044f02d32e110bc1c0dcbb544d25de2a703ebfc' have entirely different histories.

  1. 2
      src/main/java/cn/soul2/jyjc/admin/JavaJyjcAdminApplication.java
  2. 28
      src/main/java/cn/soul2/jyjc/admin/config/CorsConfig.java
  3. 4
      src/main/java/cn/soul2/jyjc/admin/config/UserLoginStatusBean.java
  4. 45
      src/main/java/cn/soul2/jyjc/admin/config/WebMvcConfig.java
  5. 1
      src/main/java/cn/soul2/jyjc/admin/filter/ReplaceStreamFilter.java
  6. 16
      src/main/java/cn/soul2/jyjc/admin/filter/ShaoduoRequestWrapper.java
  7. 84
      src/main/java/cn/soul2/jyjc/admin/interceptor/FinallyInterceptor.java
  8. 2
      src/main/java/cn/soul2/jyjc/admin/repository/impl/UserLoginOutRepositoryImpl.java
  9. 2
      src/main/resources/application-cors.yml

@ -3,6 +3,7 @@ package cn.soul2.jyjc.admin;
import org.mybatis.spring.annotation.MapperScan; import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication; import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.ComponentScan;
/** /**
* @author Soul2 * @author Soul2
@ -10,6 +11,7 @@ import org.springframework.boot.autoconfigure.SpringBootApplication;
*/ */
@SpringBootApplication @SpringBootApplication
@MapperScan("cn.soul2.jyjc.admin.mapper") @MapperScan("cn.soul2.jyjc.admin.mapper")
@ComponentScan("cn.soul2.jyjc.admin.config")
public class JavaJyjcAdminApplication { public class JavaJyjcAdminApplication {
public static void main(String[] args) { public static void main(String[] args) {

@ -0,0 +1,28 @@
package cn.soul2.jyjc.admin.config;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
/**
* @author Soul2
* @date 2024-03-25
*/
@Configuration
public class CorsConfig implements WebMvcConfigurer {
@Value("${cors.allow-origin}")
private String[] allowOrigin;
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**")
.allowedHeaders("*")
.allowedOrigins(allowOrigin)
.allowCredentials(true)
.allowedMethods("POST")
.maxAge(3600);
}
}

@ -1,4 +1,4 @@
package cn.soul2.jyjc.admin.bean; package cn.soul2.jyjc.admin.config;
import cn.soul2.jyjc.admin.entity.UserLoginOutDO; import cn.soul2.jyjc.admin.entity.UserLoginOutDO;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
@ -80,7 +80,7 @@ public class UserLoginStatusBean {
return Boolean.FALSE; return Boolean.FALSE;
} }
UserLoginOutDO loginStatus = loginStatusMap.getOrDefault(token, null); UserLoginOutDO loginStatus = loginStatusMap.getOrDefault(token, null);
if (loginStatus != null && loginStatus.getLapseTime() != null) { if (loginStatus.getLapseTime() != null) {
LocalDateTime now = LocalDateTime.now(); LocalDateTime now = LocalDateTime.now();
if (now.isAfter(loginStatus.getLapseTime())) { if (now.isAfter(loginStatus.getLapseTime())) {
logout(token); logout(token);

@ -1,12 +1,7 @@
package cn.soul2.jyjc.admin.config; package cn.soul2.jyjc.admin.config;
import cn.soul2.jyjc.admin.interceptor.FinallyInterceptor; import cn.soul2.jyjc.admin.interceptor.FinallyInterceptor;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Configuration;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
import org.springframework.web.filter.CorsFilter;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry; import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
@ -20,47 +15,9 @@ import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
@Configuration @Configuration
public class WebMvcConfig implements WebMvcConfigurer { public class WebMvcConfig implements WebMvcConfigurer {
@Value("${cors.allow-origin}")
private String[] allowOrigin;
@Bean
public CorsFilter corsFilter() {
CorsConfiguration config = new CorsConfiguration();
// 设置允许跨域请求的域名
for (String url : allowOrigin) {
config.addAllowedOrigin(url);
}
// 是否允许证书 不再默认开启
// config.setAllowCredentials(true);
// 设置允许的方法
config.addAllowedMethod("*");
// 允许任何头
config.addAllowedHeader("*");
config.addExposedHeader("token");
config.setMaxAge(3600L);
UrlBasedCorsConfigurationSource configSource = new UrlBasedCorsConfigurationSource();
configSource.registerCorsConfiguration("/**", config);
return new CorsFilter(configSource);
}
// @Override
// public void addCorsMappings(CorsRegistry registry) {
// registry.addMapping("/**")
// .allowedHeaders("*")
// .allowedOrigins(allowOrigin)
// .allowCredentials(true)
// .allowedMethods("POST")
// .maxAge(3600);
// }
@Bean
FinallyInterceptor createFinallyInterceptor() {
return new FinallyInterceptor();
}
@Override @Override
public void addInterceptors(InterceptorRegistry registry) { public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(createFinallyInterceptor()) registry.addInterceptor(new FinallyInterceptor())
// 拦截所有路径 // 拦截所有路径
.addPathPatterns("/**"); .addPathPatterns("/**");
} }

@ -27,7 +27,6 @@ public class ReplaceStreamFilter implements Filter {
return; return;
} else { } else {
ServletRequest requestWrapper = new ShaoduoRequestWrapper((HttpServletRequest) request); ServletRequest requestWrapper = new ShaoduoRequestWrapper((HttpServletRequest) request);
// System.out.printf("ReplaceStreamFilter触发, Method: %s, URI: %s%n", ((HttpServletRequest) request).getMethod(), ((HttpServletRequest) request).getRequestURI());
chain.doFilter(requestWrapper, response); chain.doFilter(requestWrapper, response);
return; return;
} }

@ -14,7 +14,7 @@ import java.nio.charset.StandardCharsets;
/** /**
* @author shaoduo * @author shaoduo
* @description 包装HttpServletRequest目的是让其输入流可重复读 * @description 包装HttpServletRequest目的是让其输入流可重复读
* @since <a href="https://blog.csdn.net/shaoduo/article/details/122322578">shaoduo</a> * @since 1.0
**/ **/
@Slf4j @Slf4j
public class ShaoduoRequestWrapper extends HttpServletRequestWrapper { public class ShaoduoRequestWrapper extends HttpServletRequestWrapper {
@ -23,7 +23,7 @@ public class ShaoduoRequestWrapper extends HttpServletRequestWrapper {
*/ */
private byte[] body; private byte[] body;
public ShaoduoRequestWrapper(HttpServletRequest request) { public ShaoduoRequestWrapper(HttpServletRequest request) throws IOException {
super(request); super(request);
// 将body数据存储起来 // 将body数据存储起来
@ -51,8 +51,9 @@ public class ShaoduoRequestWrapper extends HttpServletRequestWrapper {
* *
* @return String * @return String
*/ */
public String getBodyString() throws IOException { public String getBodyString() {
InputStream inputStream = new ByteArrayInputStream(body); InputStream inputStream = new ByteArrayInputStream(body);
return inputStream2String(inputStream); return inputStream2String(inputStream);
} }
@ -62,6 +63,7 @@ public class ShaoduoRequestWrapper extends HttpServletRequestWrapper {
* @param val * @param val
*/ */
public void setBody(String val) { public void setBody(String val) {
body = val.getBytes(StandardCharsets.UTF_8); body = val.getBytes(StandardCharsets.UTF_8);
} }
@ -71,7 +73,7 @@ public class ShaoduoRequestWrapper extends HttpServletRequestWrapper {
* @param inputStream inputStream * @param inputStream inputStream
* @return String * @return String
*/ */
private String inputStream2String(InputStream inputStream) throws IOException { private String inputStream2String(InputStream inputStream) {
StringBuilder sb = new StringBuilder(); StringBuilder sb = new StringBuilder();
BufferedReader reader = null; BufferedReader reader = null;
@ -93,6 +95,8 @@ public class ShaoduoRequestWrapper extends HttpServletRequestWrapper {
} }
} }
} }
return sb.toString(); return sb.toString();
} }
@ -102,13 +106,13 @@ public class ShaoduoRequestWrapper extends HttpServletRequestWrapper {
} }
@Override @Override
public ServletInputStream getInputStream() { public ServletInputStream getInputStream() throws IOException {
final ByteArrayInputStream inputStream = new ByteArrayInputStream(body); final ByteArrayInputStream inputStream = new ByteArrayInputStream(body);
return new ServletInputStream() { return new ServletInputStream() {
@Override @Override
public int read() { public int read() throws IOException {
return inputStream.read(); return inputStream.read();
} }

@ -2,21 +2,22 @@ package cn.soul2.jyjc.admin.interceptor;
import cn.soul2.jyjc.admin.annotation.SkinEncrypt; import cn.soul2.jyjc.admin.annotation.SkinEncrypt;
import cn.soul2.jyjc.admin.annotation.SkinLogin; import cn.soul2.jyjc.admin.annotation.SkinLogin;
import cn.soul2.jyjc.admin.bean.UserLoginStatusBean; import cn.soul2.jyjc.admin.config.UserLoginStatusBean;
import cn.soul2.jyjc.admin.filter.ShaoduoRequestWrapper; import cn.soul2.jyjc.admin.filter.ShaoduoRequestWrapper;
import cn.soul2.jyjc.admin.utils.EncryptUtils; import cn.soul2.jyjc.admin.utils.EncryptUtils;
import cn.soul2.jyjc.admin.vo.base.Back;
import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject; import com.alibaba.fastjson.JSONObject;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Lazy;
import org.springframework.http.MediaType;
import org.springframework.web.method.HandlerMethod; import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerInterceptor; import org.springframework.web.servlet.HandlerInterceptor;
import javax.annotation.Resource; import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpServletResponse;
import java.io.PrintWriter;
import java.lang.reflect.Method; import java.lang.reflect.Method;
/** /**
@ -28,14 +29,18 @@ import java.lang.reflect.Method;
@Slf4j @Slf4j
public class FinallyInterceptor implements HandlerInterceptor { public class FinallyInterceptor implements HandlerInterceptor {
@Autowired
@Lazy
private ApplicationContext context;
@Resource @Resource
@Lazy
private UserLoginStatusBean userLoginStatusBean; private UserLoginStatusBean userLoginStatusBean;
@Override @Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
boolean pass = false; boolean pass = false;
// 允许OPTIONS请求通过 // 允许OPTIONS请求通过
if ("OPTIONS".equalsIgnoreCase(request.getMethod())) { if ("OPTIONS".equals(request.getMethod()) && request.getHeader("Origin") != null) {
return true; return true;
} }
// 如果不是映射到方法直接通过 // 如果不是映射到方法直接通过
@ -63,63 +68,60 @@ public class FinallyInterceptor implements HandlerInterceptor {
if (request.getContentType() == null) { if (request.getContentType() == null) {
pass = true; pass = true;
} }
// 如果类型不是json 就放行
if (!(request.getContentType().equals(MediaType.APPLICATION_JSON_VALUE))) {
pass = true;
}
} }
// 跳过使用 @SkinEncrypt 的情况
// 跳过使用SkinEncrypt注解的情况
if (skinEncrypt != null) { if (skinEncrypt != null) {
pass = true; pass = true;
} }
ShaoduoRequestWrapper shaoduoRequestWrapper;
if (request instanceof ShaoduoRequestWrapper) {
shaoduoRequestWrapper = (ShaoduoRequestWrapper) request;
} else {
shaoduoRequestWrapper = new ShaoduoRequestWrapper(request);
request = shaoduoRequestWrapper;
}
String jsonParamBody = shaoduoRequestWrapper.getBodyString();
JSONObject obj = JSON.parseObject(EncryptUtils.decrypt(jsonParamBody));
String afterBody = JSONObject.toJSONString(obj);
if (!pass) { System.out.println("加密前 " + jsonParamBody);
ShaoduoRequestWrapper shaoduoRequestWrapper; System.out.println("解密后 " + afterBody);
try { shaoduoRequestWrapper.setBody(afterBody);
shaoduoRequestWrapper = (ShaoduoRequestWrapper) request; String temp = new ShaoduoRequestWrapper(shaoduoRequestWrapper).getBodyString();
} catch (Exception e) { System.out.println("过滤器中缓存 " + temp);
System.out.printf("request.ClassTypeError: %s%n", request.getClass().getName());
return true;
}
String sourceParamBody = shaoduoRequestWrapper.getBodyString();
JSONObject obj = JSON.parseObject(EncryptUtils.decrypt(sourceParamBody));
String afterBody = JSONObject.toJSONString(obj);
shaoduoRequestWrapper.setBody(afterBody);
log.info(String.format("解密: %s -> %s", sourceParamBody, afterBody));
} /*
token验证
*/
/* token验证 */
if (hasSkinLogin) { if (hasSkinLogin) {
// 跳过使用 @SkinLogin 的情况 // 如果存在,绕过拦截器
pass = true; pass = true;
} else { } else {
// 验证token // 验证token
if (userLoginStatusBean == null) {
userLoginStatusBean = context.getBean(UserLoginStatusBean.class);
}
// 检查 token 是否存在并且有效 // 检查 token 是否存在并且有效
if (token == null) { if (token == null) {
// 没有Token,拒绝请求 // 没有Token,拒绝请求
response.setStatus(40401); response.setStatus(40401);
pass = false; pass = false;
} else if (userLoginStatusBean != null) { } else if (userLoginStatusBean != null && !userLoginStatusBean.containsToken(token)) {
if (!userLoginStatusBean.containsToken(token)) { // Token 无效,拒绝请求,可以返回特定的响应状态码,例如 401 Unauthorized
// Token 无效,拒绝请求 response.setStatus(40401);
response.setStatus(0); pass = false;
Back<String> back = new Back<String>().setCode(40401).setMessage("Token invalid!");
// 转换为 JSON 字符串
ObjectMapper objectMapper = new ObjectMapper();
String responseBody = objectMapper.writeValueAsString(back);
// 输出错误信息到响应中
PrintWriter writer = response.getWriter();
writer.print(responseBody);
writer.flush();
pass = false;
} else {
// token存在, 通过拦截器
pass = true;
}
} }
} }
} catch (Exception e) { } catch (Exception e) {
throw new RuntimeException(e); throw new RuntimeException(e);
} }
return pass; return pass;
} }

@ -1,6 +1,6 @@
package cn.soul2.jyjc.admin.repository.impl; package cn.soul2.jyjc.admin.repository.impl;
import cn.soul2.jyjc.admin.bean.UserLoginStatusBean; import cn.soul2.jyjc.admin.config.UserLoginStatusBean;
import cn.soul2.jyjc.admin.dto.UserLoginDTO; import cn.soul2.jyjc.admin.dto.UserLoginDTO;
import cn.soul2.jyjc.admin.dto.UserLoginOutPageDTO; import cn.soul2.jyjc.admin.dto.UserLoginOutPageDTO;
import cn.soul2.jyjc.admin.dto.UserLogoutDTO; import cn.soul2.jyjc.admin.dto.UserLogoutDTO;

@ -1,7 +1,7 @@
# 允许跨域的地址 # 允许跨域的地址
cors: cors:
allow-origin: http://localhost:6100, http://localhost:7620 allow-origin: http://localhost
--- ---
spring: spring:

Loading…
Cancel
Save