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

2

parent cbaf93de
......@@ -103,6 +103,24 @@
<artifactId>hutool-all</artifactId>
<version>5.8.2</version>
</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>
<build>
......
......@@ -13,7 +13,6 @@ import org.springframework.boot.web.servlet.ServletComponentScan;
DataSourceAutoConfiguration.class,
DataSourceTransactionManagerAutoConfiguration.class,
})
@ServletComponentScan
public class Main {
public static void main(String[] args) {
SpringApplication.run(Main.class, args);
......
......@@ -20,8 +20,8 @@ import org.springframework.web.context.request.ServletRequestAttributes;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
@Aspect//声明切面,标记类(1时间,2地点,3内容)
@Component
//@Aspect//声明切面,标记类(1时间,2地点,3内容)
//@Component
public class SignatureAspect {
private static final Logger logger = LoggerFactory.getLogger(AuthAspect.class);
......
......@@ -3,10 +3,13 @@ package com.zksy.szpt.config;
import com.alibaba.druid.pool.DruidDataSource;
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.zksy.szpt.handler.SzptMetaObjectHandler;
import org.apache.ibatis.plugin.Interceptor;
import org.apache.ibatis.session.SqlSessionFactory;
import org.mybatis.spring.SqlSessionFactoryBean;
import org.mybatis.spring.SqlSessionTemplate;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.beans.factory.annotation.Qualifier;
......@@ -17,6 +20,7 @@ import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import javax.sql.DataSource;
import java.util.ArrayList;
import java.util.Arrays;
......@@ -27,6 +31,12 @@ import java.util.Properties;
@MapperScan(basePackages = {"com.zksy.szpt.mapper"}, sqlSessionTemplateRef = "sqlSessionTemplate")
public class MybatisConfig {
private final SzptMetaObjectHandler szptMetaObjectHandler;
public MybatisConfig(SzptMetaObjectHandler szptMetaObjectHandler) {
this.szptMetaObjectHandler = szptMetaObjectHandler;
}
@Bean(name = "dataSource")
@Primary
@ConfigurationProperties(prefix = "spring.datasource")
......@@ -39,7 +49,12 @@ public class MybatisConfig {
@Primary
public SqlSessionFactory getSqlSessionFactory(@Qualifier("dataSource") DataSource datasource)
throws Exception {
SqlSessionFactoryBean bean = new SqlSessionFactoryBean();
//自动填充设置
GlobalConfig globalConfig = GlobalConfigUtils.defaults();
globalConfig.setMetaObjectHandler(szptMetaObjectHandler);
MybatisSqlSessionFactoryBean bean = new MybatisSqlSessionFactoryBean();
bean.setGlobalConfig(globalConfig);
bean.setDataSource(datasource);
MybatisConfiguration configuration = new MybatisConfiguration();
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;
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.web.servlet.config.annotation.InterceptorRegistration;
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 javax.annotation.Resource;
......@@ -10,6 +14,8 @@ import javax.annotation.Resource;
@Component
public class WebConfig implements WebMvcConfigurer {
@Resource
SignatureVerificationFilter signatureVerificationFilter;
@Override
public void addInterceptors(InterceptorRegistry registry) {
......@@ -28,4 +34,36 @@ public class WebConfig implements WebMvcConfigurer {
// interceptorRegistration.excludePathPatterns("/rest/user/loginByToken");
// 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;
import com.zksy.szpt.domain.dto.AppStoreDTO;
import com.zksy.szpt.service.AppStoreService;
import io.swagger.annotations.Api;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.validation.Valid;
@Api(tags = "appKey管理")
@RequestMapping("/rest/appStore")
@RestController
public class InfSettingController {
public class AppStoreController {
private final AppStoreService appStoreService;
public InfSettingController(AppStoreService infApiSettingService) {
public AppStoreController(AppStoreService infApiSettingService) {
this.appStoreService = infApiSettingService;
}
@PostMapping("/infSetting")
@PostMapping("/getAppSecretByAppKey")
public Object infSetting(@RequestBody AppStoreDTO appStoreDTO) {
return appStoreService.getAppSecretByAppKey("1");
}
@PostMapping("/insertAppStore")
public Integer insertAppStore(@RequestBody @Valid AppStoreDTO appStoreDTO) {
return appStoreService.insertAppStore(appStoreDTO);
}
}
......@@ -6,7 +6,6 @@ public class AppStoreDTO {
private Long id;
private String appKey;
private String appSecret;
private String create_time;
public Long getId() {
return id;
......@@ -32,11 +31,4 @@ public class AppStoreDTO {
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;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import com.baomidou.mybatisplus.annotation.*;
import java.util.Date;
@TableName("tb_app_store")
public class AppStore {
@TableId
@TableId(type = IdType.AUTO)
private Long id;
//uuid, 唯一标识,雪花算法实现
@TableId(type = IdType.ASSIGN_ID)
private String appKey;
private String appSecret;
private String create_time;
@TableField(fill = FieldFill.INSERT)
private Date createTime;
public Long getId() {
return id;
......@@ -35,11 +39,11 @@ public class AppStore {
this.appSecret = appSecret;
}
public String getCreate_time() {
return create_time;
public Date getCreateTime() {
return createTime;
}
public void setCreate_time(String create_time) {
this.create_time = create_time;
public void setCreateTime(Date createTime) {
this.createTime = createTime;
}
}
......@@ -3,9 +3,10 @@ package com.zksy.szpt.filter;
import cn.hutool.crypto.digest.DigestUtil;
import cn.hutool.json.JSONUtil;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.zksy.szpt.domain.HttpResult;
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.LoggerFactory;
import org.springframework.core.annotation.Order;
......@@ -16,7 +17,6 @@ import org.springframework.util.StreamUtils;
import org.springframework.util.StringUtils;
import org.springframework.web.filter.OncePerRequestFilter;
import javax.annotation.Resource;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebFilter;
......@@ -24,20 +24,22 @@ import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.Map;
import java.util.function.Function;
@Order(1)
@WebFilter(urlPatterns = "/**", filterName = "SignatureVerificationFilter")
@Component
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) {
this.objectMapper = objectMapper;
private final AppStoreService appStoreService;
public SignatureVerificationFilter(AppStoreService appStoreService) {
this.appStoreService = appStoreService;
}
@Override
......@@ -50,10 +52,6 @@ public class SignatureVerificationFilter extends OncePerRequestFilter {
}
}
// 签名秘钥
private String secretKey = "2";
/**
* 校验签名
*
......@@ -64,19 +62,23 @@ public class SignatureVerificationFilter extends OncePerRequestFilter {
*/
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;
}
String secretKey = this.appStoreService.getAppSecretByAppKey(appId);
// timestamp 10分钟内有效
// long timestamp = Long.parseLong(timestampStr);
// long currentTimestamp = System.currentTimeMillis() / 1000;
......@@ -93,11 +95,12 @@ public class SignatureVerificationFilter extends OncePerRequestFilter {
// }
// 请求体
String body = objectMapper.writeValueAsString(objectMapper.readValue(StreamUtils.copyToString(request.getInputStream(), StandardCharsets.UTF_8), Map.class));
// 需要签名的数据:secretKey+noce+timestampStr+body
String body = StreamUtils.copyToString(request.getInputStream(), StandardCharsets.UTF_8);
// 需要签名的数据:appId+nonce+timestampStr+body+secretKey
// 校验签名
String data = String.format("%s%s%s%s%s", appId, nonce, timestampStr, body, this.secretKey);
if (!DigestUtil.md5Hex(data).equals(sign)) {
String data = String.format("%s%s%s%s%s", appId, nonce, timestampStr, body, secretKey);
String generatedSignature = DigestUtil.md5Hex(data);
if (!generatedSignature.equals(sign)) {
write(response, "签名有误");
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;
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.mapper.AppStoreMapper;
import com.zksy.szpt.util.BeanMapperUtil;
import org.springframework.stereotype.Service;
import java.util.List;
......@@ -24,4 +26,9 @@ public class AppStoreService {
}
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