Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
S
szpt
Project overview
Project overview
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
以墨为白
szpt
Commits
5bea093f
Commit
5bea093f
authored
Jan 10, 2025
by
以墨为白
🎧
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
优化
parent
744dd937
Changes
9
Show whitespace changes
Inline
Side-by-side
Showing
9 changed files
with
560 additions
and
6 deletions
+560
-6
src/main/java/com/zksy/szpt/config/WebConfig.java
src/main/java/com/zksy/szpt/config/WebConfig.java
+16
-3
src/main/java/com/zksy/szpt/domain/CommonRequestDTO.java
src/main/java/com/zksy/szpt/domain/CommonRequestDTO.java
+58
-0
src/main/java/com/zksy/szpt/filter/ReusableBodyRequestWrapper1.java
...ava/com/zksy/szpt/filter/ReusableBodyRequestWrapper1.java
+87
-0
src/main/java/com/zksy/szpt/filter/SignatureVerificationFilter.java
...ava/com/zksy/szpt/filter/SignatureVerificationFilter.java
+3
-0
src/main/java/com/zksy/szpt/filter/SignatureVerificationFilter1.java
...va/com/zksy/szpt/filter/SignatureVerificationFilter1.java
+183
-0
src/main/java/com/zksy/szpt/filter/SignatureVerificationFilter2.java
...va/com/zksy/szpt/filter/SignatureVerificationFilter2.java
+156
-0
src/main/java/com/zksy/szpt/util/EncryptUtil.java
src/main/java/com/zksy/szpt/util/EncryptUtil.java
+1
-1
src/test/java/com/zksy/szpt/CommonUtil.java
src/test/java/com/zksy/szpt/CommonUtil.java
+4
-0
src/test/java/com/zksy/szpt/TestAppStore.java
src/test/java/com/zksy/szpt/TestAppStore.java
+52
-2
No files found.
src/main/java/com/zksy/szpt/config/WebConfig.java
View file @
5bea093f
package
com
.
zksy
.
szpt
.
config
;
import
com.zksy.szpt.filter.SignatureVerificationFilter
;
import
com.zksy.szpt.filter.SignatureVerificationFilter1
;
import
org.springframework.beans.factory.annotation.Qualifier
;
import
org.springframework.boot.autoconfigure.condition.ConditionalOnBean
;
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
;
@Component
public
class
WebConfig
implements
WebMvcConfigurer
{
...
...
@@ -55,6 +54,7 @@ public class WebConfig implements WebMvcConfigurer {
* @return
*/
@Bean
@ConditionalOnBean
(
name
=
"signatureVerificationFilter"
)
public
FilterRegistrationBean
getFilter1Registration
(
@Qualifier
(
"signatureVerificationFilter"
)
SignatureVerificationFilter
signatureVerificationFilter
)
{
FilterRegistrationBean
filterRegistrationBean
=
new
FilterRegistrationBean
();
filterRegistrationBean
.
setFilter
(
signatureVerificationFilter
);
...
...
@@ -66,4 +66,17 @@ public class WebConfig implements WebMvcConfigurer {
return
filterRegistrationBean
;
}
@Bean
@ConditionalOnBean
(
name
=
"signatureVerificationFilter1"
)
public
FilterRegistrationBean
getFilter1Registration
(
@Qualifier
(
"signatureVerificationFilter1"
)
SignatureVerificationFilter1
signatureVerificationFilter
)
{
FilterRegistrationBean
filterRegistrationBean
=
new
FilterRegistrationBean
();
filterRegistrationBean
.
setFilter
(
signatureVerificationFilter
);
//设置过滤器名称和路径,在过滤器类写了的话,这里不用重复写
filterRegistrationBean
.
setName
(
"filter"
);
filterRegistrationBean
.
addUrlPatterns
(
"/rest/*"
);
//设置过滤器执行顺序,数字越小,越早进行过滤,也可设置为负数
filterRegistrationBean
.
setOrder
(
1
);
return
filterRegistrationBean
;
}
}
src/main/java/com/zksy/szpt/domain/CommonRequestDTO.java
0 → 100644
View file @
5bea093f
package
com
.
zksy
.
szpt
.
domain
;
public
class
CommonRequestDTO
{
private
String
deptCode
;
private
String
content
;
private
String
appId
;
private
String
nonce
;
private
String
timestamp
;
private
String
sign
;
public
String
getSign
()
{
return
sign
;
}
public
void
setSign
(
String
sign
)
{
this
.
sign
=
sign
;
}
public
String
getAppId
()
{
return
appId
;
}
public
void
setAppId
(
String
appId
)
{
this
.
appId
=
appId
;
}
public
String
getNonce
()
{
return
nonce
;
}
public
void
setNonce
(
String
nonce
)
{
this
.
nonce
=
nonce
;
}
public
String
getTimestamp
()
{
return
timestamp
;
}
public
void
setTimestamp
(
String
timestamp
)
{
this
.
timestamp
=
timestamp
;
}
public
String
getDeptCode
()
{
return
deptCode
;
}
public
void
setDeptCode
(
String
deptCode
)
{
this
.
deptCode
=
deptCode
;
}
public
String
getContent
()
{
return
content
;
}
public
void
setContent
(
String
content
)
{
this
.
content
=
content
;
}
}
src/main/java/com/zksy/szpt/filter/ReusableBodyRequestWrapper1.java
0 → 100644
View file @
5bea093f
package
com
.
zksy
.
szpt
.
filter
;
import
javax.servlet.ReadListener
;
import
javax.servlet.ServletInputStream
;
import
javax.servlet.http.HttpServletRequest
;
import
javax.servlet.http.HttpServletRequestWrapper
;
import
java.io.*
;
import
java.nio.charset.StandardCharsets
;
/**
* 该类用于包装HttpServletRequest,以便在读取请求体后仍可重复读取
*/
public
class
ReusableBodyRequestWrapper1
extends
HttpServletRequestWrapper
{
//参数字节数组,用于存储请求体的字节数据
private
byte
[]
requestBody
;
/**
* 构造函数,初始化包装类
* @param request 原始HttpServletRequest对象
* @throws IOException 如果读取请求体时发生IO错误
*/
public
ReusableBodyRequestWrapper1
(
HttpServletRequest
request
,
String
body
)
throws
IOException
{
super
(
request
);
this
.
requestBody
=
body
.
getBytes
(
StandardCharsets
.
UTF_8
);
}
// 构造方法:从请求中读取 body 并缓存
public
ReusableBodyRequestWrapper1
(
HttpServletRequest
request
)
throws
IOException
{
super
(
request
);
this
.
requestBody
=
request
.
getReader
().
lines
()
.
reduce
(
""
,
(
accumulator
,
actual
)
->
accumulator
+
actual
)
.
getBytes
(
StandardCharsets
.
UTF_8
);
}
/**
* 重写getInputStream方法,实现请求体的重复读取
* @return 包含请求体数据的ServletInputStream对象
* @throws IOException 如果读取请求体时发生IO错误
*/
@Override
public
ServletInputStream
getInputStream
()
throws
IOException
{
//创建一个 ByteArrayInputStream 对象,用于重复读取requestBody
final
ByteArrayInputStream
bais
=
new
ByteArrayInputStream
(
requestBody
);
return
new
ServletInputStream
()
{
@Override
public
boolean
isFinished
()
{
//始终返回false,表示数据流未完成
return
false
;
}
@Override
public
boolean
isReady
()
{
//始终返回false,表示数据流未准备好
return
false
;
}
@Override
public
void
setReadListener
(
ReadListener
listener
)
{
//不执行任何操作,因为该数据流不支持异步操作
}
@Override
public
int
read
()
{
//从ByteArrayInputStream中读取数据
return
bais
.
read
();
}
};
}
/**
* 重写getReader方法,返回一个基于getInputStream的BufferedReader
* @return 包含请求体数据的BufferedReader对象
* @throws IOException 如果读取请求体时发生IO错误
*/
@Override
public
BufferedReader
getReader
()
throws
IOException
{
//基于getInputStream创建BufferedReader
return
new
BufferedReader
(
new
InputStreamReader
(
this
.
getInputStream
()));
}
// 获取请求体的字符串
public
String
getBody
()
{
return
new
String
(
requestBody
,
StandardCharsets
.
UTF_8
);
}
}
\ No newline at end of file
src/main/java/com/zksy/szpt/filter/SignatureVerificationFilter.java
View file @
5bea093f
...
...
@@ -33,6 +33,9 @@ import java.nio.charset.StandardCharsets;
import
java.util.Map
;
import
java.util.concurrent.TimeUnit
;
/**
* body {单位, 房间, 人员信息数组} 请求头加nonce timestamp appId sign(body[遍历按照key按照顺序&拼接] 加 nonece timestamp appId 用$符号拼接)
*/
@Component
public
class
SignatureVerificationFilter
extends
OncePerRequestFilter
{
...
...
src/main/java/com/zksy/szpt/filter/SignatureVerificationFilter1.java
0 → 100644
View file @
5bea093f
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.CommonRequestDTO
;
import
com.zksy.szpt.domain.CurrentUserInfo
;
import
com.zksy.szpt.domain.HttpResult
;
import
com.zksy.szpt.domain.HttpResultState
;
import
com.zksy.szpt.domain.po.AppStore
;
import
com.zksy.szpt.service.AppStoreService
;
import
com.zksy.szpt.util.EncryptUtil
;
import
com.zksy.szpt.util.RedisKeyValidator
;
import
com.zksy.szpt.util.SignatureUtil
;
import
com.zksy.szpt.util.UserContextHolder
;
import
org.slf4j.Logger
;
import
org.slf4j.LoggerFactory
;
import
org.springframework.data.redis.core.RedisTemplate
;
import
org.springframework.http.MediaType
;
import
org.springframework.stereotype.Component
;
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.http.HttpServletRequest
;
import
javax.servlet.http.HttpServletResponse
;
import
java.io.BufferedReader
;
import
java.io.IOException
;
import
java.nio.charset.StandardCharsets
;
import
java.util.HashMap
;
import
java.util.Map
;
import
java.util.concurrent.TimeUnit
;
import
java.util.stream.Collectors
;
/**
* 请求body { appkey , method , hotelCode , content(根据密钥[md5]对dto的json加密aes), sign(前面的参数一起哈希运算)} 。 无其他参数
* 数据获取到json解密后转发到对应的controller
*/
//@Component(value = "signatureVerificationFilter1")
public
class
SignatureVerificationFilter1
extends
OncePerRequestFilter
{
public
Logger
logger
=
LoggerFactory
.
getLogger
(
SignatureVerificationFilter1
.
class
);
@Resource
ObjectMapper
objectMapper
;
AppStore
appStore
;
@Resource
private
RedisTemplate
<
String
,
Object
>
redisTemplate
;
private
final
AppStoreService
appStoreService
;
public
SignatureVerificationFilter1
(
AppStoreService
appStoreService
)
{
this
.
appStoreService
=
appStoreService
;
}
@Override
protected
void
doFilterInternal
(
HttpServletRequest
request
,
HttpServletResponse
response
,
FilterChain
filterChain
)
throws
ServletException
,
IOException
{
// 对request进行包装,支持重复读取body
ReusableBodyRequestWrapper1
requestWrapper
=
new
ReusableBodyRequestWrapper1
(
request
);
String
body
=
requestWrapper
.
getBody
();
String
result
=
this
.
verifySignature
(
body
);
// 校验签名
if
(
result
!=
null
)
{
this
.
write
(
response
,
result
);
}
else
{
CommonRequestDTO
commonRequestDTO
=
objectMapper
.
readValue
(
body
,
CommonRequestDTO
.
class
);
String
content
=
EncryptUtil
.
getInstance
().
AESDecode
(
commonRequestDTO
.
getContent
(),
appStore
.
getAppSecret
());
ReusableBodyRequestWrapper1
requestWrapper1
=
new
ReusableBodyRequestWrapper1
(
request
,
content
);
addUserInfo
(
requestWrapper1
);
filterChain
.
doFilter
(
requestWrapper1
,
response
);
}
}
/**
* 校验签名
*
* @return 签名验证结果
* @throws IOException 如果读取请求体失败
*/
public
String
verifySignature
(
String
body
)
throws
IOException
{
// post请求body
CommonRequestDTO
commonRequestDTO
=
objectMapper
.
readValue
(
body
,
CommonRequestDTO
.
class
);
// 签名
String
appId
=
commonRequestDTO
.
getAppId
();
// 签名
String
sign
=
commonRequestDTO
.
getSign
();
// 随机数
String
nonce
=
commonRequestDTO
.
getNonce
();
// 时间戳
String
timestampStr
=
commonRequestDTO
.
getTimestamp
();
String
deptCode
=
commonRequestDTO
.
getDeptCode
();
if
(!
StringUtils
.
hasText
(
appId
)
||
!
StringUtils
.
hasText
(
sign
)
||
!
StringUtils
.
hasText
(
nonce
)
||
!
StringUtils
.
hasText
(
timestampStr
))
{
logger
.
warn
(
"缺少参数appId:{},sign:{},nonce{},timestampStr:{}"
,
appId
,
sign
,
nonce
,
timestampStr
);
return
"请求缺少参数,appId:"
+
appId
+
",sign:"
+
sign
+
",nonce:"
+
nonce
+
",timestamp:"
+
timestampStr
;
}
// 验证nonce和timestamp合法性
if
(!
RedisKeyValidator
.
isValidString
(
nonce
))
{
return
"不是合法的由数字和字母以及下划线组成的nonce:"
+
nonce
;
}
if
(!
RedisKeyValidator
.
isValidTimestamp
(
timestampStr
))
{
return
"不是合法的十位秒级时间戳timestamp:"
+
timestampStr
;
}
// timestamp 10分钟内有效
long
timestamp
=
Long
.
parseLong
(
timestampStr
);
long
currentTimestamp
=
System
.
currentTimeMillis
()
/
1000
;
if
(
Math
.
abs
(
currentTimestamp
-
timestamp
)
>
600
)
{
return
"请求已过期"
;
}
// 防止请求重放,nonce只能用一次,放在redis中,有效期 20分钟
String
nonceKey
=
"api_signature:nonce:"
+
nonce
;
if
(
Boolean
.
FALSE
.
equals
(
this
.
redisTemplate
.
opsForValue
().
setIfAbsent
(
nonceKey
,
"1"
,
20
,
TimeUnit
.
MINUTES
)))
{
return
"nonce无效:"
+
nonce
;
}
// 校验appId
appStore
=
this
.
appStoreService
.
getAppSecretInfo
(
appId
);
String
appSecret
=
appStore
.
getAppSecret
();
if
(!
StringUtils
.
hasText
(
appSecret
))
{
return
"appId无效:"
+
appId
;
}
//验证单位
if
(
deptCode
!=
null
&&
!
deptCode
.
startsWith
(
appStore
.
getDeptCode
().
replaceAll
(
"0+$"
,
""
)))
{
return
"AppId和传入的单位不匹配,appId:"
+
appId
+
",deptCode:"
+
deptCode
;
}
String
data
=
String
.
format
(
"%s%s%s%s%s"
,
appId
,
nonce
,
timestampStr
,
commonRequestDTO
.
getContent
(),
deptCode
);
String
generatedSignature
=
DigestUtil
.
md5Hex
(
data
);
if
(!
generatedSignature
.
equals
(
sign
))
{
logger
.
warn
(
"签名有误,generatedSignature:{},sign:{},appId:{},nonce:{},timestampStr:{},deptCode:{}"
,
generatedSignature
,
sign
,
appId
,
nonce
,
timestampStr
,
deptCode
);
return
"签名有误,sign: "
+
sign
+
",appId:"
+
appId
+
",nonce:"
+
nonce
+
",timestamp:"
+
timestampStr
+
",deptCode:"
+
deptCode
;
}
// 签名验证通过
return
null
;
}
/**
* 向客户端写入响应信息
*
* @param response HTTP响应
* @param msg 响应信息
* @throws IOException 如果写入失败
*/
private
void
write
(
HttpServletResponse
response
,
String
msg
)
throws
IOException
{
HttpResultState
httpResultState
=
HttpResultState
.
INVALID_SIGNATURE
;
httpResultState
.
setMessage
(
msg
);
HttpResult
<
String
>
httpResult
=
new
HttpResult
<>(
httpResultState
);
response
.
setContentType
(
MediaType
.
APPLICATION_JSON_VALUE
);
response
.
setCharacterEncoding
(
StandardCharsets
.
UTF_8
.
name
());
response
.
getWriter
().
write
(
JSONUtil
.
toJsonStr
(
httpResult
));
}
/**
* 增加用户信息
*
* @param request
*/
private
void
addUserInfo
(
HttpServletRequest
request
)
{
// 增加用户信息
String
userId
=
request
.
getHeader
(
SignatureUtil
.
APPID
);
String
ip
=
request
.
getRemoteAddr
();
CurrentUserInfo
currentUserInfo
=
new
CurrentUserInfo
.
CurrentUserInfoBuilder
().
userId
(
userId
).
userName
(
userId
).
ip
(
ip
).
build
();
UserContextHolder
.
set
(
currentUserInfo
);
}
private
String
getRequestBody
(
HttpServletRequest
request
)
throws
IOException
{
try
(
BufferedReader
reader
=
request
.
getReader
())
{
return
reader
.
lines
().
collect
(
Collectors
.
joining
(
System
.
lineSeparator
()));
}
}
}
src/main/java/com/zksy/szpt/filter/SignatureVerificationFilter2.java
0 → 100644
View file @
5bea093f
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.CommonRequestDTO
;
import
com.zksy.szpt.domain.CurrentUserInfo
;
import
com.zksy.szpt.domain.HttpResult
;
import
com.zksy.szpt.domain.HttpResultState
;
import
com.zksy.szpt.domain.po.AppStore
;
import
com.zksy.szpt.service.AppStoreService
;
import
com.zksy.szpt.util.EncryptUtil
;
import
com.zksy.szpt.util.RedisKeyValidator
;
import
com.zksy.szpt.util.SignatureUtil
;
import
com.zksy.szpt.util.UserContextHolder
;
import
org.slf4j.Logger
;
import
org.slf4j.LoggerFactory
;
import
org.springframework.data.redis.core.RedisTemplate
;
import
org.springframework.http.MediaType
;
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.http.HttpServletRequest
;
import
javax.servlet.http.HttpServletResponse
;
import
java.io.BufferedReader
;
import
java.io.IOException
;
import
java.nio.charset.StandardCharsets
;
import
java.util.concurrent.TimeUnit
;
import
java.util.stream.Collectors
;
/**
* 请求body { appkey , method , hotelCode , content(根据密钥[md5]对dto的json加密aes), sign(前面的参数一起哈希运算)} 。 无其他参数
* 请求数据直接转发到后端服务
*/
//@Component(value = "signatureVerificationFilter1")
public
class
SignatureVerificationFilter2
extends
OncePerRequestFilter
{
public
Logger
logger
=
LoggerFactory
.
getLogger
(
SignatureVerificationFilter2
.
class
);
@Resource
ObjectMapper
objectMapper
;
AppStore
appStore
;
@Resource
private
RedisTemplate
<
String
,
Object
>
redisTemplate
;
private
final
AppStoreService
appStoreService
;
public
SignatureVerificationFilter2
(
AppStoreService
appStoreService
)
{
this
.
appStoreService
=
appStoreService
;
}
@Override
protected
void
doFilterInternal
(
HttpServletRequest
request
,
HttpServletResponse
response
,
FilterChain
filterChain
)
throws
ServletException
,
IOException
{
// 对request进行包装,支持重复读取body
ReusableBodyRequestWrapper1
requestWrapper
=
new
ReusableBodyRequestWrapper1
(
request
);
String
body
=
requestWrapper
.
getBody
();
String
result
=
this
.
verifySignature
(
body
);
// 校验签名
if
(
result
!=
null
)
{
this
.
write
(
response
,
result
);
}
else
{
filterChain
.
doFilter
(
requestWrapper
,
response
);
}
}
/**
* 校验签名
*
* @return 签名验证结果
* @throws IOException 如果读取请求体失败
*/
public
String
verifySignature
(
String
body
)
throws
IOException
{
// post请求body
CommonRequestDTO
commonRequestDTO
=
objectMapper
.
readValue
(
body
,
CommonRequestDTO
.
class
);
// 签名
String
appId
=
commonRequestDTO
.
getAppId
();
// 签名
String
sign
=
commonRequestDTO
.
getSign
();
// 随机数
String
nonce
=
commonRequestDTO
.
getNonce
();
// 时间戳
String
timestampStr
=
commonRequestDTO
.
getTimestamp
();
String
deptCode
=
commonRequestDTO
.
getDeptCode
();
if
(!
StringUtils
.
hasText
(
appId
)
||
!
StringUtils
.
hasText
(
sign
)
||
!
StringUtils
.
hasText
(
nonce
)
||
!
StringUtils
.
hasText
(
timestampStr
))
{
logger
.
warn
(
"缺少参数appId:{},sign:{},nonce{},timestampStr:{}"
,
appId
,
sign
,
nonce
,
timestampStr
);
return
"请求缺少参数,appId:"
+
appId
+
",sign:"
+
sign
+
",nonce:"
+
nonce
+
",timestamp:"
+
timestampStr
;
}
// 验证nonce和timestamp合法性
if
(!
RedisKeyValidator
.
isValidString
(
nonce
))
{
return
"不是合法的由数字和字母以及下划线组成的nonce:"
+
nonce
;
}
if
(!
RedisKeyValidator
.
isValidTimestamp
(
timestampStr
))
{
return
"不是合法的十位秒级时间戳timestamp:"
+
timestampStr
;
}
// timestamp 10分钟内有效
long
timestamp
=
Long
.
parseLong
(
timestampStr
);
long
currentTimestamp
=
System
.
currentTimeMillis
()
/
1000
;
if
(
Math
.
abs
(
currentTimestamp
-
timestamp
)
>
600
)
{
return
"请求已过期"
;
}
// 防止请求重放,nonce只能用一次,放在redis中,有效期 20分钟
String
nonceKey
=
"api_signature:nonce:"
+
nonce
;
if
(
Boolean
.
FALSE
.
equals
(
this
.
redisTemplate
.
opsForValue
().
setIfAbsent
(
nonceKey
,
"1"
,
20
,
TimeUnit
.
MINUTES
)))
{
return
"nonce无效:"
+
nonce
;
}
// 校验appId
appStore
=
this
.
appStoreService
.
getAppSecretInfo
(
appId
);
String
appSecret
=
appStore
.
getAppSecret
();
if
(!
StringUtils
.
hasText
(
appSecret
))
{
return
"appId无效:"
+
appId
;
}
//验证单位
if
(
deptCode
!=
null
&&
!
deptCode
.
startsWith
(
appStore
.
getDeptCode
().
replaceAll
(
"0+$"
,
""
)))
{
return
"AppId和传入的单位不匹配,appId:"
+
appId
+
",deptCode:"
+
deptCode
;
}
String
data
=
String
.
format
(
"%s%s%s%s%s"
,
appId
,
nonce
,
timestampStr
,
commonRequestDTO
.
getContent
(),
deptCode
);
String
generatedSignature
=
DigestUtil
.
md5Hex
(
data
);
if
(!
generatedSignature
.
equals
(
sign
))
{
logger
.
warn
(
"签名有误,generatedSignature:{},sign:{},appId:{},nonce:{},timestampStr:{},deptCode:{}"
,
generatedSignature
,
sign
,
appId
,
nonce
,
timestampStr
,
deptCode
);
return
"签名有误,sign: "
+
sign
+
",appId:"
+
appId
+
",nonce:"
+
nonce
+
",timestamp:"
+
timestampStr
+
",deptCode:"
+
deptCode
;
}
// 签名验证通过
return
null
;
}
/**
* 向客户端写入响应信息
*
* @param response HTTP响应
* @param msg 响应信息
* @throws IOException 如果写入失败
*/
private
void
write
(
HttpServletResponse
response
,
String
msg
)
throws
IOException
{
HttpResultState
httpResultState
=
HttpResultState
.
INVALID_SIGNATURE
;
httpResultState
.
setMessage
(
msg
);
HttpResult
<
String
>
httpResult
=
new
HttpResult
<>(
httpResultState
);
response
.
setContentType
(
MediaType
.
APPLICATION_JSON_VALUE
);
response
.
setCharacterEncoding
(
StandardCharsets
.
UTF_8
.
name
());
response
.
getWriter
().
write
(
JSONUtil
.
toJsonStr
(
httpResult
));
}
}
src/main/java/com/zksy/szpt/util/EncryptUtil.java
View file @
5bea093f
...
...
@@ -151,7 +151,7 @@ public class EncryptUtil {
* @param res 需要解密的密文
* @param key 秘钥
*/
p
rivate
String
AESDecode
(
String
res
,
String
key
)
{
p
ublic
String
AESDecode
(
String
res
,
String
key
)
{
return
keyGeneratorES
(
res
,
AES
,
key
,
keySizeAES
,
false
);
}
...
...
src/test/java/com/zksy/szpt/CommonUtil.java
0 → 100644
View file @
5bea093f
package
com
.
zksy
.
szpt
;
public
class
CommonUtil
{
}
src/test/java/com/zksy/szpt/TestAppStore.java
View file @
5bea093f
...
...
@@ -3,6 +3,7 @@ package com.zksy.szpt;
import
cn.hutool.crypto.digest.DigestUtil
;
import
com.fasterxml.jackson.core.JsonProcessingException
;
import
com.fasterxml.jackson.databind.ObjectMapper
;
import
com.zksy.szpt.domain.CommonRequestDTO
;
import
com.zksy.szpt.domain.dto.*
;
import
com.zksy.szpt.util.EncryptUtil
;
import
com.zksy.szpt.util.SignatureUtil
;
...
...
@@ -38,7 +39,7 @@ public class TestAppStore {
Assertions
.
assertNotNull
(
appId
,
"appId不存在"
);
//断言appId存在,为空直接抛出异常不进行下一步测试,提高测试效率
//请求参数
AppStoreDTO
appStoreDTO
=
new
AppStoreDTO
();
appStoreDTO
.
setAppKey
(
"us"
);
appStoreDTO
.
setAppKey
(
"us
2
"
);
appStoreDTO
.
setAppSecret
(
DigestUtil
.
md5Hex
(
"us"
));
appStoreDTO
.
setDeptCode
(
"123456"
);
String
json
=
null
;
...
...
@@ -62,7 +63,7 @@ public class TestAppStore {
.
header
(
SignatureUtil
.
NONCE
,
nonce
)
.
header
(
SignatureUtil
.
TIMESTAMP
,
timestampStr
)
.
header
(
SignatureUtil
.
SIGNATURE
,
generatedSignature
)
.
body
(
Mono
.
just
(
appStoreDTO
),
XxRwwcqk
DTO
.
class
)
.
body
(
Mono
.
just
(
appStoreDTO
),
AppStore
DTO
.
class
)
.
retrieve
()
.
bodyToMono
(
String
.
class
)
.
block
();
...
...
@@ -107,4 +108,53 @@ public class TestAppStore {
.
block
();
System
.
out
.
println
(
response
);
}
/**
* 新增AppId
*/
@Test
@DisplayName
(
"新增AppId1"
)
public
void
addAppId1
()
{
String
deptCode
=
"330102"
;
timestampStr
=
String
.
valueOf
(
System
.
currentTimeMillis
()
/
1000
);
nonce
=
String
.
valueOf
(
System
.
currentTimeMillis
()
/
1000
);
appSecret
=
DigestUtil
.
md5Hex
(
appSecret
);
Assertions
.
assertNotNull
(
appId
,
"appId不存在"
);
//断言appId存在,为空直接抛出异常不进行下一步测试,提高测试效率
//请求参数
AppStoreDTO
appStoreDTO
=
new
AppStoreDTO
();
appStoreDTO
.
setAppKey
(
"us2"
);
appStoreDTO
.
setAppSecret
(
DigestUtil
.
md5Hex
(
"us"
));
appStoreDTO
.
setDeptCode
(
deptCode
);
String
json
=
null
;
try
{
json
=
objectMapper
.
writeValueAsString
(
appStoreDTO
);
}
catch
(
JsonProcessingException
e
)
{
Assertions
.
fail
(
"json序列化失败"
);
}
//请求体加密
json
=
EncryptUtil
.
getInstance
().
AESEncode
(
json
,
appSecret
);
//签名appId+nonce+timestampStr+aes(body)+deptCode
String
data
=
String
.
format
(
"%s%s%s%s%s"
,
appId
,
nonce
,
timestampStr
,
json
,
deptCode
);
String
generatedSignature
=
DigestUtil
.
md5Hex
(
data
);
CommonRequestDTO
commonRequestDTO
=
new
CommonRequestDTO
();
commonRequestDTO
.
setAppId
(
appId
);
commonRequestDTO
.
setNonce
(
nonce
);
commonRequestDTO
.
setTimestamp
(
timestampStr
);
commonRequestDTO
.
setDeptCode
(
deptCode
);
commonRequestDTO
.
setContent
(
json
);
commonRequestDTO
.
setSign
(
generatedSignature
);
//请求
WebClient
webClient
=
WebClient
.
builder
()
.
baseUrl
(
"http://localhost:8086"
)
.
defaultHeader
(
"Content-Type"
,
"application/json"
)
.
build
();
String
response
=
webClient
.
post
().
uri
(
"/rest/appStore/insertAppStore"
)
.
body
(
Mono
.
just
(
commonRequestDTO
),
CommonRequestDTO
.
class
)
.
retrieve
()
.
bodyToMono
(
String
.
class
)
.
block
();
System
.
out
.
println
(
response
);
}
}
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment