Commit b5cb6865 authored by 以墨为白's avatar 以墨为白 🎧

2

parent cbaf93de
...@@ -103,6 +103,24 @@ ...@@ -103,6 +103,24 @@
<artifactId>hutool-all</artifactId> <artifactId>hutool-all</artifactId>
<version>5.8.2</version> <version>5.8.2</version>
</dependency> </dependency>
<!--swagger2-->
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger2</artifactId>
<version>2.9.2</version>
</dependency>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger-ui</artifactId>
<version>2.9.2</version>
</dependency>
<dependency>
<groupId>ma.glasnost.orika</groupId>
<artifactId>orika-core</artifactId>
<version>1.5.4</version>
</dependency>
</dependencies> </dependencies>
<build> <build>
......
...@@ -13,7 +13,6 @@ import org.springframework.boot.web.servlet.ServletComponentScan; ...@@ -13,7 +13,6 @@ import org.springframework.boot.web.servlet.ServletComponentScan;
DataSourceAutoConfiguration.class, DataSourceAutoConfiguration.class,
DataSourceTransactionManagerAutoConfiguration.class, DataSourceTransactionManagerAutoConfiguration.class,
}) })
@ServletComponentScan
public class Main { public class Main {
public static void main(String[] args) { public static void main(String[] args) {
SpringApplication.run(Main.class, args); SpringApplication.run(Main.class, args);
......
...@@ -20,8 +20,8 @@ import org.springframework.web.context.request.ServletRequestAttributes; ...@@ -20,8 +20,8 @@ import org.springframework.web.context.request.ServletRequestAttributes;
import javax.annotation.Resource; import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequest;
@Aspect//声明切面,标记类(1时间,2地点,3内容) //@Aspect//声明切面,标记类(1时间,2地点,3内容)
@Component //@Component
public class SignatureAspect { public class SignatureAspect {
private static final Logger logger = LoggerFactory.getLogger(AuthAspect.class); private static final Logger logger = LoggerFactory.getLogger(AuthAspect.class);
......
...@@ -3,10 +3,13 @@ package com.zksy.szpt.config; ...@@ -3,10 +3,13 @@ package com.zksy.szpt.config;
import com.alibaba.druid.pool.DruidDataSource; import com.alibaba.druid.pool.DruidDataSource;
import com.baomidou.mybatisplus.core.MybatisConfiguration; import com.baomidou.mybatisplus.core.MybatisConfiguration;
import com.baomidou.mybatisplus.core.config.GlobalConfig;
import com.baomidou.mybatisplus.core.toolkit.GlobalConfigUtils;
import com.baomidou.mybatisplus.extension.spring.MybatisSqlSessionFactoryBean;
import com.github.pagehelper.PageInterceptor; import com.github.pagehelper.PageInterceptor;
import com.zksy.szpt.handler.SzptMetaObjectHandler;
import org.apache.ibatis.plugin.Interceptor; import org.apache.ibatis.plugin.Interceptor;
import org.apache.ibatis.session.SqlSessionFactory; import org.apache.ibatis.session.SqlSessionFactory;
import org.mybatis.spring.SqlSessionFactoryBean;
import org.mybatis.spring.SqlSessionTemplate; import org.mybatis.spring.SqlSessionTemplate;
import org.mybatis.spring.annotation.MapperScan; import org.mybatis.spring.annotation.MapperScan;
import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.beans.factory.annotation.Qualifier;
...@@ -17,6 +20,7 @@ import org.springframework.context.annotation.Configuration; ...@@ -17,6 +20,7 @@ import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary; import org.springframework.context.annotation.Primary;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver; import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.jdbc.datasource.DataSourceTransactionManager; import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import javax.sql.DataSource; import javax.sql.DataSource;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
...@@ -27,6 +31,12 @@ import java.util.Properties; ...@@ -27,6 +31,12 @@ import java.util.Properties;
@MapperScan(basePackages = {"com.zksy.szpt.mapper"}, sqlSessionTemplateRef = "sqlSessionTemplate") @MapperScan(basePackages = {"com.zksy.szpt.mapper"}, sqlSessionTemplateRef = "sqlSessionTemplate")
public class MybatisConfig { public class MybatisConfig {
private final SzptMetaObjectHandler szptMetaObjectHandler;
public MybatisConfig(SzptMetaObjectHandler szptMetaObjectHandler) {
this.szptMetaObjectHandler = szptMetaObjectHandler;
}
@Bean(name = "dataSource") @Bean(name = "dataSource")
@Primary @Primary
@ConfigurationProperties(prefix = "spring.datasource") @ConfigurationProperties(prefix = "spring.datasource")
...@@ -39,7 +49,12 @@ public class MybatisConfig { ...@@ -39,7 +49,12 @@ public class MybatisConfig {
@Primary @Primary
public SqlSessionFactory getSqlSessionFactory(@Qualifier("dataSource") DataSource datasource) public SqlSessionFactory getSqlSessionFactory(@Qualifier("dataSource") DataSource datasource)
throws Exception { throws Exception {
SqlSessionFactoryBean bean = new SqlSessionFactoryBean(); //自动填充设置
GlobalConfig globalConfig = GlobalConfigUtils.defaults();
globalConfig.setMetaObjectHandler(szptMetaObjectHandler);
MybatisSqlSessionFactoryBean bean = new MybatisSqlSessionFactoryBean();
bean.setGlobalConfig(globalConfig);
bean.setDataSource(datasource); bean.setDataSource(datasource);
MybatisConfiguration configuration = new MybatisConfiguration(); MybatisConfiguration configuration = new MybatisConfiguration();
configuration.setCallSettersOnNulls(true); configuration.setCallSettersOnNulls(true);
......
package com.zksy.szpt.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import springfox.documentation.builders.ApiInfoBuilder;
import springfox.documentation.builders.PathSelectors;
import springfox.documentation.builders.RequestHandlerSelectors;
import springfox.documentation.service.ApiInfo;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spring.web.plugins.Docket;
import springfox.documentation.swagger2.annotations.EnableSwagger2;
/**
* Created by wcy on 2023/5/14.
*/
@Configuration
@EnableSwagger2
public class SwaggerConfig {
ApiInfo apiInfo = new ApiInfoBuilder()
// .title("模块服务接口文档")
// .description("服务接口文档,遵循RESTful API设计规范")
// .contact(new Contact("wcy", "www.baidu.com", "4"))
// .version("1.0")
.build();
@Bean
public Docket createRestApi() {
return new Docket(DocumentationType.SWAGGER_2)
// .groupName("system")
.apiInfo(apiInfo)
.select()
//以扫描包的方式
.apis(RequestHandlerSelectors.basePackage("com.zksy.szpt.controller"))
.paths(PathSelectors.any())
.build();
}
}
package com.zksy.szpt.config; package com.zksy.szpt.config;
import com.zksy.szpt.filter.SignatureVerificationFilter;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import org.springframework.web.servlet.config.annotation.InterceptorRegistration; import org.springframework.web.servlet.config.annotation.InterceptorRegistration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry; import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import javax.annotation.Resource; import javax.annotation.Resource;
...@@ -10,6 +14,8 @@ import javax.annotation.Resource; ...@@ -10,6 +14,8 @@ import javax.annotation.Resource;
@Component @Component
public class WebConfig implements WebMvcConfigurer { public class WebConfig implements WebMvcConfigurer {
@Resource
SignatureVerificationFilter signatureVerificationFilter;
@Override @Override
public void addInterceptors(InterceptorRegistry registry) { public void addInterceptors(InterceptorRegistry registry) {
...@@ -28,4 +34,36 @@ public class WebConfig implements WebMvcConfigurer { ...@@ -28,4 +34,36 @@ public class WebConfig implements WebMvcConfigurer {
// interceptorRegistration.excludePathPatterns("/rest/user/loginByToken"); // interceptorRegistration.excludePathPatterns("/rest/user/loginByToken");
// registry.addInterceptor(logInterceptor).order(2); // registry.addInterceptor(logInterceptor).order(2);
} }
/**
* 静态资源配置
* @param registry
*/
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/favicon.ico", "/demo_upload.html", "/images/favicon-32x32.png", "/images/favicon-16x16.png", "/excel/newsList.xlsx")
.addResourceLocations("classpath:/static/");
// 解决 swagger-ui.html 404报错
registry.addResourceHandler("swagger-ui.html").addResourceLocations(
"classpath:/META-INF/resources/");
registry.addResourceHandler("/webjars/**").addResourceLocations(
"classpath:/META-INF/resources/webjars/");
}
/**
* 注册过滤器,这里注册的是自定义的签名验证过滤器,并且只会对/rest/*路径下的请求进行过滤
* @return
*/
@Bean
public FilterRegistrationBean getFilter1Registration() {
FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean();
filterRegistrationBean.setFilter(this.signatureVerificationFilter);
//设置过滤器名称和路径,在过滤器类写了的话,这里不用重复写
filterRegistrationBean.setName("filter");
filterRegistrationBean.addUrlPatterns("/rest/*");
//设置过滤器执行顺序,数字越小,越早进行过滤,也可设置为负数
filterRegistrationBean.setOrder(1);
return filterRegistrationBean;
}
} }
...@@ -2,20 +2,31 @@ package com.zksy.szpt.controller; ...@@ -2,20 +2,31 @@ package com.zksy.szpt.controller;
import com.zksy.szpt.domain.dto.AppStoreDTO; import com.zksy.szpt.domain.dto.AppStoreDTO;
import com.zksy.szpt.service.AppStoreService; import com.zksy.szpt.service.AppStoreService;
import io.swagger.annotations.Api;
import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController; import org.springframework.web.bind.annotation.RestController;
import javax.validation.Valid;
@Api(tags = "appKey管理")
@RequestMapping("/rest/appStore")
@RestController @RestController
public class InfSettingController { public class AppStoreController {
private final AppStoreService appStoreService; private final AppStoreService appStoreService;
public InfSettingController(AppStoreService infApiSettingService) { public AppStoreController(AppStoreService infApiSettingService) {
this.appStoreService = infApiSettingService; this.appStoreService = infApiSettingService;
} }
@PostMapping("/infSetting") @PostMapping("/getAppSecretByAppKey")
public Object infSetting(@RequestBody AppStoreDTO appStoreDTO) { public Object infSetting(@RequestBody AppStoreDTO appStoreDTO) {
return appStoreService.getAppSecretByAppKey("1"); return appStoreService.getAppSecretByAppKey("1");
} }
@PostMapping("/insertAppStore")
public Integer insertAppStore(@RequestBody @Valid AppStoreDTO appStoreDTO) {
return appStoreService.insertAppStore(appStoreDTO);
}
} }
...@@ -6,7 +6,6 @@ public class AppStoreDTO { ...@@ -6,7 +6,6 @@ public class AppStoreDTO {
private Long id; private Long id;
private String appKey; private String appKey;
private String appSecret; private String appSecret;
private String create_time;
public Long getId() { public Long getId() {
return id; return id;
...@@ -32,11 +31,4 @@ public class AppStoreDTO { ...@@ -32,11 +31,4 @@ public class AppStoreDTO {
this.appSecret = appSecret; this.appSecret = appSecret;
} }
public String getCreate_time() {
return create_time;
}
public void setCreate_time(String create_time) {
this.create_time = create_time;
}
} }
package com.zksy.szpt.domain.po; package com.zksy.szpt.domain.po;
import com.baomidou.mybatisplus.annotation.TableId; import com.baomidou.mybatisplus.annotation.*;
import com.baomidou.mybatisplus.annotation.TableName;
import java.util.Date;
@TableName("tb_app_store") @TableName("tb_app_store")
public class AppStore { public class AppStore {
@TableId @TableId(type = IdType.AUTO)
private Long id; private Long id;
//uuid, 唯一标识,雪花算法实现
@TableId(type = IdType.ASSIGN_ID)
private String appKey; private String appKey;
private String appSecret; private String appSecret;
private String create_time; @TableField(fill = FieldFill.INSERT)
private Date createTime;
public Long getId() { public Long getId() {
return id; return id;
...@@ -35,11 +39,11 @@ public class AppStore { ...@@ -35,11 +39,11 @@ public class AppStore {
this.appSecret = appSecret; this.appSecret = appSecret;
} }
public String getCreate_time() { public Date getCreateTime() {
return create_time; return createTime;
} }
public void setCreate_time(String create_time) { public void setCreateTime(Date createTime) {
this.create_time = create_time; this.createTime = createTime;
} }
} }
...@@ -3,9 +3,10 @@ package com.zksy.szpt.filter; ...@@ -3,9 +3,10 @@ package com.zksy.szpt.filter;
import cn.hutool.crypto.digest.DigestUtil; import cn.hutool.crypto.digest.DigestUtil;
import cn.hutool.json.JSONUtil; import cn.hutool.json.JSONUtil;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.zksy.szpt.domain.HttpResult; import com.zksy.szpt.domain.HttpResult;
import com.zksy.szpt.domain.HttpResultState; import com.zksy.szpt.domain.HttpResultState;
import com.zksy.szpt.service.AppStoreService;
import com.zksy.szpt.util.SignPayload;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import org.springframework.core.annotation.Order; import org.springframework.core.annotation.Order;
...@@ -16,7 +17,6 @@ import org.springframework.util.StreamUtils; ...@@ -16,7 +17,6 @@ import org.springframework.util.StreamUtils;
import org.springframework.util.StringUtils; import org.springframework.util.StringUtils;
import org.springframework.web.filter.OncePerRequestFilter; import org.springframework.web.filter.OncePerRequestFilter;
import javax.annotation.Resource;
import javax.servlet.FilterChain; import javax.servlet.FilterChain;
import javax.servlet.ServletException; import javax.servlet.ServletException;
import javax.servlet.annotation.WebFilter; import javax.servlet.annotation.WebFilter;
...@@ -24,20 +24,22 @@ import javax.servlet.http.HttpServletRequest; ...@@ -24,20 +24,22 @@ import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpServletResponse;
import java.io.IOException; import java.io.IOException;
import java.nio.charset.StandardCharsets; import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.Map; import java.util.Map;
import java.util.function.Function;
@Order(1)
@WebFilter(urlPatterns = "/**", filterName = "SignatureVerificationFilter")
@Component @Component
public class SignatureVerificationFilter extends OncePerRequestFilter { public class SignatureVerificationFilter extends OncePerRequestFilter {
public static Logger logger = LoggerFactory.getLogger(SignatureVerificationFilter.class); public Logger logger = LoggerFactory.getLogger(SignatureVerificationFilter.class);
private final ObjectMapper objectMapper; private static Map<String, Function<String, String>> workTypeMap = new HashMap<>();
public SignatureVerificationFilter(ObjectMapper objectMapper) { private final AppStoreService appStoreService;
this.objectMapper = objectMapper;
public SignatureVerificationFilter(AppStoreService appStoreService) {
this.appStoreService = appStoreService;
} }
@Override @Override
...@@ -50,10 +52,6 @@ public class SignatureVerificationFilter extends OncePerRequestFilter { ...@@ -50,10 +52,6 @@ public class SignatureVerificationFilter extends OncePerRequestFilter {
} }
} }
// 签名秘钥
private String secretKey = "2";
/** /**
* 校验签名 * 校验签名
* *
...@@ -64,19 +62,23 @@ public class SignatureVerificationFilter extends OncePerRequestFilter { ...@@ -64,19 +62,23 @@ public class SignatureVerificationFilter extends OncePerRequestFilter {
*/ */
public boolean verifySignature(HttpServletRequest request, HttpServletResponse response) throws IOException { public boolean verifySignature(HttpServletRequest request, HttpServletResponse response) throws IOException {
// 签名 // 签名
String appId = request.getHeader("appId"); String appId = request.getHeader(SignPayload.appid);
// 签名 // 签名
String sign = request.getHeader("signature"); String sign = request.getHeader(SignPayload.sign);
// 随机数 // 随机数
String nonce = request.getHeader("nonce"); String nonce = request.getHeader(SignPayload.nonce);
// 时间戳 // 时间戳
String timestampStr = request.getHeader("timestamp"); String timestampStr = request.getHeader(SignPayload.timestamp);
if (!StringUtils.hasText(sign) || !StringUtils.hasText(nonce) || !StringUtils.hasText(timestampStr)) {
this.write(response, "参数错误"); if (!StringUtils.hasText(appId) || !StringUtils.hasText(sign) || !StringUtils.hasText(nonce) || !StringUtils.hasText(timestampStr)) {
logger.error("缺少参数appId{},sign{},nonce{},timestampStr{}", appId, sign, nonce, timestampStr);
this.write(response, "缺少参数");
return false; return false;
} }
String secretKey = this.appStoreService.getAppSecretByAppKey(appId);
// timestamp 10分钟内有效 // timestamp 10分钟内有效
// long timestamp = Long.parseLong(timestampStr); // long timestamp = Long.parseLong(timestampStr);
// long currentTimestamp = System.currentTimeMillis() / 1000; // long currentTimestamp = System.currentTimeMillis() / 1000;
...@@ -93,11 +95,12 @@ public class SignatureVerificationFilter extends OncePerRequestFilter { ...@@ -93,11 +95,12 @@ public class SignatureVerificationFilter extends OncePerRequestFilter {
// } // }
// 请求体 // 请求体
String body = objectMapper.writeValueAsString(objectMapper.readValue(StreamUtils.copyToString(request.getInputStream(), StandardCharsets.UTF_8), Map.class)); String body = StreamUtils.copyToString(request.getInputStream(), StandardCharsets.UTF_8);
// 需要签名的数据:secretKey+noce+timestampStr+body // 需要签名的数据:appId+nonce+timestampStr+body+secretKey
// 校验签名 // 校验签名
String data = String.format("%s%s%s%s%s", appId, nonce, timestampStr, body, this.secretKey); String data = String.format("%s%s%s%s%s", appId, nonce, timestampStr, body, secretKey);
if (!DigestUtil.md5Hex(data).equals(sign)) { String generatedSignature = DigestUtil.md5Hex(data);
if (!generatedSignature.equals(sign)) {
write(response, "签名有误"); write(response, "签名有误");
return false; return false;
} }
......
package com.zksy.szpt.handler;
import com.baomidou.mybatisplus.core.handlers.MetaObjectHandler;
import org.apache.ibatis.reflection.MetaObject;
import org.springframework.stereotype.Component;
import java.util.Date;
/**
* 自动填充 create_time, update_time 字段
*/
@Component
public class SzptMetaObjectHandler implements MetaObjectHandler {
@Override
public void insertFill(MetaObject metaObject) {
// 新增时自动填充 create_time, update_time 字段
this.strictInsertFill(metaObject, "createTime", Date.class, new Date());
}
@Override
public void updateFill(MetaObject metaObject) {
this.strictInsertFill(metaObject, "updateTime", Date.class, new Date());
}
}
package com.zksy.szpt.service; package com.zksy.szpt.service;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.zksy.szpt.domain.dto.AppStoreDTO;
import com.zksy.szpt.domain.po.AppStore; import com.zksy.szpt.domain.po.AppStore;
import com.zksy.szpt.mapper.AppStoreMapper; import com.zksy.szpt.mapper.AppStoreMapper;
import com.zksy.szpt.util.BeanMapperUtil;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import java.util.List; import java.util.List;
...@@ -24,4 +26,9 @@ public class AppStoreService { ...@@ -24,4 +26,9 @@ public class AppStoreService {
} }
return null; return null;
} }
public Integer insertAppStore(AppStoreDTO appStoreDTO) {
AppStore appStore = BeanMapperUtil.map(appStoreDTO, AppStore.class);
return appStoreMapper.insert(appStore);
}
} }
package com.zksy.szpt.util;
import ma.glasnost.orika.MapperFactory;
import ma.glasnost.orika.impl.DefaultMapperFactory;
import java.util.Collection;
import java.util.List;
public class BeanMapperUtil {
private static MapperFactory MAPPER_FACTORY = new DefaultMapperFactory.Builder().build();
public static <E, T> E map(T source, Class<E> destinationClass) {
if (source == null) {
return null;
}
return MAPPER_FACTORY.getMapperFacade().map(source, destinationClass);
}
public static <E, T> List<E> mapList(Collection<T> sourceList, Class<E> destinationClass) {
return MAPPER_FACTORY.getMapperFacade().mapAsList(sourceList, destinationClass);
}
}
\ No newline at end of file
package com.zksy.szpt.util;
public class SignPayload {
public static String sign = "x-szpt-sign";
public static String timestamp = "x-szpt-timestamp";
public static String nonce = "x-szpt-nonce";
public static String appid = "x-szpt-appid";
}
package com.zksy.szpt.util;
import cn.hutool.crypto.digest.DigestUtil;
import org.springframework.util.StringUtils;
import java.util.UUID;
public class SignatureUtil {
/**
* 生成签名
*
* @param body 请求体
* @param secretKey 密钥
* @param nonce 随机数
* @param timestamp 时间戳
* @return 签名
*/
public static String generateSignature(String body, String secretKey, String nonce, String timestamp) {
if (!StringUtils.hasText(body) || !StringUtils.hasText(secretKey) || !StringUtils.hasText(nonce) || !StringUtils.hasText(timestamp)) {
throw new IllegalArgumentException("参数不能为空");
}
// 按照 secretKey + nonce + timestamp + body 的顺序拼接字符串
String data = String.format("%s%s%s%s", secretKey, nonce, timestamp, body);
System.out.println("data = " + data);
// 使用MD5算法计算签名
String sign = DigestUtil.md5Hex(data);
return sign;
}
public static void main(String[] args) {
// 示例参数
String body = "{\n" +
" \"fromAccountId\": \"张三\",\n" +
" \"toAccountId\": \"李四\",\n" +
" \"transferPrice\": 100\n" +
"}";
//秘钥
String secretKey = "b0e8668b-bcf2-4d73-abd4-893bbc1c6079";
// 随机数
String nonce = UUID.randomUUID().toString().replace("-", "");
// 时间戳
long timestamp = System.currentTimeMillis() / 1000;
// 生成签名
String sign = generateSignature(body, secretKey, nonce, String.valueOf(timestamp));
// 输出生成的签名
System.out.println("X-Sign: " + sign);
System.out.println("X-Nonce: " + nonce);
System.out.println("X-Timestamp: " + timestamp);
}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment