Skip to content
GitLab
Projects
Groups
Snippets
Help
Loading...
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
S
schbrain-parent
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Service Desk
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Operations
Operations
Metrics
Incidents
Environments
Packages & Registries
Packages & Registries
Package Registry
Analytics
Analytics
CI / CD
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
framework
schbrain-parent
Commits
e6f5f8b2
Commit
e6f5f8b2
authored
Aug 18, 2023
by
liaozan
🏀
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
AbstractSignatureValidationInterceptor
parent
c98d8823
Changes
6
Hide whitespace changes
Inline
Side-by-side
Showing
6 changed files
with
176 additions
and
23 deletions
+176
-23
commons/web-common/src/main/java/com/schbrain/common/web/servlet/RequestLoggingFilter.java
...com/schbrain/common/web/servlet/RequestLoggingFilter.java
+2
-23
commons/web-common/src/main/java/com/schbrain/common/web/support/signature/AbstractSignatureValidationInterceptor.java
...ort/signature/AbstractSignatureValidationInterceptor.java
+79
-0
commons/web-common/src/main/java/com/schbrain/common/web/support/signature/SignatureContext.java
...hbrain/common/web/support/signature/SignatureContext.java
+12
-0
commons/web-common/src/main/java/com/schbrain/common/web/support/signature/SignatureContextUtil.java
...in/common/web/support/signature/SignatureContextUtil.java
+33
-0
commons/web-common/src/main/java/com/schbrain/common/web/support/signature/SignatureValidationException.java
...n/web/support/signature/SignatureValidationException.java
+22
-0
commons/web-common/src/main/java/com/schbrain/common/web/utils/ContentCachingServletUtils.java
...schbrain/common/web/utils/ContentCachingServletUtils.java
+28
-0
No files found.
commons/web-common/src/main/java/com/schbrain/common/web/servlet/RequestLoggingFilter.java
View file @
e6f5f8b2
package
com.schbrain.common.web.servlet
;
import
cn.hutool.core.text.CharPool
;
import
c
n.hutool.core.util.ArrayUtil
;
import
c
om.schbrain.common.web.utils.ContentCachingServletUtils
;
import
lombok.extern.slf4j.Slf4j
;
import
org.apache.commons.lang3.StringUtils
;
import
org.springframework.boot.web.servlet.filter.OrderedFilter
;
import
org.springframework.core.Ordered
;
import
org.springframework.web.cors.CorsUtils
;
import
org.springframework.web.filter.OncePerRequestFilter
;
import
org.springframework.web.util.ContentCachingRequestWrapper
;
import
org.springframework.web.util.WebUtils
;
import
javax.servlet.FilterChain
;
import
javax.servlet.ServletException
;
import
javax.servlet.http.HttpServletRequest
;
import
javax.servlet.http.HttpServletResponse
;
import
java.io.IOException
;
import
java.io.UnsupportedEncodingException
;
import
static
com
.
schbrain
.
common
.
web
.
utils
.
ContentCachingServletUtils
.
wrapRequestIfRequired
;
...
...
@@ -58,7 +55,7 @@ public class RequestLoggingFilter extends OncePerRequestFilter implements Ordere
String
method
=
request
.
getMethod
();
String
requestUri
=
request
.
getRequestURI
();
String
queryString
=
request
.
getQueryString
();
String
body
=
getRequestBody
(
request
);
String
body
=
ContentCachingServletUtils
.
getRequestBody
(
request
,
false
);
StringBuilder
builder
=
new
StringBuilder
();
builder
.
append
(
"requestUri: "
).
append
(
method
).
append
(
CharPool
.
SPACE
).
append
(
requestUri
);
if
(
StringUtils
.
isNotBlank
(
queryString
))
{
...
...
@@ -73,22 +70,4 @@ public class RequestLoggingFilter extends OncePerRequestFilter implements Ordere
return
builder
.
toString
();
}
protected
String
getRequestBody
(
HttpServletRequest
request
)
{
ContentCachingRequestWrapper
nativeRequest
=
WebUtils
.
getNativeRequest
(
request
,
ContentCachingRequestWrapper
.
class
);
if
(
nativeRequest
==
null
)
{
return
null
;
}
byte
[]
content
=
nativeRequest
.
getContentAsByteArray
();
if
(
ArrayUtil
.
isEmpty
(
content
))
{
return
null
;
}
String
charset
=
nativeRequest
.
getCharacterEncoding
();
try
{
return
new
String
(
content
,
charset
);
}
catch
(
UnsupportedEncodingException
e
)
{
log
.
warn
(
"unsupported charset {} detect during convert body to String"
,
charset
,
e
);
return
null
;
}
}
}
commons/web-common/src/main/java/com/schbrain/common/web/support/signature/AbstractSignatureValidationInterceptor.java
0 → 100644
View file @
e6f5f8b2
package
com.schbrain.common.web.support.signature
;
import
cn.hutool.crypto.digest.DigestUtil
;
import
com.schbrain.common.web.support.BaseHandlerInterceptor
;
import
org.apache.commons.lang3.StringUtils
;
import
org.springframework.web.method.HandlerMethod
;
import
javax.servlet.http.HttpServletRequest
;
import
javax.servlet.http.HttpServletResponse
;
import
static
cn
.
hutool
.
core
.
text
.
StrPool
.
UNDERLINE
;
import
static
com
.
schbrain
.
common
.
web
.
utils
.
ContentCachingServletUtils
.
getRequestBody
;
import
static
com
.
schbrain
.
common
.
web
.
utils
.
ContentCachingServletUtils
.
wrapRequestIfRequired
;
public
abstract
class
AbstractSignatureValidationInterceptor
<
T
extends
SignatureContext
>
extends
BaseHandlerInterceptor
{
private
static
final
String
SCH_APP_KEY
=
"Sch-App-Key"
;
private
static
final
String
SCH_TIMESTAMP
=
"Sch-Timestamp"
;
private
static
final
String
SCH_SIGNATURE
=
"Sch-Signature"
;
private
static
final
String
SCH_EXPIRE_TIME
=
"Sch-Expire-Time"
;
@Override
protected
boolean
preHandle
(
HttpServletRequest
request
,
HttpServletResponse
response
,
HandlerMethod
handlerMethod
)
{
String
appKey
=
request
.
getHeader
(
SCH_APP_KEY
);
String
timestamp
=
request
.
getHeader
(
SCH_TIMESTAMP
);
String
signature
=
request
.
getHeader
(
SCH_SIGNATURE
);
String
expireTime
=
request
.
getHeader
(
SCH_EXPIRE_TIME
);
// 空校验
if
(
StringUtils
.
isAnyBlank
(
appKey
,
timestamp
,
signature
))
{
throw
new
SignatureValidationException
(
"签名参数为空!"
);
}
// 过期校验
if
(
StringUtils
.
isNotBlank
(
expireTime
)
&&
System
.
currentTimeMillis
()
>
Long
.
parseLong
(
expireTime
))
{
throw
new
SignatureValidationException
(
"请求信息已过期!"
);
}
// 获取appSecret
SignatureContext
context
=
getSignatureContext
(
appKey
);
if
(
null
==
context
||
StringUtils
.
isBlank
(
context
.
getAppSecret
()))
{
throw
new
SignatureValidationException
();
}
request
=
wrapRequestIfRequired
(
request
);
// 校验签名
String
requestUri
=
request
.
getRequestURI
();
String
queryString
=
request
.
getQueryString
();
String
body
=
getRequestBody
(
request
,
true
);
String
compareSignature
=
signParams
(
requestUri
,
queryString
,
body
,
timestamp
,
appKey
,
context
.
getAppSecret
());
if
(!
signature
.
equals
(
compareSignature
))
{
throw
new
SignatureValidationException
();
}
SignatureContextUtil
.
set
(
context
);
return
true
;
}
@Override
protected
void
afterCompletion
(
HttpServletRequest
request
,
HttpServletResponse
response
,
HandlerMethod
handlerMethod
,
Exception
ex
)
{
SignatureContextUtil
.
clear
();
}
protected
abstract
T
getSignatureContext
(
String
appKey
);
protected
String
signParams
(
String
requestUri
,
String
queryString
,
String
bodyString
,
String
timestamp
,
String
appKey
,
String
appSecret
)
{
StringBuilder
toSign
=
new
StringBuilder
(
requestUri
);
if
(
StringUtils
.
isNotBlank
(
queryString
))
{
toSign
.
append
(
UNDERLINE
).
append
(
queryString
);
}
if
(
StringUtils
.
isNotBlank
(
bodyString
))
{
toSign
.
append
(
UNDERLINE
).
append
(
bodyString
);
}
toSign
.
append
(
UNDERLINE
).
append
(
timestamp
).
append
(
UNDERLINE
).
append
(
appKey
).
append
(
UNDERLINE
).
append
(
appSecret
);
return
DigestUtil
.
sha256Hex
(
toSign
.
toString
());
}
}
commons/web-common/src/main/java/com/schbrain/common/web/support/signature/SignatureContext.java
0 → 100644
View file @
e6f5f8b2
package
com.schbrain.common.web.support.signature
;
import
lombok.Data
;
@Data
public
class
SignatureContext
{
private
String
appKey
;
private
String
appSecret
;
}
commons/web-common/src/main/java/com/schbrain/common/web/support/signature/SignatureContextUtil.java
0 → 100644
View file @
e6f5f8b2
package
com.schbrain.common.web.support.signature
;
import
java.util.Optional
;
import
java.util.function.Supplier
;
public
class
SignatureContextUtil
{
private
static
final
ThreadLocal
<
SignatureContext
>
LOCAL
=
new
InheritableThreadLocal
<>();
private
static
final
Supplier
<
SignatureValidationException
>
EXCEPTION_SUPPLIER
=
SignatureValidationException:
:
new
;
/**
* 取值
*/
public
static
<
T
extends
SignatureContext
>
T
get
(
Class
<
T
>
type
)
{
return
type
.
cast
(
Optional
.
ofNullable
(
LOCAL
.
get
()).
orElseThrow
(
EXCEPTION_SUPPLIER
));
}
/**
* 赋值
*/
public
static
<
T
extends
SignatureContext
>
void
set
(
T
signatureContext
)
{
LOCAL
.
set
(
signatureContext
);
}
/**
* 移除
*/
public
static
void
clear
()
{
LOCAL
.
remove
();
}
}
commons/web-common/src/main/java/com/schbrain/common/web/support/signature/SignatureValidationException.java
0 → 100644
View file @
e6f5f8b2
package
com.schbrain.common.web.support.signature
;
import
com.schbrain.common.exception.BaseException
;
import
static
com
.
schbrain
.
common
.
constants
.
ResponseActionConstants
.
ALERT
;
import
static
com
.
schbrain
.
common
.
constants
.
ResponseCodeConstants
.
PARAM_INVALID
;
public
class
SignatureValidationException
extends
BaseException
{
private
static
final
long
serialVersionUID
=
7564001466173362458L
;
private
static
final
String
DEFAULT_ERR_MSG
=
"签名验证异常"
;
public
SignatureValidationException
()
{
this
(
DEFAULT_ERR_MSG
);
}
public
SignatureValidationException
(
String
message
)
{
super
(
message
,
PARAM_INVALID
,
ALERT
);
}
}
commons/web-common/src/main/java/com/schbrain/common/web/utils/ContentCachingServletUtils.java
View file @
e6f5f8b2
package
com.schbrain.common.web.utils
;
import
cn.hutool.core.util.ArrayUtil
;
import
lombok.extern.slf4j.Slf4j
;
import
org.springframework.util.Assert
;
import
org.springframework.util.StreamUtils
;
import
org.springframework.web.util.ContentCachingRequestWrapper
;
import
org.springframework.web.util.ContentCachingResponseWrapper
;
import
org.springframework.web.util.WebUtils
;
import
javax.servlet.http.HttpServletRequest
;
import
javax.servlet.http.HttpServletResponse
;
import
java.io.IOException
;
import
java.nio.charset.Charset
;
/**
* @author liaozan
* @since 2023-05-08
*/
@Slf4j
public
class
ContentCachingServletUtils
{
/**
...
...
@@ -37,4 +44,25 @@ public class ContentCachingServletUtils {
}
}
public
static
String
getRequestBody
(
HttpServletRequest
request
,
boolean
readFromInputStream
)
{
ContentCachingRequestWrapper
nativeRequest
=
WebUtils
.
getNativeRequest
(
request
,
ContentCachingRequestWrapper
.
class
);
if
(
nativeRequest
==
null
)
{
return
null
;
}
Charset
charset
=
Charset
.
forName
(
nativeRequest
.
getCharacterEncoding
());
if
(
readFromInputStream
)
{
try
{
return
StreamUtils
.
copyToString
(
request
.
getInputStream
(),
charset
);
}
catch
(
IOException
e
)
{
log
.
warn
(
"Failed to read body content from request inputStream"
);
return
null
;
}
}
byte
[]
content
=
nativeRequest
.
getContentAsByteArray
();
if
(
ArrayUtil
.
isEmpty
(
content
))
{
return
null
;
}
return
new
String
(
content
,
charset
);
}
}
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