Skip to content
Toggle navigation
P
Projects
G
Groups
S
Snippets
Help
Administrator
/
framework-tools
This project
Loading...
Sign in
Toggle navigation
Go to a project
Project
Repository
Issues
0
Merge Requests
0
Pipelines
Wiki
Snippets
Settings
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Commit 2c8ec2b3
authored
Jul 01, 2024
by
henry
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
修改gateway服务
1 parent
3647d763
Show whitespace changes
Inline
Side-by-side
Showing
29 changed files
with
5334 additions
and
18 deletions
arch-gateway/pom.xml
arch-gateway/src/main/java/org/arch/GatewayApp.java
arch-gateway/src/main/java/org/arch/Main.java
arch-gateway/src/main/java/org/arch/common/Constant.java
arch-gateway/src/main/java/org/arch/config/AnonFilterChainDefinitionMap.java
arch-gateway/src/main/java/org/arch/config/CacheBodyGlobalFilter.java
arch-gateway/src/main/java/org/arch/config/GatewayLogFilter.java
arch-gateway/src/main/java/org/arch/config/LoginFilter.java
arch-gateway/src/main/java/org/arch/config/OriginFilter_ISC.java
arch-gateway/src/main/java/org/arch/config/ParamsEncryptionFilter.java
arch-gateway/src/main/java/org/arch/config/ParamsSM4EncryptionFilter.java
arch-gateway/src/main/java/org/arch/config/fileFilter/FileUploadInterceptor.java
arch-gateway/src/main/java/org/arch/config/fileFilter/FileUploadSizeLimitFilter.java
arch-gateway/src/main/java/org/arch/config/fileFilter/FilterConfig.java
arch-gateway/src/main/java/org/arch/config/fileFilter/WebFileConfig.java
arch-gateway/src/main/java/org/arch/config/sm4jm/ByteConvertUtil.java
arch-gateway/src/main/java/org/arch/config/sm4jm/SM4.java
arch-gateway/src/main/java/org/arch/config/sm4jm/SM4Context.java
arch-gateway/src/main/java/org/arch/config/sm4jm/SM4Utils.java
arch-gateway/src/main/java/org/arch/config/tszf/specialCharFilter.java
arch-gateway/src/main/java/org/arch/config/xssFilter/JsonUtil.java
arch-gateway/src/main/java/org/arch/config/xssFilter/XssFilter.java
arch-gateway/src/main/java/org/arch/config/xssFilter/XssUtil.java
arch-gateway/src/main/java/org/arch/service/RedisService.java
arch-gateway/src/main/java/org/arch/systemLog/GatewayLog.java
arch-gateway/src/main/java/org/arch/util/Base64ConvertUtil.java
arch-gateway/src/main/java/org/arch/util/JwtUtil.java
arch-gateway/src/main/java/org/arch/util/StringUtils.java
pom.xml
arch-gateway/pom.xml
View file @
2c8ec2b
...
...
@@ -16,5 +16,94 @@
<maven.compiler.target>
8
</maven.compiler.target>
<project.build.sourceEncoding>
UTF-8
</project.build.sourceEncoding>
</properties>
<dependencies>
<!--(nacos统一配置中心管理依赖)-->
<dependency>
<groupId>
com.alibaba.cloud
</groupId>
<artifactId>
spring-cloud-starter-alibaba-nacos-config
</artifactId>
</dependency>
<dependency>
<groupId>
com.alibaba.cloud
</groupId>
<artifactId>
spring-cloud-starter-alibaba-nacos-discovery
</artifactId>
</dependency>
<dependency>
<groupId>
com.github.xiaoymin
</groupId>
<artifactId>
knife4j-gateway-spring-boot-starter
</artifactId>
</dependency>
<dependency>
<groupId>
org.springframework.cloud
</groupId>
<artifactId>
spring-cloud-starter-loadbalancer
</artifactId>
</dependency>
<dependency>
<groupId>
org.springframework.cloud
</groupId>
<artifactId>
spring-cloud-starter-bootstrap
</artifactId>
</dependency>
<!--gateway依赖-->
<dependency>
<groupId>
org.springframework.cloud
</groupId>
<artifactId>
spring-cloud-starter-gateway
</artifactId>
</dependency>
<!--openfeign-->
<dependency>
<groupId>
org.springframework.cloud
</groupId>
<artifactId>
spring-cloud-starter-openfeign
</artifactId>
</dependency>
<!--jwt-->
<dependency>
<groupId>
com.auth0
</groupId>
<artifactId>
java-jwt
</artifactId>
</dependency>
<dependency>
<groupId>
io.jsonwebtoken
</groupId>
<artifactId>
jjwt
</artifactId>
</dependency>
<dependency>
<groupId>
javax.servlet
</groupId>
<artifactId>
javax.servlet-api
</artifactId>
</dependency>
<dependency>
<groupId>
cn.hutool
</groupId>
<artifactId>
hutool-all
</artifactId>
</dependency>
<dependency>
<groupId>
org.jsoup
</groupId>
<artifactId>
jsoup
</artifactId>
</dependency>
<!--SM4-CBC加密需要-->
<!-- https://mvnrepository.com/artifact/org.bouncycastle/bcprov-jdk15on -->
<dependency>
<groupId>
org.bouncycastle
</groupId>
<artifactId>
bcprov-jdk15on
</artifactId>
</dependency>
</dependencies>
<build>
<finalName>
${project.artifactId}
</finalName>
<plugins>
<plugin>
<groupId>
org.springframework.boot
</groupId>
<artifactId>
spring-boot-maven-plugin
</artifactId>
<configuration>
<includeSystemScope>
true
</includeSystemScope>
</configuration>
<executions>
<execution>
<goals>
<goal>
repackage
</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
\ No newline at end of file
arch-gateway/src/main/java/org/arch/GatewayApp.java
0 → 100644
View file @
2c8ec2b
package
org
.
arch
;
import
org.springframework.boot.SpringApplication
;
import
org.springframework.boot.autoconfigure.SpringBootApplication
;
import
org.springframework.cloud.client.discovery.EnableDiscoveryClient
;
/**
* Hello world!
*/
@SpringBootApplication
@EnableDiscoveryClient
public
class
GatewayApp
{
public
static
void
main
(
String
[]
args
)
{
SpringApplication
.
run
(
GatewayApp
.
class
,
args
);
}
}
arch-gateway/src/main/java/org/arch/Main.java
deleted
100644 → 0
View file @
3647d76
package
org
.
arch
;
public
class
Main
{
public
static
void
main
(
String
[]
args
)
{
System
.
out
.
println
(
"Hello world!"
);
}
}
\ No newline at end of file
arch-gateway/src/main/java/org/arch/common/Constant.java
0 → 100644
View file @
2c8ec2b
package
org
.
arch
.
common
;
public
class
Constant
{
/**
* redis过期时间,以秒为单位,一分钟
*/
public
static
final
int
EXRP_MINUTE
=
60
;
/**
* redis过期时间,以秒为单位,一小时
*/
public
static
final
int
EXRP_HOUR
=
60
*
60
;
/**
* redis过期时间,以秒为单位,一天
*/
public
static
final
int
EXRP_DAY
=
60
*
60
*
24
;
/**
* redis-key-前缀-shiro:cache:
*/
public
static
final
String
PREFIX_SHIRO_CACHE
=
"shiro:cache:"
;
/**
* 用户信息缓存
*/
public
static
final
String
USER_ACCOUNT
=
"user_account:"
;
/**
* redis-key-前缀-shiro:access_token:
*/
public
static
final
String
PREFIX_SHIRO_ACCESS_TOKEN
=
"shiro:access_token:"
;
/**
* redis-key-前缀-shiro:refresh_token:
*/
public
static
final
String
PREFIX_SHIRO_REFRESH_TOKEN
=
"shiro:refresh_token:"
;
/**
* redis-key-前缀-tkv:refresh_token:
*/
public
static
final
String
PREFIX_TKV_REFRESH_TOKEN
=
"tkv:refresh_token:"
;
/**
* JWT-account:
*/
public
static
final
String
ACCOUNT
=
"account"
;
/**
* JWT-currentTimeMillis:
*/
public
static
final
String
CURRENT_TIME_MILLIS
=
"currentTimeMillis"
;
/**
* PASSWORD_MAX_LEN
*/
public
static
final
Integer
PASSWORD_MAX_LEN
=
8
;
//token
public
static
final
int
RESCODE_REFTOKEN_MSG
=
1006
;
//刷新TOKEN(有返回数据)
public
static
final
int
RESCODE_REFTOKEN
=
1007
;
//刷新TOKEN
public
static
final
int
JWT_ERRCODE_NULL
=
4000
;
//Token不存在
public
static
final
int
JWT_ERRCODE_EXPIRE
=
4001
;
//Token过期
public
static
final
int
JWT_ERRCODE_FAIL
=
4002
;
//验证不通过
//密匙
public
static
final
String
JWT_SECRET
=
"8677df7fc87d23u87k61c89s54312hpk"
;
public
static
final
String
TOKEN_ISSUER
=
"IT4IT"
;
//token失效的时间,单位:秒,默认设置3天
public
static
final
Long
ACCESS_TOKEN_EXPIRE
=
7
*
24
*
60
*
60L
;
//accessToken在header中的key
public
static
final
String
ACCESS_TOKEN_HEADER_KEY
=
"accessToken"
;
//用户sessionKey前缀
public
static
final
String
USER_SESSION_KEY
=
"User:Session:key:"
;
//用户令牌前缀
public
static
final
String
JWT_TOKEN_REDIS_KEY_PREFIX
=
"UserAuth:JWT:Key:"
;
//省市区redis key,缓存7天
public
static
final
String
AREA_REDIS_KEY
=
"areaKey"
;
public
static
final
Long
AREA_REDIS_EXPEPIRE
=
7
*
24
*
60
*
60L
;
//一次最多只能两个时段
public
static
final
Integer
EVERY_TIME_MAX_TWO_TIMES
=
2
;
//排队受理业务人均时长,单位:分钟
public
static
final
Integer
LINE_PER_TIMES
=
3
;
//订单到期规定的时间不能取消订单(分钟)
public
static
final
Integer
VALID_EXPIRE_TIME
=
120
;
//演示系统账户
public
static
String
DEMO_ACCOUNT
=
"test"
;
//自动去除表前缀
public
static
String
AUTO_REOMVE_PRE
=
"true"
;
//停止计划任务
public
static
String
STATUS_RUNNING_STOP
=
"stop"
;
//开启计划任务
public
static
String
STATUS_RUNNING_START
=
"start"
;
//通知公告阅读状态-未读
public
static
String
OA_NOTIFY_READ_NO
=
"0"
;
//通知公告阅读状态-已读
public
static
int
OA_NOTIFY_READ_YES
=
1
;
//部门根节点id
public
static
Long
DEPT_ROOT_ID
=
0
l
;
//缓存方式
public
static
String
CACHE_TYPE_REDIS
=
"redis"
;
public
static
String
LOG_ERROR
=
"error"
;
}
arch-gateway/src/main/java/org/arch/config/AnonFilterChainDefinitionMap.java
0 → 100644
View file @
2c8ec2b
package
org
.
arch
.
config
;
import
org.springframework.util.AntPathMatcher
;
import
java.util.ArrayList
;
import
java.util.List
;
/**
* 不需要登录的请求路径
*/
public
class
AnonFilterChainDefinitionMap
{
//不需要登录的路径
public
static
List
<
String
>
anonUrlList
=
new
ArrayList
<>();
static
{
anonUrlList
.
add
(
"/project/updateFile2"
);
anonUrlList
.
add
(
"/adsproject/updateFile2"
);
anonUrlList
.
add
(
"/file/webDownload"
);
anonUrlList
.
add
(
"/directoryList/getJiagoutu"
);
anonUrlList
.
add
(
"/project/getTableDatas"
);
//架构表/
anonUrlList
.
add
(
"/psrPlan/getPsrPlansByFsrId"
);
////插入需求
anonUrlList
.
add
(
"/expose/getEquipmentList"
);
anonUrlList
.
add
(
"/expose/getBusList"
);
anonUrlList
.
add
(
"/expose/getRelatedList"
);
anonUrlList
.
add
(
"/auth/isclogin"
);
////插入需求
anonUrlList
.
add
(
"/auth/login"
);
////插入需求
anonUrlList
.
add
(
"/file/upload"
);
////插入需求
anonUrlList
.
add
(
"/version/getCurrentVersion"
);
////插入需求
// 架构元模型管理
anonUrlList
.
add
(
"/architecture/vi/file/getById"
);
}
/**
* 验证是否不需要登录
* @param url 路径
* @return 是否需要登录
*/
public
static
boolean
isNotPermission
(
String
url
)
{
AntPathMatcher
matcher
=
new
AntPathMatcher
();
for
(
String
p
:
anonUrlList
)
{
if
(
matcher
.
match
(
p
,
url
))
{
return
true
;
}
}
return
false
;
}
}
arch-gateway/src/main/java/org/arch/config/CacheBodyGlobalFilter.java
0 → 100644
View file @
2c8ec2b
package
org
.
arch
.
config
;
import
org.springframework.cloud.gateway.filter.GatewayFilterChain
;
import
org.springframework.cloud.gateway.filter.GlobalFilter
;
import
org.springframework.core.Ordered
;
import
org.springframework.core.io.buffer.DataBuffer
;
import
org.springframework.core.io.buffer.DataBufferUtils
;
import
org.springframework.http.server.reactive.ServerHttpRequest
;
import
org.springframework.http.server.reactive.ServerHttpRequestDecorator
;
import
org.springframework.stereotype.Component
;
import
org.springframework.web.server.ServerWebExchange
;
import
reactor.core.publisher.Flux
;
import
reactor.core.publisher.Mono
;
/**
* 把body中的数据缓存起来
* @author zg_xl920
* @create 2022-05-26 19:43
*/
@Component
public
class
CacheBodyGlobalFilter
implements
Ordered
,
GlobalFilter
{
// public static final String CACHE_REQUEST_BODY_OBJECT_KEY = "cachedRequestBodyObject";
@Override
public
Mono
<
Void
>
filter
(
ServerWebExchange
exchange
,
GatewayFilterChain
chain
)
{
if
(
exchange
.
getRequest
().
getHeaders
().
getContentType
()
==
null
)
{
return
chain
.
filter
(
exchange
);
}
else
{
return
DataBufferUtils
.
join
(
exchange
.
getRequest
().
getBody
())
.
flatMap
(
dataBuffer
->
{
DataBufferUtils
.
retain
(
dataBuffer
);
Flux
<
DataBuffer
>
cachedFlux
=
Flux
.
defer
(()
->
Flux
.
just
(
dataBuffer
.
slice
(
0
,
dataBuffer
.
readableByteCount
())));
ServerHttpRequest
mutatedRequest
=
new
ServerHttpRequestDecorator
(
exchange
.
getRequest
())
{
@Override
public
Flux
<
DataBuffer
>
getBody
()
{
return
cachedFlux
;
}
};
//exchange.getAttributes().put(CACHE_REQUEST_BODY_OBJECT_KEY, cachedFlux);
return
chain
.
filter
(
exchange
.
mutate
().
request
(
mutatedRequest
).
build
());
});
}
}
@Override
public
int
getOrder
()
{
return
-
2
;
}
}
arch-gateway/src/main/java/org/arch/config/GatewayLogFilter.java
0 → 100644
View file @
2c8ec2b
package
org
.
arch
.
config
;
import
com.alibaba.fastjson.JSON
;
import
lombok.extern.slf4j.Slf4j
;
import
org.apache.commons.lang3.StringUtils
;
import
org.arch.systemLog.GatewayLog
;
import
org.reactivestreams.Publisher
;
import
org.springframework.beans.factory.annotation.Autowired
;
import
org.springframework.cloud.gateway.filter.GatewayFilterChain
;
import
org.springframework.cloud.gateway.filter.GlobalFilter
;
import
org.springframework.cloud.gateway.filter.factory.rewrite.CachedBodyOutputMessage
;
import
org.springframework.cloud.gateway.route.Route
;
import
org.springframework.cloud.gateway.support.BodyInserterContext
;
import
org.springframework.cloud.gateway.support.ServerWebExchangeUtils
;
import
org.springframework.context.ApplicationEventPublisher
;
import
org.springframework.core.Ordered
;
import
org.springframework.core.io.buffer.DataBuffer
;
import
org.springframework.core.io.buffer.DataBufferFactory
;
import
org.springframework.core.io.buffer.DataBufferUtils
;
import
org.springframework.core.io.buffer.DefaultDataBufferFactory
;
import
org.springframework.http.HttpHeaders
;
import
org.springframework.http.HttpStatus
;
import
org.springframework.http.MediaType
;
import
org.springframework.http.codec.HttpMessageReader
;
import
org.springframework.http.server.reactive.ServerHttpRequest
;
import
org.springframework.http.server.reactive.ServerHttpRequestDecorator
;
import
org.springframework.http.server.reactive.ServerHttpResponse
;
import
org.springframework.http.server.reactive.ServerHttpResponseDecorator
;
import
org.springframework.util.MultiValueMap
;
import
org.springframework.util.ObjectUtils
;
import
org.springframework.web.reactive.function.BodyInserter
;
import
org.springframework.web.reactive.function.BodyInserters
;
import
org.springframework.web.reactive.function.server.HandlerStrategies
;
import
org.springframework.web.reactive.function.server.ServerRequest
;
import
org.springframework.web.server.ServerWebExchange
;
import
reactor.core.publisher.Flux
;
import
reactor.core.publisher.Mono
;
import
javax.servlet.http.HttpServletRequest
;
import
java.net.InetAddress
;
import
java.net.UnknownHostException
;
import
java.nio.charset.StandardCharsets
;
import
java.util.*
;
import
static
com
.
sun
.
org
.
apache
.
xml
.
internal
.
serializer
.
Method
.
UNKNOWN
;
@Slf4j
//@Component
public
class
GatewayLogFilter
implements
GlobalFilter
,
Ordered
{
@Autowired
private
ApplicationEventPublisher
applicationEventPublisher
;
private
final
List
<
HttpMessageReader
<?>>
messageReaders
=
HandlerStrategies
.
withDefaults
().
messageReaders
();
private
static
final
String
CONTENT_TYPE
=
"application/json"
;
// 请求来源应用
private
static
final
String
REQUEST_ORIGIN_APP
=
"Request-Origin-App"
;
// 自定义请求头,转发之前删除自定义请求头
private
static
final
List
<
String
>
CUSTOM_HEADERS
=
Arrays
.
asList
(
"sign"
,
"timestamp"
,
"random"
,
"Request-Origin-App"
);
@Override
public
Mono
<
Void
>
filter
(
ServerWebExchange
exchange
,
GatewayFilterChain
chain
)
{
ServerHttpRequest
request
=
exchange
.
getRequest
();
// 请求路径
String
requestPath
=
request
.
getPath
().
pathWithinApplication
().
value
();
// 获取路由信息
Route
route
=
getGatewayRoute
(
exchange
);
// String ipAddress = IpUtil.getIpAddr(request);
String
ipAddress
=
this
.
getIp
((
HttpServletRequest
)
request
);
GatewayLog
gatewayLog
=
new
GatewayLog
();
gatewayLog
.
setOrigin
(
request
.
getHeaders
().
getFirst
(
REQUEST_ORIGIN_APP
));
gatewayLog
.
setSchema
(
request
.
getURI
().
getScheme
());
gatewayLog
.
setRequestMethod
(
request
.
getMethodValue
());
gatewayLog
.
setRequestPath
(
requestPath
);
gatewayLog
.
setTargetServer
(
route
.
getUri
().
toString
());
gatewayLog
.
setStartTime
(
new
Date
().
getTime
());
gatewayLog
.
setIp
(
ipAddress
);
gatewayLog
.
setRouteConfig
(
JSON
.
toJSONString
(
route
));
Map
<
String
,
Object
>
headers
=
new
HashMap
<>();
for
(
String
key
:
request
.
getHeaders
().
keySet
())
{
headers
.
put
(
key
,
request
.
getHeaders
().
getFirst
(
key
));
}
gatewayLog
.
setHeaders
(
JSON
.
toJSONString
(
headers
));
MediaType
mediaType
=
request
.
getHeaders
().
getContentType
();
if
(
request
.
getHeaders
().
getContentType
()
!=
null
)
{
gatewayLog
.
setRequestContentType
(
request
.
getHeaders
().
getContentType
().
toString
());
}
if
(
mediaType
!=
null
&&
(
MediaType
.
APPLICATION_FORM_URLENCODED
.
isCompatibleWith
(
mediaType
)
||
MediaType
.
APPLICATION_JSON
.
isCompatibleWith
(
mediaType
))){
return
writeBodyLog
(
exchange
,
chain
,
gatewayLog
);
}
else
{
return
writeBasicLog
(
exchange
,
chain
,
gatewayLog
);
}
}
/**
* 获取ip地址
*/
private
String
getIp
(
HttpServletRequest
request
)
{
String
ip
=
request
.
getHeader
(
"x-forwarded-for"
);
if
(
ip
==
null
||
ip
.
length
()
==
0
||
UNKNOWN
.
equalsIgnoreCase
(
ip
))
{
ip
=
request
.
getHeader
(
"Proxy-Client-IP"
);
}
if
(
ip
==
null
||
ip
.
length
()
==
0
||
UNKNOWN
.
equalsIgnoreCase
(
ip
))
{
ip
=
request
.
getHeader
(
"WL-Proxy-Client-IP"
);
}
if
(
ip
==
null
||
ip
.
length
()
==
0
||
UNKNOWN
.
equalsIgnoreCase
(
ip
))
{
ip
=
request
.
getRemoteAddr
();
}
String
comma
=
","
;
String
localhost
=
"127.0.0.1"
;
if
(
ip
.
contains
(
comma
))
{
ip
=
ip
.
split
(
","
)[
0
];
}
if
(
localhost
.
equals
(
ip
))
{
// 获取本机真正的ip地址
try
{
ip
=
InetAddress
.
getLocalHost
().
getHostAddress
();
}
catch
(
UnknownHostException
e
)
{
e
.
printStackTrace
();
}
}
return
ip
;
}
@Override
public
int
getOrder
()
{
// 必须小于等于-2,否则无法获取相应结果
return
-
2
;
}
/**
* 获取路由信息
* @param exchange
* @return
*/
private
Route
getGatewayRoute
(
ServerWebExchange
exchange
)
{
return
exchange
.
getAttribute
(
ServerWebExchangeUtils
.
GATEWAY_ROUTE_ATTR
);
}
private
Mono
<
Void
>
writeBasicLog
(
ServerWebExchange
exchange
,
GatewayFilterChain
chain
,
GatewayLog
gatewayLog
)
{
StringBuilder
builder
=
new
StringBuilder
();
MultiValueMap
<
String
,
String
>
queryParams
=
exchange
.
getRequest
().
getQueryParams
();
gatewayLog
.
setRequestBody
(
getUrlParamsByMap
(
queryParams
));
// 修改Header
ServerHttpRequest
mutableReq
=
exchange
.
getRequest
().
mutate
().
headers
(
httpHeaders
->
{
// 删除自定义header
for
(
String
customHeader
:
CUSTOM_HEADERS
)
{
httpHeaders
.
remove
(
customHeader
);
}
}).
build
();
//获取响应体
ServerHttpResponseDecorator
decoratedResponse
=
recordResponseLog
(
exchange
,
gatewayLog
);
return
chain
.
filter
(
exchange
.
mutate
().
request
(
mutableReq
).
response
(
decoratedResponse
).
build
())
.
then
(
Mono
.
fromRunnable
(()
->
{
// 打印日志
writeAccessLog
(
gatewayLog
);
}));
}
/**
* 解决 request body 只能读取一次问题,
* 参考: org.springframework.cloud.gateway.filter.factory.rewrite.ModifyRequestBodyGatewayFilterFactory
* @param exchange
* @param chain
* @param gatewayLog
* @return
*/
private
Mono
<
Void
>
writeBodyLog
(
ServerWebExchange
exchange
,
GatewayFilterChain
chain
,
GatewayLog
gatewayLog
)
{
ServerRequest
serverRequest
=
ServerRequest
.
create
(
exchange
,
messageReaders
);
Mono
<
String
>
modifiedBody
=
serverRequest
.
bodyToMono
(
String
.
class
)
.
flatMap
(
body
->{
gatewayLog
.
setRequestBody
(
body
);
return
Mono
.
just
(
body
);
});
// 通过 BodyInserter 插入 body(支持修改body), 避免 request body 只能获取一次
BodyInserter
bodyInserter
=
BodyInserters
.
fromPublisher
(
modifiedBody
,
String
.
class
);
HttpHeaders
headers
=
new
HttpHeaders
();
headers
.
putAll
(
exchange
.
getRequest
().
getHeaders
());
// the new content type will be computed by bodyInserter
// and then set in the request decorator
headers
.
remove
(
HttpHeaders
.
CONTENT_LENGTH
);
CachedBodyOutputMessage
outputMessage
=
new
CachedBodyOutputMessage
(
exchange
,
headers
);
return
bodyInserter
.
insert
(
outputMessage
,
new
BodyInserterContext
())
.
then
(
Mono
.
defer
(()
->
{
// 重新封装请求
ServerHttpRequest
decoratedRequest
=
requestDecorate
(
exchange
,
headers
,
outputMessage
);
// 记录响应日志
ServerHttpResponseDecorator
decoratedResponse
=
recordResponseLog
(
exchange
,
gatewayLog
);
// 记录普通的
return
chain
.
filter
(
exchange
.
mutate
().
request
(
decoratedRequest
).
response
(
decoratedResponse
).
build
())
.
then
(
Mono
.
fromRunnable
(()
->
{
// 打印日志
writeAccessLog
(
gatewayLog
);
}));
}));
}
/**
* 打印日志
* @param gatewayLog 网关日志
*/
private
void
writeAccessLog
(
GatewayLog
gatewayLog
)
{
// applicationEventPublisher.publishEvent(new GatewayLogEvent(this, gatewayLog));
}
/**
* 请求装饰器,重新计算 headers
* @param exchange
* @param headers
* @param outputMessage
* @return
*/
private
ServerHttpRequestDecorator
requestDecorate
(
ServerWebExchange
exchange
,
HttpHeaders
headers
,
CachedBodyOutputMessage
outputMessage
)
{
return
new
ServerHttpRequestDecorator
(
exchange
.
getRequest
())
{
@Override
public
HttpHeaders
getHeaders
()
{
long
contentLength
=
headers
.
getContentLength
();
HttpHeaders
httpHeaders
=
new
HttpHeaders
();
httpHeaders
.
putAll
(
super
.
getHeaders
());
if
(
contentLength
>
0
)
{
httpHeaders
.
setContentLength
(
contentLength
);
}
else
{
// TODO: this causes a 'HTTP/1.1 411 Length Required' // on
// httpbin.org
httpHeaders
.
set
(
HttpHeaders
.
TRANSFER_ENCODING
,
"chunked"
);
}
// 删除自定义header
for
(
String
customHeader
:
CUSTOM_HEADERS
)
{
headers
.
remove
(
customHeader
);
}
return
httpHeaders
;
}
@Override
public
Flux
<
DataBuffer
>
getBody
()
{
return
outputMessage
.
getBody
();
}
};
}
/**
* 记录响应日志
* 通过 DataBufferFactory 解决响应体分段传输问题。
*/
private
ServerHttpResponseDecorator
recordResponseLog
(
ServerWebExchange
exchange
,
GatewayLog
gatewayLog
)
{
ServerHttpResponse
response
=
exchange
.
getResponse
();
DataBufferFactory
bufferFactory
=
response
.
bufferFactory
();
return
new
ServerHttpResponseDecorator
(
response
)
{
@Override
public
Mono
<
Void
>
writeWith
(
Publisher
<?
extends
DataBuffer
>
body
)
{
if
(
body
instanceof
Flux
)
{
Date
responseTime
=
new
Date
();
gatewayLog
.
setEndTime
(
responseTime
.
getTime
());
// 计算执行时间
long
executeTime
=
(
responseTime
.
getTime
()
-
gatewayLog
.
getStartTime
());
gatewayLog
.
setExecuteTime
(
executeTime
);
gatewayLog
.
setStatus
(
response
.
getStatusCode
().
value
()
==
200
?
"成功"
:
"失败"
);
// 获取响应类型,如果是 json 就打印
String
originalResponseContentType
=
exchange
.
getAttribute
(
ServerWebExchangeUtils
.
ORIGINAL_RESPONSE_CONTENT_TYPE_ATTR
);
if
(
Objects
.
equals
(
this
.
getStatusCode
(),
HttpStatus
.
OK
)
&&
StringUtils
.
isNotBlank
(
originalResponseContentType
)
&&
originalResponseContentType
.
contains
(
CONTENT_TYPE
))
{
Flux
<?
extends
DataBuffer
>
fluxBody
=
Flux
.
from
(
body
);
return
super
.
writeWith
(
fluxBody
.
buffer
().
map
(
dataBuffers
->
{
// 合并多个流集合,解决返回体分段传输
DataBufferFactory
dataBufferFactory
=
new
DefaultDataBufferFactory
();
DataBuffer
join
=
dataBufferFactory
.
join
(
dataBuffers
);
byte
[]
content
=
new
byte
[
join
.
readableByteCount
()];
join
.
read
(
content
);
// 释放掉内存
DataBufferUtils
.
release
(
join
);
String
responseResult
=
new
String
(
content
,
StandardCharsets
.
UTF_8
);
gatewayLog
.
setResponseData
(
responseResult
);
return
bufferFactory
.
wrap
(
content
);
}));
}
}
// if body is not a flux. never got there.
return
super
.
writeWith
(
body
);
}
};
}
/**
* 将map参数转换成url参数
* @param map
* @return
*/
private
String
getUrlParamsByMap
(
MultiValueMap
<
String
,
String
>
map
)
{
if
(
ObjectUtils
.
isEmpty
(
map
))
{
return
""
;
}
StringBuilder
sb
=
new
StringBuilder
();
for
(
Map
.
Entry
<
String
,
List
<
String
>>
entry
:
map
.
entrySet
())
{
sb
.
append
(
entry
.
getKey
()).
append
(
"="
).
append
(
entry
.
getValue
().
get
(
0
));
sb
.
append
(
"&"
);
}
String
s
=
sb
.
toString
();
if
(
s
.
endsWith
(
"&"
))
{
s
=
StringUtils
.
substringBeforeLast
(
s
,
"&"
);
}
return
s
;
}
}
arch-gateway/src/main/java/org/arch/config/LoginFilter.java
0 → 100644
View file @
2c8ec2b
package
org
.
arch
.
config
;
import
com.alibaba.cloud.commons.lang.StringUtils
;
import
net.minidev.json.JSONObject
;
import
org.arch.service.RedisService
;
import
org.arch.util.JwtUtil
;
import
org.slf4j.Logger
;
import
org.slf4j.LoggerFactory
;
import
org.springframework.beans.factory.annotation.Autowired
;
import
org.springframework.beans.factory.annotation.Value
;
import
org.springframework.cloud.gateway.filter.GatewayFilterChain
;
import
org.springframework.cloud.gateway.filter.GlobalFilter
;
import
org.springframework.core.Ordered
;
import
org.springframework.core.io.buffer.DataBuffer
;
import
org.springframework.http.server.reactive.ServerHttpResponse
;
import
org.springframework.web.server.ServerWebExchange
;
import
reactor.core.publisher.Mono
;
import
java.nio.charset.StandardCharsets
;
import
java.util.concurrent.atomic.AtomicReference
;
// @Component
public
class
LoginFilter
implements
GlobalFilter
,
Ordered
{
private
static
final
Logger
logger
=
LoggerFactory
.
getLogger
(
LoginFilter
.
class
);
// @Value("${isc.serviceValidate}")
// private String isc_serviceValidate;
//
// @Value("${isc.sso_front_home_url}")
// private String isc_sso_front_home_url;
//
// @Value("${isc.start}")
// private boolean iscStart;
@Value
(
"${crypto.key}"
)
private
String
key
;
private
String
charset
=
"UTF-8"
;
@Autowired
private
RedisService
redisService
;
/**
* 执行过滤器中的业务逻辑
* 对请求参数中的access-token进行判断
* 如果存在此参数:代表已经认证成功
* 如果不存在此参数 : 认证失败.
* ServerWebExchange : 相当于请求和响应的上下文(zuul中的RequestContext)
*/
@Override
public
Mono
<
Void
>
filter
(
ServerWebExchange
exchange
,
GatewayFilterChain
chain
)
{
logger
.
info
(
"3:--登录拦截器。。。。。。。。。。。。。。。。。。。。。。。。。。。"
);
//1.获取请求参数access-token--本地系统token
String
authon
=
exchange
.
getRequest
().
getHeaders
().
getFirst
(
"Authorization"
);
//isc令牌
String
ticket
=
exchange
.
getRequest
().
getHeaders
().
getFirst
(
"ticket"
);
//每个接口刷新token,接口调用之前获取新的刷新token,防止截取拿着原token可以无限调用,一个token只能调用一次接口
String
tkv
=
exchange
.
getRequest
().
getHeaders
().
getFirst
(
"tkv"
);
//每个接口的刷新token值
String
method
=
exchange
.
getRequest
().
getMethodValue
();
String
path
=
exchange
.
getRequest
().
getPath
().
toString
();
if
(
method
.
equals
(
"OPTIONS"
)){
logger
.
info
(
"3:--不支持改方法:"
+
method
+
"。。。。。。。。。。。。。。。。。。。。。。。。。。。"
);
return
setUnauthorizedResponse
(
exchange
,
507
,
"error"
);
}
try
{
ServerHttpResponse
response1
=
exchange
.
getResponse
();
// response1.setHeader("Access-Control-Expose-Headers", "File-Name"); //允许头部信息字段设置
// response1.addHeader("Access-Control-Allow-Headers", "File-Name"); //允许头部信息字段设置
response1
.
getHeaders
().
add
(
"Access-Control-Expose-Headers"
,
"File-Name"
);
response1
.
getHeaders
().
add
(
"Access-Control-Allow-Headers"
,
"File-Name"
);
// exchange.getResponse().getHeaders().add("Access-control-Allow-Origin","*");
//本地测试用*。线上打包用线上的ip与访问端口
// response1.getHeaders().add("Access-control-Allow-Origin","*");
if
(
StringUtils
.
isNotBlank
(
tkv
)
&&
StringUtils
.
isNotBlank
(
path
)){
//String preparam= SecureUtil.aes(key.getBytes(charset)).decryptStr(tkv);
//String[] arr = preparam.split("\\|", 4);
//String decryptUrl= arr[0];
//String authonVal= arr[1];
//Date date=new Date();
//LocalDate localDate = LocalDate.now();
//int year=localDate.getYear();
//int month=localDate.getMonthValue();
//String curyearMonth=String.valueOf(year)+String.valueOf(month);
//String ss = Constant.PREFIX_TKV_REFRESH_TOKEN +curyearMonth+":"+authon+":"+path;
//List<String> list=redisService.lRange(ss,0,-1);
//if(path.equals(decryptUrl)){
// if(list!=null&& list.contains(tkv)){
// logger.info("3:同一刷新token多次请求无效。。。。。。。。。。。。。。。。。。。。。。。。。。。");
// return setUnauthorizedResponse(exchange,555,"无效请求-秘钥认证失效 tkv未刷新");
// }
// redisService.lLeftPush(ss, tkv);
// //设置有效期为7天
// redisService.expire(ss,7, TimeUnit.DAYS);
//
//}else {
// logger.info("3:同一刷新token多次请求无效。。。。。。。。。。。。。。。。。。。。。。。。。。。");
// return setUnauthorizedResponse(exchange,555,"无效请求-秘钥认证失效");
//}
}
else
{
logger
.
info
(
"3:同一刷新token多次请求无效。。。。。。。。。。。。。。。。。。。。。。。。。。。"
);
return
setUnauthorizedResponse
(
exchange
,
555
,
"请求无效 tkv为空或请求路径为空"
);
}
}
catch
(
Exception
e
){
return
setUnauthorizedResponse
(
exchange
,
555
,
"请求无效 tkv验证异常"
);
}
//放过一部分接口
AtomicReference
<
Boolean
>
isTrue
=
new
AtomicReference
<>(
false
);
AnonFilterChainDefinitionMap
.
anonUrlList
.
forEach
((
item
)->{
if
(
path
.
contains
(
item
)){
isTrue
.
set
(
true
);
}
});
if
(
isTrue
.
get
()){
//如果存在,继续执行
logger
.
info
(
"3:--登录成功。。。。。。。。。。。。。。。。。。。。。。。。。。。"
);
return
chain
.
filter
(
exchange
);
//继续向下执行
}
/*try {
ServerHttpResponse response1 = exchange.getResponse();
//本地测试用*。线上打包用线上的ip与访问端口
response1.getHeaders().add("Access-control-Allow-Origin","*");
if (StringUtils.isNotBlank(tkv) && StringUtils.isNotBlank(path)){
String preparam= SecureUtil.aes(key.getBytes(charset)).decryptStr(tkv);
String[] arr = preparam.split("\\|", 4);
String decryptUrl= arr[0];
String authonVal= arr[1];
Date date=new Date();
LocalDate localDate = LocalDate.now();
int year=localDate.getYear();
int month=localDate.getMonthValue();
String curyearMonth=String.valueOf(year)+String.valueOf(month);
String ss = Constant.PREFIX_TKV_REFRESH_TOKEN +curyearMonth+":"+authon+":"+path;
List<String> list=redisService.lRange(ss,0,-1);
if(path.equals(decryptUrl)){
if(list!=null&& list.contains(tkv)){
logger.info("3:同一刷新token多次请求无效。。。。。。。。。。。。。。。。。。。。。。。。。。。");
return setUnauthorizedResponse(exchange,555,"无效请求-秘钥认证失效 tkv未刷新");
}
redisService.lLeftPush(ss, tkv);
//设置有效期为7天
redisService.expire(ss,7, TimeUnit.DAYS);
}else {
logger.info("3:同一刷新token多次请求无效。。。。。。。。。。。。。。。。。。。。。。。。。。。");
return setUnauthorizedResponse(exchange,555,"无效请求-秘钥认证失效");
}
} else {
logger.info("3:同一刷新token多次请求无效。。。。。。。。。。。。。。。。。。。。。。。。。。。");
return setUnauthorizedResponse(exchange,555,"请求无效 tkv为空或请求路径为空");
}
}catch (Exception e){
return setUnauthorizedResponse(exchange,555,"请求无效 tkv验证异常");
}*/
//2.判断是否存在
if
(
authon
==
null
||
authon
.
equals
(
""
))
{
//3.如果不存在 : 认证失败
logger
.
info
(
"3:--登录失败。。。。。。。。。。。。。。。。。。。。。。。。。。。"
);
return
setUnauthorizedResponse
(
exchange
,
507
,
"登录状态过期,请重新登录"
);
}
if
(!
JwtUtil
.
verify
(
authon
)){
//3.如果不存在 : 认证失败
logger
.
info
(
"3:--登录失败。。。。。。。。。。。。。。。。。。。。。。。。。。。"
);
return
setUnauthorizedResponse
(
exchange
,
507
,
"登录状态过期,请重新登录"
);
}
/*try {
if(!JwtUtil.verify(authon)){
//3.如果不存在 : 认证失败
logger.info("3:--登录失败。。。。。。。。。。。。。。。。。。。。。。。。。。。");
return setUnauthorizedResponse(exchange,507,"登录状态过期,请重新登录");
}*//*else {
if(iscStart){//带isc
if(StringUtils.isNotBlank(tkv)&&StringUtils.isNotBlank(path)){
String tkval=redisService.get(Constant.PREFIX_SHIRO_REFRESH_TOKEN + authon+":"+path);
if(tkv.equals(tkval)){
ServerHttpResponse response = exchange.getResponse();
JSONObject message = new JSONObject();
message.put("code", 507);
message.put("msg", "请求无效");
byte[] bits = message.toJSONString().getBytes(StandardCharsets.UTF_8);
DataBuffer buffer = response.bufferFactory().wrap(bits);
//指定编码,否则在浏览器中会中文乱码
response.getHeaders().add("Content-Type", "text/plain;charset=UTF-8");
logger.info("3:同一刷新token多次请求无效。。。。。。。。。。。。。。。。。。。。。。。。。。。");
return response.writeWith(Mono.just(buffer));
}
redisService.set(Constant.PREFIX_SHIRO_REFRESH_TOKEN + authon+":"+path, tkv);
}
}
}*//*
ServerHttpResponse response1 = exchange.getResponse();
//本地测试用*。线上打包用线上的ip与访问端口
response1.getHeaders().add("Access-control-Allow-Origin","*");
if (StringUtils.isNotBlank(tkv) && StringUtils.isNotBlank(path)){
String preparam= SecureUtil.aes(key.getBytes(charset)).decryptStr(tkv);
String[] arr = preparam.split("\\|", 4);
String decryptUrl= arr[0];
String authonVal= arr[1];
Date date=new Date();
LocalDate localDate = LocalDate.now();
int year=localDate.getYear();
int month=localDate.getMonthValue();
String curyearMonth=String.valueOf(year)+String.valueOf(month);
String ss = Constant.PREFIX_TKV_REFRESH_TOKEN +curyearMonth+":"+authon+":"+path;
List<String> list=redisService.lRange(ss,0,-1);
if(path.equals(decryptUrl)){
if(list!=null&& list.contains(tkv)){
logger.info("3:同一刷新token多次请求无效。。。。。。。。。。。。。。。。。。。。。。。。。。。");
return setUnauthorizedResponse(exchange,555,"无效请求-秘钥认证失效");
}
redisService.lLeftPush(ss, tkv);
//设置有效期为7天
redisService.expire(ss,7, TimeUnit.DAYS);
}else {
logger.info("3:同一刷新token多次请求无效。。。。。。。。。。。。。。。。。。。。。。。。。。。");
return setUnauthorizedResponse(exchange,555,"无效请求-秘钥认证失效");
}
} else {
logger.info("3:同一刷新token多次请求无效。。。。。。。。。。。。。。。。。。。。。。。。。。。");
return setUnauthorizedResponse(exchange,555,"请求无效");
}
}catch (Exception e){
//3.如果不存在 : 认证失败
logger.info("3:--登录失败。。。。。。。。。。。。。。。。。。。。。。。。。。。");
return setUnauthorizedResponse(exchange,507,"登录状态过期,请重新登录");
}*/
String
user
=
""
;
String
userid
=
""
;
String
errorCode
;
String
errorMessage
;
String
xmlResponse
;
/*判断ticket是否存在,不存在重定向到统一认证客户端*/
//验证isctoken
// if(iscStart){
// if(null == ticket || "".equals(ticket)){
// // /*重定向到统一认证服务端,service参数是业务系统LoginModule请求地址*/
//// httpServletResponse.sendRedirect("http://27.50.21.55:17001/isc_sso/login?service=http://10.138.91.158:8082");
//
// ServerHttpResponse response = exchange.getResponse();
// JSONObject message = new JSONObject();
// message.put("code", 555);
// message.put("msg", "ticket_check_fail");
// byte[] bits = message.toJSONString().getBytes(StandardCharsets.UTF_8);
// DataBuffer buffer = response.bufferFactory().wrap(bits);
// //指定编码,否则在浏览器中会中文乱码
// response.getHeaders().add("Content-Type", "text/plain;charset=UTF-8");
// logger.info("3:--登录失败。。。。。。。。。。。。。。。。。。。。。。。。。。。");
// return response.writeWith(Mono.just(buffer));
// }else{
//// /* ticket校验器 */
//// IscServiceTicketValidator sv = new IscServiceTicketValidator();
//// /*统一认证服务端校验器地址*/
//// sv.setCasValidateUrl(isc_serviceValidate);
////// sv.setCasValidateUrl("http://27.50.21.55:17001/isc_sso/serviceValidate");
//// /*业务系统LoginModule访问地址*/
//// sv.setService(isc_sso_front_home_url);
////// sv.setService("http://10.138.91.158:8082/");
//// /*设置Ticket*/
//// sv.setServiceTicket(ticket);
////
//// /*校验*/
//// try {
//// sv.validate();
//// } catch (SAXException e) {
//// // TODO Auto-generated catch block
//// e.printStackTrace();
//// } catch (ParserConfigurationException e) {
//// // TODO Auto-generated catch block
//// e.printStackTrace();
//// } catch (IOException e) {
//// e.printStackTrace();
//// }
////
//// xmlResponse = sv.getResponse();
//// if(sv.isAuthenticationSuccesful()) {
//// user = sv.getUser();
//// IscSSOUserBean iscSSOUserBean = null;
//// try {
//// /*获取当前用户登录信息*/
//// iscSSOUserBean = IscSSOResourceUtil.transferIscUserBean(user);
//// /*当前登录用户ID*/
//// userid = iscSSOUserBean.getIscUserId();
//// //***************获取用户部门组织信息
////// List<BusinessOrganization> org= orgs.getBusiOrgsByUserId(userid, "c3482d816eb24dbc8b644444dd0fb0db");
////// BusiOrgNode mode= orgs.getAllBusiOrgsById("36776AA83E554E5E8D4A93CC19DA2912");//36776AA83E554E5E8D4A93CC19DA2912
////// System.out.println(userid);
//// //***************
//// /*当前登录用户账号*/
//// String loginName = iscSSOUserBean.getIscUserSourceId();
////// System.out.println(loginName);
//// exchange.getRequest().getHeaders().add("iscUser", userid);
//// logger.info("userinfo >>>>>>>>>>>> "+user);
//// } catch (Exception e) {
//// // TODO Auto-generated catch block
//// e.printStackTrace();
//// }
//// } else {
//// errorCode = sv.getErrorCode();
//// errorMessage = sv.getErrorMessage();
//// ServerHttpResponse response = exchange.getResponse();
//// JSONObject message = new JSONObject();
//// message.put("code", 555);
//// message.put("msg", "ticket_check_fail");
//// byte[] bits = message.toJSONString().getBytes(StandardCharsets.UTF_8);
//// DataBuffer buffer = response.bufferFactory().wrap(bits);
//// //指定编码,否则在浏览器中会中文乱码
//// response.getHeaders().add("Content-Type", "text/plain;charset=UTF-8");
//// logger.info("3:--isctoken验证失败。。。。。。。。。。。。。。。。。。。。。。。。。。。");
//// logger.error("errorInfo -----------> "+errorCode +"\r\n"+errorMessage);
//// return response.writeWith(Mono.just(buffer));
////
//// }
//// userid = "34242567890";
//////// //***************获取用户部门组织信息
////// List<BusinessOrganization> org= orgs.getBusiOrgsByUserId(userid, "c3482d816eb24dbc8b644444dd0fb0db");
////// BusiOrgNode mode= orgs.getAllBusiOrgsById("36776AA83E554E5E8D4A93CC19DA2912");//36776AA83E554E5E8D4A93CC19DA2912
//// System.out.println(userid);
////// //***************
////// /*当前登录用户账号*/
////// String loginName = iscSSOUserBean.getIscUserSourceId();
//////// System.out.println(loginName);
//// exchange.getRequest().getHeaders().add("iscUser", userid);
// }
//
// }
//4.如果存在,继续执行
logger
.
info
(
"3:--登录成功。。。。。。。。。。。。。。。。。。。。。。。。。。。"
);
return
chain
.
filter
(
exchange
);
//继续向下执行
}
/**
* 指定过滤器的执行顺序 , 返回值越小,执行优先级越高
*/
@Override
public
int
getOrder
()
{
return
0
;
}
private
Mono
<
Void
>
setUnauthorizedResponse
(
ServerWebExchange
exchange
,
int
code
,
String
msg
)
{
ServerHttpResponse
response
=
exchange
.
getResponse
();
JSONObject
message
=
new
JSONObject
();
message
.
put
(
"code"
,
code
);
message
.
put
(
"msg"
,
msg
);
byte
[]
bits
=
message
.
toJSONString
().
getBytes
(
StandardCharsets
.
UTF_8
);
DataBuffer
buffer
=
response
.
bufferFactory
().
wrap
(
bits
);
//指定编码,否则在浏览器中会中文乱码
response
.
getHeaders
().
add
(
"Content-Type"
,
"text/plain;charset=UTF-8"
);
return
response
.
writeWith
(
Mono
.
just
(
buffer
));
}
}
\ No newline at end of file
arch-gateway/src/main/java/org/arch/config/OriginFilter_ISC.java
0 → 100644
View file @
2c8ec2b
package
org
.
arch
.
config
;
//package com.it4it.config;
//
//import com.it4it.common.Constant;
//import com.it4it.service.RedisService;
//import com.sgcc.isc.ualogin.client.IscServiceTicketValidator;
//import com.sgcc.isc.ualogin.client.util.IscSSOResourceUtil;
//import com.sgcc.isc.ualogin.client.vo.IscSSOUserBean;
//import org.apache.commons.lang.StringUtils;
//import org.slf4j.Logger;
//import org.slf4j.LoggerFactory;
//import org.springframework.beans.factory.annotation.Autowired;
//import org.springframework.beans.factory.annotation.Value;
//import org.springframework.core.Ordered;
//import org.xml.sax.SAXException;
//
//import javax.servlet.*;
//import javax.servlet.http.HttpServletRequest;
//import javax.servlet.http.HttpServletResponse;
//import javax.xml.parsers.ParserConfigurationException;
//import java.io.IOException;
//import java.util.concurrent.atomic.AtomicReference;
//
////import org.apache.shiro.web.util.WebUtils;
//
////import javax.servlet.*;
//
///**
// * 全局跨域放开
// *
// * @author wliduo[i@dolyw.com]
// * @date 2019/11/26 14:29
// */
////@Component
//public class OriginFilter_ISC implements Filter, Ordered {
//
// /**
// * logger
// */
// private static final Logger logger = LoggerFactory.getLogger(OriginFilter_ISC.class);
//
// @Value("${isc.serviceValidate}")
// private String isc_serviceValidate;
//
// @Value("${isc.sso_front_home_url}")
// private String isc_sso_front_home_url;
//
//
// @Autowired
// private RedisService redisService;
//
// @Override
// public void init(FilterConfig filterConfig) throws ServletException {
// logger.info("初始化全局跨域放开...");
// }
//
// @Override
// public void doFilter(ServletRequest request, ServletResponse response, FilterChain filterChain) throws IOException, ServletException {
//
// logger.info("111:--进入isc过滤器。。。。。。。。。。。。。。。。。。。。。。。。。。。");
// // HttpServletRequest httpServletRequest = WebUtils.toHttp(request);
//// HttpServletResponse httpServletResponse = WebUtils.toHttp(response);
// HttpServletRequest httpServletRequest = (HttpServletRequest)request;
// HttpServletResponse httpServletResponse = (HttpServletResponse)response;
//
// httpServletResponse.setHeader("Access-Control-Allow-Methods", "GET,POST,OPTIONS,PUT,DELETE");
// httpServletResponse.setHeader("Access-Control-Max-Age", "3600");
// httpServletResponse.setHeader("Access-control-Allow-Origin", httpServletRequest.getHeader("Origin"));
// httpServletResponse.setHeader("Access-Control-Allow-Headers", httpServletRequest.getHeader("Access-Control-Request-Headers"));
//// try {
//// IscSSOUserBean userbean2= IscSSOResourceUtil.getIscUserBean(((HttpServletRequest) request).getSession());
//// } catch (Exception e1) {
//// // TODO Auto-generated catch block
//// e1.printStackTrace();
//// }
// String ticket= httpServletRequest.getHeader("ticket");
// String authon=httpServletRequest.getHeader("Authorization"); //Authorization
//// String authon=JwtUtil.getClaim(Authorization, Constant.ACCOUNT);
// String tkv=httpServletRequest.getHeader("tkv"); //每个接口的刷新token值
// String method=httpServletRequest.getMethod();
//
// String uRl=httpServletRequest.getRequestURI();
// String uRl2=httpServletRequest.getRequestURL().toString();
// String uRl3=httpServletRequest.getContextPath();
////
// String user ="";
// String userid="";
// String errorCode;
// String errorMessage ;
// String xmlResponse;
// //httpServletRequest.getParameter("ticket")
// if(uRl.contains("project/download/pdf")){
// filterChain.doFilter(request, response);
// return;
// }
//
//
// if(method.equals("OPTIONS")){
// filterChain.doFilter(request, response);
// return;
// }
//
// AtomicReference<Boolean> isTrue = new AtomicReference<>(false);
// AnonFilterChainDefinitionMap.anonUrlList.forEach((item)->{
// if(uRl.contains(item)){
// isTrue.set(true);
// }
// });
// if(isTrue.get()){
// filterChain.doFilter(request, response);
// }
//
// if(StringUtils.isNotBlank(authon)){
// if(StringUtils.isNotBlank(tkv)&&StringUtils.isNotBlank(uRl)){
// String tkval=redisService.get(Constant.PREFIX_SHIRO_REFRESH_TOKEN + authon+":"+uRl);
// if(tkv.equals(tkval)){
// httpServletResponse.sendError(555, "无效请求");
// filterChain.doFilter(request, response);
// return;
// }
// redisService.set(Constant.PREFIX_SHIRO_REFRESH_TOKEN + authon+":"+uRl, tkv);
// }
// filterChain.doFilter(request, response);
// return;
// }
//
// /*判断ticket是否存在,不存在重定向到统一认证客户端*/
// if(null == ticket || "".equals(ticket)){
//
//// /*重定向到统一认证服务端,service参数是业务系统LoginModule请求地址*/
//// httpServletResponse.sendRedirect("http://27.50.21.55:17001/isc_sso/login?service=http://10.138.91.158:8082");
// httpServletResponse.sendError(555, "ticket_check_fail");
// filterChain.doFilter(request, response);
//// httpServletResponse.setStatus(401, "ticket_check_fail");
// return;
// }else{
// /* ticket校验器 */
// IscServiceTicketValidator sv = new IscServiceTicketValidator();
//
//
// /*统一认证服务端校验器地址*/
// sv.setCasValidateUrl(isc_serviceValidate);
//// sv.setCasValidateUrl("http://27.50.21.55:17001/isc_sso/serviceValidate");
// /*业务系统LoginModule访问地址*/
// sv.setService(isc_sso_front_home_url);
//// sv.setService("http://10.138.91.158:8082/");
// /*设置Ticket*/
// sv.setServiceTicket(ticket);
//
// /*校验*/
// try {
// sv.validate();
// } catch (SAXException e) {
// // TODO Auto-generated catch block
// e.printStackTrace();
// } catch (ParserConfigurationException e) {
// // TODO Auto-generated catch block
// e.printStackTrace();
// }
//
// xmlResponse = sv.getResponse();
// if(sv.isAuthenticationSuccesful()) {
// user = sv.getUser();
// IscSSOUserBean iscSSOUserBean = null;
// try {
// /*获取当前用户登录信息*/
// iscSSOUserBean = IscSSOResourceUtil.transferIscUserBean(user);
// /*当前登录用户ID*/
// userid = iscSSOUserBean.getIscUserId();
// //***************获取用户部门组织信息
//// List<BusinessOrganization> org= orgs.getBusiOrgsByUserId(userid, "c3482d816eb24dbc8b644444dd0fb0db");
//// BusiOrgNode mode= orgs.getAllBusiOrgsById("36776AA83E554E5E8D4A93CC19DA2912");//36776AA83E554E5E8D4A93CC19DA2912
//// System.out.println(userid);
// //***************
// /*当前登录用户账号*/
// String loginName = iscSSOUserBean.getIscUserSourceId();
//// System.out.println(loginName);
// httpServletResponse.setHeader("iscUser", userid);
// logger.info("userinfo >>>>>>>>>>>> "+user);
// } catch (Exception e) {
// // TODO Auto-generated catch block
// e.printStackTrace();
// }
// } else {
// errorCode = sv.getErrorCode();
// errorMessage = sv.getErrorMessage();
// httpServletResponse.sendError(555, "ticket_check_fail");
// /* handle the error */
// logger.error("errorInfo -----------> "+errorCode +"\r\n"+errorMessage);
//// return;
// }
//
//
// }
//
//
//
//
//
// filterChain.doFilter(request, response);
// }
//
// @Override
// public void destroy() {
//
// }
//
//// @Override
//// public void destroy() { }
//
//
// @Override
// public int getOrder() {
// return 1;
// }
//
//
//}
arch-gateway/src/main/java/org/arch/config/ParamsEncryptionFilter.java
0 → 100644
View file @
2c8ec2b
package
org
.
arch
.
config
;
import
cn.hutool.crypto.symmetric.AES
;
import
com.alibaba.fastjson.JSON
;
import
com.alibaba.fastjson.JSONObject
;
import
io.netty.buffer.ByteBufAllocator
;
import
lombok.SneakyThrows
;
import
org.springframework.beans.factory.annotation.Value
;
import
org.springframework.cloud.gateway.filter.GatewayFilterChain
;
import
org.springframework.cloud.gateway.filter.GlobalFilter
;
import
org.springframework.core.Ordered
;
import
org.springframework.core.io.buffer.DataBuffer
;
import
org.springframework.core.io.buffer.DataBufferUtils
;
import
org.springframework.core.io.buffer.NettyDataBufferFactory
;
import
org.springframework.http.HttpHeaders
;
import
org.springframework.http.HttpMethod
;
import
org.springframework.http.MediaType
;
import
org.springframework.http.server.reactive.ServerHttpRequest
;
import
org.springframework.http.server.reactive.ServerHttpRequestDecorator
;
import
org.springframework.util.MultiValueMap
;
import
org.springframework.web.server.ServerWebExchange
;
import
org.springframework.web.util.UriComponentsBuilder
;
import
reactor.core.publisher.Flux
;
import
reactor.core.publisher.Mono
;
import
java.io.UnsupportedEncodingException
;
import
java.net.URI
;
import
java.net.URLDecoder
;
import
java.nio.CharBuffer
;
import
java.nio.charset.StandardCharsets
;
import
java.util.HashMap
;
import
java.util.List
;
import
java.util.Map
;
import
java.util.concurrent.atomic.AtomicReference
;
/**
* 解密过滤器
* @author zg_xl920
* @create 2022-05-26 15:47
*/
//@Component
public
class
ParamsEncryptionFilter
implements
GlobalFilter
,
Ordered
{
@Value
(
"${crypto.key}"
)
private
String
key
;
@SneakyThrows
@Override
public
Mono
<
Void
>
filter
(
ServerWebExchange
exchange
,
GatewayFilterChain
chain
)
{
AES
aes
=
new
AES
(
key
.
getBytes
());
ServerHttpRequest
serverHttpRequest
=
exchange
.
getRequest
();
HttpMethod
method
=
serverHttpRequest
.
getMethod
();
URI
uri
=
serverHttpRequest
.
getURI
();
//过滤上传文件的接口,不做解密处理
if
(
uri
.
toString
().
contains
(
"upload"
)){
return
chain
.
filter
(
exchange
);
}
MediaType
mediaType
=
serverHttpRequest
.
getHeaders
().
getContentType
();
if
(
method
==
HttpMethod
.
POST
){
//从请求里获取post请求体
String
bodyStr
=
resolveBodyFromRequest
(
serverHttpRequest
);
//密文参数
String
cipherParams
=
""
;
//明文参数
String
plainParams
=
""
;
if
(
bodyStr
!=
null
){
plainParams
=
aes
.
decryptStr
(
bodyStr
);
}
ServerHttpRequest
request
=
serverHttpRequest
.
mutate
().
uri
(
uri
).
build
();
DataBuffer
bodyDataBuffer
=
stringBuffer
(
plainParams
);
Flux
<
DataBuffer
>
bodyFlux
=
Flux
.
just
(
bodyDataBuffer
);
request
=
new
ServerHttpRequestDecorator
(
request
){
@Override
public
Flux
<
DataBuffer
>
getBody
()
{
return
bodyFlux
;
}
};
//构建新的请求头
HttpHeaders
headers
=
new
HttpHeaders
();
headers
.
putAll
(
exchange
.
getRequest
().
getHeaders
());
// 重新设置CONTENT_LENGTH
int
length
=
plainParams
.
getBytes
().
length
;
headers
.
remove
(
HttpHeaders
.
CONTENT_LENGTH
);
headers
.
setContentLength
(
length
);
request
=
new
ServerHttpRequestDecorator
(
request
){
@Override
public
HttpHeaders
getHeaders
()
{
return
headers
;
}
};
return
chain
.
filter
(
exchange
.
mutate
().
request
(
request
).
build
());
}
else
if
(
method
==
HttpMethod
.
GET
){
MultiValueMap
<
String
,
String
>
requestQueryParams
=
serverHttpRequest
.
getQueryParams
();
//String rawQuery = uri.getRawQuery();
//
//String query = uri.getQuery();
if
(
requestQueryParams
.
isEmpty
()){
return
chain
.
filter
(
exchange
);
}
//String params = requestQueryParams.get("0").get(0);
//String first = requestQueryParams.getFirst("0");
//解密
//params = aes.decryptStr(params);
Map
<
String
,
Object
>
map
=
this
.
dealGetRequestDecode
(
requestQueryParams
,
aes
);
if
(
map
.
isEmpty
()){
return
chain
.
filter
(
exchange
);
}
String
stringParams
=
stringParams
(
map
);
URI
newUri
=
UriComponentsBuilder
.
fromUri
(
uri
)
.
replaceQuery
(
stringParams
)
.
build
()
.
toUri
();
//封装url
//URI plaintUrl = new URI(uri.getScheme(), uri.getAuthority(), uri.getPath(), params, uri.getFragment());
//封装request,传给下一级
ServerHttpRequest
request
=
serverHttpRequest
.
mutate
().
uri
(
newUri
).
build
();
return
chain
.
filter
(
exchange
.
mutate
().
request
(
request
).
build
());
}
return
chain
.
filter
(
exchange
);
}
/**
* 前端get请求 加密之后需要解码请求参数
* @param requestQueryParams
* @param aes
* @return
*/
private
Map
<
String
,
Object
>
dealGetRequestDecode
(
MultiValueMap
<
String
,
String
>
requestQueryParams
,
AES
aes
){
Map
<
String
,
Object
>
paras
=
new
HashMap
<>();
requestQueryParams
.
forEach
((
paramKey
,
encryptValue
)
->
{
for
(
String
s
:
encryptValue
)
{
String
params
=
aes
.
decryptStr
(
s
);
JSONObject
jsonObject
=
JSON
.
parseObject
(
params
);
jsonObject
.
forEach
((
name
,
value
)
->
{
paras
.
put
(
name
,
value
);
});
}
});
return
paras
;
}
/**
* 拼接路径参数
* @param params
* @return
*/
public
String
stringParams
(
Map
<
String
,
Object
>
params
)
{
StringBuffer
sb
=
new
StringBuffer
();
for
(
Map
.
Entry
<
String
,
Object
>
param
:
params
.
entrySet
())
{
if
(
param
.
getValue
()
instanceof
List
)
{
List
<
Object
>
listObj
=
(
List
<
Object
>)
param
.
getValue
();
for
(
Object
obj
:
listObj
)
{
if
(
sb
.
length
()
>
0
)
{
sb
.
append
(
"&"
);
}
sb
.
append
(
param
.
getKey
()
+
"="
+
obj
.
toString
());
}
}
else
{
// String Int Long Dobule 之类的
if
(
sb
.
length
()
>
0
)
{
sb
.
append
(
"&"
);
}
sb
.
append
(
param
.
getKey
()
+
"="
+
param
.
getValue
().
toString
());
}
}
return
sb
.
toString
();
}
/**
* 解密过滤器必须在所有过滤器之前,否则后续过滤器获取参数会报错
* 如果有的其他的过滤器添加请调整过滤器顺序
* @return
*/
@Override
public
int
getOrder
()
{
return
-
1
;
}
/**
* 根据请求方法类型获取密文
* @param bodyStr
* @param mediaType
* @return
* @throws UnsupportedEncodingException
*/
private
String
getCiphertextByMediaType
(
String
bodyStr
,
MediaType
mediaType
)
throws
UnsupportedEncodingException
{
/*if (mediaType.equals(MediaType.APPLICATION_JSON)){
JSONObject bodyJson = JSONObject.parseObject(bodyStr);
return bodyJson.getString("params");
}*/
if
(
mediaType
.
equals
(
MediaType
.
MULTIPART_FORM_DATA
)
||
mediaType
.
equals
(
MediaType
.
APPLICATION_FORM_URLENCODED
)){
Map
<
String
,
String
>
keyValues
=
urlSplit
(
bodyStr
);
return
URLDecoder
.
decode
(
keyValues
.
get
(
"params"
),
"UTF-8"
);
}
else
{
return
"-1"
;
}
}
/**
* 解析出url参数中的键值对
* 如 "Action=del&id=123",解析出Action:del,id:123存入map中
*
* @param params url地址
* @return url请求参数部分
*/
private
static
Map
<
String
,
String
>
urlSplit
(
String
params
)
{
Map
<
String
,
String
>
mapRequest
=
new
HashMap
<>();
String
[]
arrSplit
=
null
;
if
(
params
==
null
)
{
return
mapRequest
;
}
arrSplit
=
params
.
split
(
"[&]"
);
for
(
String
strSplit
:
arrSplit
)
{
String
[]
arrSplitEqual
=
null
;
arrSplitEqual
=
strSplit
.
split
(
"[=]"
);
//解析出键值
if
(
arrSplitEqual
.
length
>
1
)
{
//正确解析
mapRequest
.
put
(
arrSplitEqual
[
0
],
arrSplitEqual
[
1
]);
}
else
if
(
arrSplitEqual
[
0
]
!=
""
)
{
//只有参数没有值,不加入
mapRequest
.
put
(
arrSplitEqual
[
0
],
""
);
}
}
return
mapRequest
;
}
private
String
resolveBodyFromRequest
(
ServerHttpRequest
serverHttpRequest
)
{
//获取请求体
Flux
<
DataBuffer
>
body
=
serverHttpRequest
.
getBody
();
AtomicReference
<
String
>
bodyRef
=
new
AtomicReference
<>();
body
.
subscribe
(
buffer
->
{
CharBuffer
charBuffer
=
StandardCharsets
.
UTF_8
.
decode
(
buffer
.
asByteBuffer
());
DataBufferUtils
.
release
(
buffer
);
bodyRef
.
set
(
charBuffer
.
toString
());
});
//获取request body
return
bodyRef
.
get
();
}
private
DataBuffer
stringBuffer
(
String
value
)
{
byte
[]
bytes
=
value
.
getBytes
(
StandardCharsets
.
UTF_8
);
NettyDataBufferFactory
nettyDataBufferFactory
=
new
NettyDataBufferFactory
(
ByteBufAllocator
.
DEFAULT
);
DataBuffer
buffer
=
nettyDataBufferFactory
.
allocateBuffer
(
bytes
.
length
);
buffer
.
write
(
bytes
);
return
buffer
;
}
}
arch-gateway/src/main/java/org/arch/config/ParamsSM4EncryptionFilter.java
0 → 100644
View file @
2c8ec2b
package
org
.
arch
.
config
;
import
cn.hutool.core.util.StrUtil
;
import
com.alibaba.fastjson2.JSONObject
;
import
com.eadc.config.sm4jm.SM4Utils
;
import
org.springframework.beans.factory.annotation.Value
;
import
org.springframework.boot.autoconfigure.condition.ConditionalOnProperty
;
import
org.springframework.cloud.gateway.filter.GatewayFilterChain
;
import
org.springframework.cloud.gateway.filter.GlobalFilter
;
import
org.springframework.core.Ordered
;
import
org.springframework.http.HttpMethod
;
import
org.springframework.http.HttpStatus
;
import
org.springframework.http.server.reactive.ServerHttpRequest
;
import
org.springframework.http.server.reactive.ServerHttpResponse
;
import
org.springframework.stereotype.Component
;
import
org.springframework.web.server.ServerWebExchange
;
import
reactor.core.publisher.Mono
;
/**
* 国网SM4加密
*/
@Component
@ConditionalOnProperty
(
value
=
"sm4.enable"
,
havingValue
=
"true"
)
public
class
ParamsSM4EncryptionFilter
implements
GlobalFilter
,
Ordered
{
@Value
(
"${sm4.CBCSecretKey}"
)
private
String
CBCSecretKey
;
@Value
(
"${sm4.CBCIV}"
)
private
String
CBCIV
;
@Override
public
Mono
<
Void
>
filter
(
ServerWebExchange
exchange
,
GatewayFilterChain
chain
)
{
ServerHttpRequest
serverHttpRequest
=
exchange
.
getRequest
();
HttpMethod
method
=
serverHttpRequest
.
getMethod
();
String
uri
=
serverHttpRequest
.
getURI
().
toString
();
if
(
uri
.
contains
(
"upload"
)
||
method
!=
HttpMethod
.
POST
)
{
return
chain
.
filter
(
exchange
);
}
String
bodyStr
=
serverHttpRequest
.
getBody
().
toString
();
String
plainParams
=
SM4Utils
.
decryptData_CBC
(
bodyStr
,
CBCSecretKey
,
CBCIV
);
if
(
StrUtil
.
isBlank
(
plainParams
))
{
return
errorResponse
(
exchange
,
"已开启加密模式,请先加密"
);
}
return
chain
.
filter
(
exchange
);
}
private
Mono
<
Void
>
errorResponse
(
ServerWebExchange
exchange
,
String
message
)
{
ServerHttpResponse
response
=
exchange
.
getResponse
();
response
.
setStatusCode
(
HttpStatus
.
BAD_REQUEST
);
response
.
getHeaders
().
add
(
"Content-Type"
,
"application/json;charset=UTF-8"
);
JSONObject
json
=
new
JSONObject
();
json
.
put
(
"code"
,
500
);
json
.
put
(
"msg"
,
message
);
json
.
put
(
"data"
,
""
);
return
response
.
writeWith
(
Mono
.
just
(
response
.
bufferFactory
().
wrap
(
json
.
toString
().
getBytes
())));
}
@Override
public
int
getOrder
()
{
return
-
1
;
}
}
\ No newline at end of file
arch-gateway/src/main/java/org/arch/config/fileFilter/FileUploadInterceptor.java
0 → 100644
View file @
2c8ec2b
package
org
.
arch
.
config
.
fileFilter
;
import
org.springframework.cloud.gateway.filter.GatewayFilterChain
;
import
org.springframework.cloud.gateway.filter.GlobalFilter
;
import
org.springframework.http.HttpStatus
;
import
org.springframework.http.MediaType
;
import
org.springframework.http.server.reactive.ServerHttpRequest
;
import
org.springframework.http.server.reactive.ServerHttpResponse
;
import
org.springframework.web.server.ServerWebExchange
;
import
reactor.core.publisher.Mono
;
import
java.nio.charset.StandardCharsets
;
/**
* 限值文件上传
*/
public
class
FileUploadInterceptor
implements
GlobalFilter
{
@Override
public
Mono
<
Void
>
filter
(
ServerWebExchange
exchange
,
GatewayFilterChain
chain
)
{
ServerHttpRequest
request
=
exchange
.
getRequest
();
// 检查请求是否包含文件
if
(
request
.
getHeaders
().
getContentType
()
!=
null
&&
request
.
getHeaders
().
getContentType
().
includes
(
MediaType
.
MULTIPART_FORM_DATA
))
{
// 文件上传拦截逻辑
ServerHttpResponse
response
=
exchange
.
getResponse
();
response
.
setStatusCode
(
HttpStatus
.
UNAUTHORIZED
);
response
.
getHeaders
().
setContentType
(
MediaType
.
TEXT_PLAIN
);
return
response
.
writeWith
(
Mono
.
just
(
response
.
bufferFactory
().
wrap
(
"File upload is not allowed."
.
getBytes
(
StandardCharsets
.
UTF_8
))));
}
// 继续过滤器链
return
chain
.
filter
(
exchange
);
}
}
\ No newline at end of file
arch-gateway/src/main/java/org/arch/config/fileFilter/FileUploadSizeLimitFilter.java
0 → 100644
View file @
2c8ec2b
package
org
.
arch
.
config
.
fileFilter
;
import
org.springframework.cloud.gateway.filter.GatewayFilterChain
;
import
org.springframework.cloud.gateway.filter.GlobalFilter
;
import
org.springframework.core.io.buffer.DataBufferUtils
;
import
org.springframework.http.MediaType
;
import
org.springframework.http.server.reactive.ServerHttpRequest
;
import
org.springframework.http.server.reactive.ServerHttpResponse
;
import
org.springframework.web.server.ServerWebExchange
;
import
reactor.core.publisher.Mono
;
import
java.util.Objects
;
/**
* 文件上传大小限制
*/
public
class
FileUploadSizeLimitFilter
implements
GlobalFilter
{
private
final
int
maxFileSize
=
100
*
1024
*
1024
;
// 设置最大文件大小为100MB
@Override
public
Mono
<
Void
>
filter
(
ServerWebExchange
exchange
,
GatewayFilterChain
chain
)
{
ServerHttpRequest
request
=
exchange
.
getRequest
();
// 如果是POST请求且内容类型是multipart/form-data,则检查文件大小
if
(
"POST"
.
equals
(
request
.
getMethodValue
())
&&
request
.
getHeaders
().
getContentType
().
includes
(
MediaType
.
MULTIPART_FORM_DATA
))
{
return
DataBufferUtils
.
join
(
exchange
.
getRequest
().
getBody
())
.
flatMap
(
dataBuffer
->
{
try
{
// 此处可以获取文件数据,进行大小校验
// 示例仅为检查是否超出最大文件大小
long
contentLength
=
request
.
getHeaders
().
getContentLength
();
if
(!
Objects
.
isNull
(
contentLength
)
&&
contentLength
>
maxFileSize
)
{
ServerHttpResponse
response
=
exchange
.
getResponse
();
response
.
setStatusCode
(
org
.
springframework
.
http
.
HttpStatus
.
PAYLOAD_TOO_LARGE
);
// 可以返回错误信息到客户端
return
response
.
writeWith
(
Mono
.
just
(
response
.
bufferFactory
().
wrap
(
"File size exceeds the maximum allowed limit."
.
getBytes
()))
);
}
}
catch
(
Exception
e
)
{
// 处理异常
}
return
chain
.
filter
(
exchange
);
});
}
return
chain
.
filter
(
exchange
);
}
}
\ No newline at end of file
arch-gateway/src/main/java/org/arch/config/fileFilter/FilterConfig.java
0 → 100644
View file @
2c8ec2b
package
org
.
arch
.
config
.
fileFilter
;
import
org.springframework.cloud.gateway.filter.GlobalFilter
;
import
org.springframework.context.annotation.Bean
;
//@Configuration
public
class
FilterConfig
{
@Bean
public
GlobalFilter
fileUploadSizeLimitFilter
()
{
return
new
FileUploadSizeLimitFilter
();
}
}
\ No newline at end of file
arch-gateway/src/main/java/org/arch/config/fileFilter/WebFileConfig.java
0 → 100644
View file @
2c8ec2b
package
org
.
arch
.
config
.
fileFilter
;
//package com.eadc.config.fileFilter;
//
//import org.springframework.beans.factory.annotation.Autowired;
//import org.springframework.context.annotation.Configuration;
//import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
//import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
//
///**
// * 注册文件上传拦截器(做文件上传安全漏洞扫描使用)
// *
// */
////@Configuration
//public class WebFileConfig implements WebMvcConfigurer {
//
// @Autowired
// private FileUploadInterceptor fileUploadInterceptor;
//
// @Override
// public void addInterceptors(InterceptorRegistry registry) {
// registry.addInterceptor(fileUploadInterceptor)
// .addPathPatterns("/upload/**"); // 指定需要拦截的路径模式
// }
//}
arch-gateway/src/main/java/org/arch/config/sm4jm/ByteConvertUtil.java
0 → 100644
View file @
2c8ec2b
package
org
.
arch
.
config
.
sm4jm
;
import
java.math.BigInteger
;
public
class
ByteConvertUtil
{
/**
* 整形转换成网络传输的字节流(字节数组)型数据
*
* @param num 一个整型数据
* @return 4个字节的自己数组
*/
public
static
byte
[]
intToBytes
(
int
num
)
{
byte
[]
bytes
=
new
byte
[
4
];
bytes
[
0
]
=
(
byte
)
(
0xff
&
(
num
>>
0
));
bytes
[
1
]
=
(
byte
)
(
0xff
&
(
num
>>
8
));
bytes
[
2
]
=
(
byte
)
(
0xff
&
(
num
>>
16
));
bytes
[
3
]
=
(
byte
)
(
0xff
&
(
num
>>
24
));
return
bytes
;
}
/**
* 四个字节的字节数据转换成一个整形数据
*
* @param bytes 4个字节的字节数组
* @return 一个整型数据
*/
public
static
int
byteToInt
(
byte
[]
bytes
)
{
int
num
=
0
;
int
temp
;
temp
=
(
0x000000ff
&
(
bytes
[
0
]))
<<
0
;
num
=
num
|
temp
;
temp
=
(
0x000000ff
&
(
bytes
[
1
]))
<<
8
;
num
=
num
|
temp
;
temp
=
(
0x000000ff
&
(
bytes
[
2
]))
<<
16
;
num
=
num
|
temp
;
temp
=
(
0x000000ff
&
(
bytes
[
3
]))
<<
24
;
num
=
num
|
temp
;
return
num
;
}
/**
* 长整形转换成网络传输的字节流(字节数组)型数据
*
* @param num 一个长整型数据
* @return 4个字节的自己数组
*/
public
static
byte
[]
longToBytes
(
long
num
)
{
byte
[]
bytes
=
new
byte
[
8
];
for
(
int
i
=
0
;
i
<
8
;
i
++)
{
bytes
[
i
]
=
(
byte
)
(
0xff
&
(
num
>>
(
i
*
8
)));
}
return
bytes
;
}
/**
* 大数字转换字节流(字节数组)型数据
*
* @param n
* @return
*/
public
static
byte
[]
byteConvert32Bytes
(
BigInteger
n
)
{
byte
[]
tmp
;
if
(
n
==
null
)
{
return
null
;
}
if
(
n
.
toByteArray
().
length
==
33
)
{
tmp
=
new
byte
[
32
];
System
.
arraycopy
(
n
.
toByteArray
(),
1
,
tmp
,
0
,
32
);
}
else
if
(
n
.
toByteArray
().
length
==
32
)
{
tmp
=
n
.
toByteArray
();
}
else
{
tmp
=
new
byte
[
32
];
for
(
int
i
=
0
;
i
<
32
-
n
.
toByteArray
().
length
;
i
++)
{
tmp
[
i
]
=
0
;
}
System
.
arraycopy
(
n
.
toByteArray
(),
0
,
tmp
,
32
-
n
.
toByteArray
().
length
,
n
.
toByteArray
().
length
);
}
return
tmp
;
}
/**
* 换字节流(字节数组)型数据转大数字
*
* @param b
* @return
*/
public
static
BigInteger
byteConvertInteger
(
byte
[]
b
)
{
if
(
b
[
0
]
<
0
)
{
byte
[]
temp
=
new
byte
[
b
.
length
+
1
];
temp
[
0
]
=
0
;
System
.
arraycopy
(
b
,
0
,
temp
,
1
,
b
.
length
);
return
new
BigInteger
(
temp
);
}
return
new
BigInteger
(
b
);
}
/**
* 根据字节数组获得值(十六进制数字)
*
* @param bytes
* @return
*/
public
static
String
getHexString
(
byte
[]
bytes
)
{
return
getHexString
(
bytes
,
true
);
}
/**
* 根据字节数组获得值(十六进制数字)
*
* @param bytes
* @param upperCase
* @return
*/
public
static
String
getHexString
(
byte
[]
bytes
,
boolean
upperCase
)
{
StringBuilder
ret
=
new
StringBuilder
();
for
(
byte
aByte
:
bytes
)
{
ret
.
append
(
Integer
.
toString
((
aByte
&
0xff
)
+
0x100
,
16
).
substring
(
1
));
}
return
upperCase
?
ret
.
toString
().
toUpperCase
()
:
ret
.
toString
();
}
/**
* 打印十六进制字符串
*
* @param bytes
*/
public
static
void
printHexString
(
byte
[]
bytes
)
{
for
(
byte
aByte
:
bytes
)
{
String
hex
=
Integer
.
toHexString
(
aByte
&
0xFF
);
if
(
hex
.
length
()
==
1
)
{
hex
=
'0'
+
hex
;
}
System
.
out
.
print
(
"0x"
+
hex
.
toUpperCase
()
+
","
);
}
}
/**
* Convert hex string to byte[]
*
* @param hexString the hex string
* @return byte[]
*/
public
static
byte
[]
hexStringToBytes
(
String
hexString
)
{
if
(
hexString
==
null
||
""
.
equals
(
hexString
))
{
return
null
;
}
hexString
=
hexString
.
toUpperCase
();
int
length
=
hexString
.
length
()
/
2
;
char
[]
hexChars
=
hexString
.
toCharArray
();
byte
[]
d
=
new
byte
[
length
];
for
(
int
i
=
0
;
i
<
length
;
i
++)
{
int
pos
=
i
*
2
;
d
[
i
]
=
(
byte
)
(
charToByte
(
hexChars
[
pos
])
<<
4
|
charToByte
(
hexChars
[
pos
+
1
]));
}
return
d
;
}
/**
* Convert char to byte
*
* @param c char
* @return byte
*/
public
static
byte
charToByte
(
char
c
)
{
return
(
byte
)
"0123456789ABCDEF"
.
indexOf
(
c
);
}
/**
* 用于建立十六进制字符的输出的小写字符数组
*/
private
static
final
char
[]
DIGITS_LOWER
=
{
'0'
,
'1'
,
'2'
,
'3'
,
'4'
,
'5'
,
'6'
,
'7'
,
'8'
,
'9'
,
'a'
,
'b'
,
'c'
,
'd'
,
'e'
,
'f'
};
/**
* 用于建立十六进制字符的输出的大写字符数组
*/
private
static
final
char
[]
DIGITS_UPPER
=
{
'0'
,
'1'
,
'2'
,
'3'
,
'4'
,
'5'
,
'6'
,
'7'
,
'8'
,
'9'
,
'A'
,
'B'
,
'C'
,
'D'
,
'E'
,
'F'
};
/**
* 将字节数组转换为十六进制字符数组
*
* @param data byte[]
* @return 十六进制char[]
*/
public
static
char
[]
encodeHex
(
byte
[]
data
)
{
return
encodeHex
(
data
,
true
);
}
/**
* 将字节数组转换为十六进制字符数组
*
* @param data byte[]
* @param toLowerCase <code>true</code> 传换成小写格式 , <code>false</code> 传换成大写格式
* @return 十六进制char[]
*/
public
static
char
[]
encodeHex
(
byte
[]
data
,
boolean
toLowerCase
)
{
return
encodeHex
(
data
,
toLowerCase
?
DIGITS_LOWER
:
DIGITS_UPPER
);
}
/**
* 将字节数组转换为十六进制字符数组
*
* @param data byte[]
* @param toDigits 用于控制输出的char[]
* @return 十六进制char[]
*/
protected
static
char
[]
encodeHex
(
byte
[]
data
,
char
[]
toDigits
)
{
int
l
=
data
.
length
;
char
[]
out
=
new
char
[
l
<<
1
];
// two characters form the hex value.
for
(
int
i
=
0
,
j
=
0
;
i
<
l
;
i
++)
{
out
[
j
++]
=
toDigits
[(
0xF0
&
data
[
i
])
>>>
4
];
out
[
j
++]
=
toDigits
[
0x0F
&
data
[
i
]];
}
return
out
;
}
/**
* 将字节数组转换为十六进制字符串
*
* @param data byte[]
* @return 十六进制String
*/
public
static
String
encodeHexString
(
byte
[]
data
)
{
return
encodeHexString
(
data
,
true
);
}
/**
* 将字节数组转换为十六进制字符串
*
* @param data byte[]
* @param toLowerCase <code>true</code> 传换成小写格式 , <code>false</code> 传换成大写格式
* @return 十六进制String
*/
public
static
String
encodeHexString
(
byte
[]
data
,
boolean
toLowerCase
)
{
return
encodeHexString
(
data
,
toLowerCase
?
DIGITS_LOWER
:
DIGITS_UPPER
);
}
/**
* 将字节数组转换为十六进制字符串
*
* @param data byte[]
* @param toDigits 用于控制输出的char[]
* @return 十六进制String
*/
protected
static
String
encodeHexString
(
byte
[]
data
,
char
[]
toDigits
)
{
return
new
String
(
encodeHex
(
data
,
toDigits
));
}
/**
* 将十六进制字符数组转换为字节数组
*
* @param data 十六进制char[]
* @return byte[]
* @throws RuntimeException 如果源十六进制字符数组是一个奇怪的长度,将抛出运行时异常
*/
public
static
byte
[]
decodeHex
(
char
[]
data
)
{
int
len
=
data
.
length
;
if
((
len
&
0x01
)
!=
0
)
{
throw
new
RuntimeException
(
"Odd number of characters."
);
}
byte
[]
out
=
new
byte
[
len
>>
1
];
// two characters form the hex value.
for
(
int
i
=
0
,
j
=
0
;
j
<
len
;
i
++)
{
int
f
=
toDigit
(
data
[
j
],
j
)
<<
4
;
j
++;
f
=
f
|
toDigit
(
data
[
j
],
j
);
j
++;
out
[
i
]
=
(
byte
)
(
f
&
0xFF
);
}
return
out
;
}
/**
* 将十六进制字符转换成一个整数
*
* @param ch 十六进制char
* @param index 十六进制字符在字符数组中的位置
* @return 一个整数
* @throws RuntimeException 当ch不是一个合法的十六进制字符时,抛出运行时异常
*/
protected
static
int
toDigit
(
char
ch
,
int
index
)
{
int
digit
=
Character
.
digit
(
ch
,
16
);
if
(
digit
==
-
1
)
{
throw
new
RuntimeException
(
"Illegal hexadecimal character "
+
ch
+
" at index "
+
index
);
}
return
digit
;
}
/**
* 数字字符串转ASCII码字符串
*
* @param content 字符串
* @return ASCII字符串
*/
public
static
String
StringToAsciiString
(
String
content
)
{
StringBuilder
result
=
new
StringBuilder
();
int
max
=
content
.
length
();
for
(
int
i
=
0
;
i
<
max
;
i
++)
{
char
c
=
content
.
charAt
(
i
);
String
b
=
Integer
.
toHexString
(
c
);
result
.
append
(
b
);
}
return
result
.
toString
();
}
/**
* 十六进制转字符串
*
* @param hexString 十六进制字符串
* @param encodeType 编码类型4:Unicode,2:普通编码
* @return 字符串
*/
public
static
String
hexStringToString
(
String
hexString
,
int
encodeType
)
{
StringBuilder
result
=
new
StringBuilder
();
int
max
=
hexString
.
length
()
/
encodeType
;
for
(
int
i
=
0
;
i
<
max
;
i
++)
{
char
c
=
(
char
)
hexStringToAlgorism
(
hexString
.
substring
(
i
*
encodeType
,
(
i
+
1
)
*
encodeType
));
result
.
append
(
c
);
}
return
result
.
toString
();
}
/**
* 十六进制字符串装十进制
*
* @param hex 十六进制字符串
* @return 十进制数值
*/
public
static
int
hexStringToAlgorism
(
String
hex
)
{
hex
=
hex
.
toUpperCase
();
int
max
=
hex
.
length
();
int
result
=
0
;
for
(
int
i
=
max
;
i
>
0
;
i
--)
{
char
c
=
hex
.
charAt
(
i
-
1
);
int
algorism
;
if
(
c
>=
'0'
&&
c
<=
'9'
)
{
algorism
=
c
-
'0'
;
}
else
{
algorism
=
c
-
55
;
}
result
+=
Math
.
pow
(
16
,
max
-
i
)
*
algorism
;
}
return
result
;
}
/**
* 十六转二进制
*
* @param hex 十六进制字符串
* @return 二进制字符串
*/
public
static
String
hexStringToBinary
(
String
hex
)
{
hex
=
hex
.
toUpperCase
();
StringBuilder
result
=
new
StringBuilder
();
int
max
=
hex
.
length
();
for
(
int
i
=
0
;
i
<
max
;
i
++)
{
char
c
=
hex
.
charAt
(
i
);
switch
(
c
)
{
case
'0'
:
result
.
append
(
"0000"
);
break
;
case
'1'
:
result
.
append
(
"0001"
);
break
;
case
'2'
:
result
.
append
(
"0010"
);
break
;
case
'3'
:
result
.
append
(
"0011"
);
break
;
case
'4'
:
result
.
append
(
"0100"
);
break
;
case
'5'
:
result
.
append
(
"0101"
);
break
;
case
'6'
:
result
.
append
(
"0110"
);
break
;
case
'7'
:
result
.
append
(
"0111"
);
break
;
case
'8'
:
result
.
append
(
"1000"
);
break
;
case
'9'
:
result
.
append
(
"1001"
);
break
;
case
'A'
:
result
.
append
(
"1010"
);
break
;
case
'B'
:
result
.
append
(
"1011"
);
break
;
case
'C'
:
result
.
append
(
"1100"
);
break
;
case
'D'
:
result
.
append
(
"1101"
);
break
;
case
'E'
:
result
.
append
(
"1110"
);
break
;
case
'F'
:
result
.
append
(
"1111"
);
break
;
default
:
System
.
out
.
println
(
"hexStringToBinary无匹配项"
);
break
;
}
}
return
result
.
toString
();
}
/**
* ASCII码字符串转数字字符串
*
* @param content ASCII字符串
* @return 字符串
*/
public
static
String
AsciiStringToString
(
String
content
)
{
StringBuilder
result
=
new
StringBuilder
();
int
length
=
content
.
length
()
/
2
;
for
(
int
i
=
0
;
i
<
length
;
i
++)
{
String
c
=
content
.
substring
(
i
*
2
,
i
*
2
+
2
);
int
a
=
hexStringToAlgorism
(
c
);
char
b
=
(
char
)
a
;
String
d
=
String
.
valueOf
(
b
);
result
.
append
(
d
);
}
return
result
.
toString
();
}
/**
* 将十进制转换为指定长度的十六进制字符串
*
* @param algorism int 十进制数字
* @param maxLength int 转换后的十六进制字符串长度
* @return String 转换后的十六进制字符串
*/
public
static
String
algorismToHexString
(
int
algorism
,
int
maxLength
)
{
String
result
;
result
=
Integer
.
toHexString
(
algorism
);
if
(
result
.
length
()
%
2
==
1
)
{
result
=
"0"
+
result
;
}
return
patchHexString
(
result
.
toUpperCase
(),
maxLength
);
}
/**
* 字节数组转为普通字符串(ASCII对应的字符)
*
* @param bytearray byte[]
* @return String
*/
public
static
String
byteToString
(
byte
[]
bytearray
)
{
StringBuilder
result
=
new
StringBuilder
();
char
temp
;
int
length
=
bytearray
.
length
;
for
(
byte
b
:
bytearray
)
{
temp
=
(
char
)
b
;
result
.
append
(
temp
);
}
return
result
.
toString
();
}
/**
* 二进制字符串转十进制
*
* @param binary 二进制字符串
* @return 十进制数值
*/
public
static
int
binaryToAlgorism
(
String
binary
)
{
int
max
=
binary
.
length
();
int
result
=
0
;
for
(
int
i
=
max
;
i
>
0
;
i
--)
{
char
c
=
binary
.
charAt
(
i
-
1
);
int
algorism
=
c
-
'0'
;
result
+=
Math
.
pow
(
2
,
max
-
i
)
*
algorism
;
}
return
result
;
}
/**
* 十进制转换为十六进制字符串
*
* @param algorism int 十进制的数字
* @return String 对应的十六进制字符串
*/
public
static
String
algorismToHEXString
(
int
algorism
)
{
String
result
;
result
=
Integer
.
toHexString
(
algorism
);
if
(
result
.
length
()
%
2
==
1
)
{
result
=
"0"
+
result
;
}
result
=
result
.
toUpperCase
();
return
result
;
}
/**
* HEX字符串前补0,主要用于长度位数不足。
*
* @param str String 需要补充长度的十六进制字符串
* @param maxLength int 补充后十六进制字符串的长度
* @return 补充结果
*/
static
public
String
patchHexString
(
String
str
,
int
maxLength
)
{
StringBuilder
temp
=
new
StringBuilder
();
for
(
int
i
=
0
;
i
<
maxLength
-
str
.
length
();
i
++)
{
temp
.
insert
(
0
,
"0"
);
}
str
=
(
temp
+
str
).
substring
(
0
,
maxLength
);
return
str
;
}
/**
* 将一个字符串转换为int
*
* @param s String 要转换的字符串
* @param defaultInt int 如果出现异常,默认返回的数字
* @param radix int 要转换的字符串是什么进制的,如16 8 10.
* @return int 转换后的数字
*/
public
static
int
parseToInt
(
String
s
,
int
defaultInt
,
int
radix
)
{
int
i
;
try
{
i
=
Integer
.
parseInt
(
s
,
radix
);
}
catch
(
NumberFormatException
ex
)
{
i
=
defaultInt
;
}
return
i
;
}
/**
* 将一个十进制形式的数字字符串转换为int
*
* @param s String 要转换的字符串
* @param defaultInt int 如果出现异常,默认返回的数字
* @return int 转换后的数字
*/
public
static
int
parseToInt
(
String
s
,
int
defaultInt
)
{
int
i
;
try
{
i
=
Integer
.
parseInt
(
s
);
}
catch
(
NumberFormatException
ex
)
{
i
=
defaultInt
;
}
return
i
;
}
/**
* 十六进制串转化为byte数组
*
* @return the array of byte
*/
public
static
byte
[]
hexToByte
(
String
hex
)
throws
IllegalArgumentException
{
if
(
hex
.
length
()
%
2
!=
0
)
{
throw
new
IllegalArgumentException
();
}
char
[]
arr
=
hex
.
toCharArray
();
byte
[]
b
=
new
byte
[
hex
.
length
()
/
2
];
for
(
int
i
=
0
,
j
=
0
,
l
=
hex
.
length
();
i
<
l
;
i
++,
j
++)
{
String
swap
=
""
+
arr
[
i
++]
+
arr
[
i
];
int
byteInt
=
Integer
.
parseInt
(
swap
,
16
)
&
0xFF
;
b
[
j
]
=
Integer
.
valueOf
(
byteInt
).
byteValue
();
}
return
b
;
}
/**
* 字节数组转换为十六进制字符串
*
* @param b byte[] 需要转换的字节数组
* @return String 十六进制字符串
*/
public
static
String
byteToHex
(
byte
[]
b
)
{
if
(
b
==
null
)
{
throw
new
IllegalArgumentException
(
"Argument b ( byte array ) is null! "
);
}
StringBuilder
hs
=
new
StringBuilder
();
String
stmp
;
for
(
byte
value
:
b
)
{
stmp
=
Integer
.
toHexString
(
value
&
0xff
);
if
(
stmp
.
length
()
==
1
)
{
hs
.
append
(
"0"
).
append
(
stmp
);
}
else
{
hs
.
append
(
stmp
);
}
}
return
hs
.
toString
().
toUpperCase
();
}
public
static
byte
[]
subByte
(
byte
[]
input
,
int
startIndex
,
int
length
)
{
byte
[]
bt
=
new
byte
[
length
];
System
.
arraycopy
(
input
,
startIndex
,
bt
,
0
,
length
);
return
bt
;
}
}
arch-gateway/src/main/java/org/arch/config/sm4jm/SM4.java
0 → 100644
View file @
2c8ec2b
package
org
.
arch
.
config
.
sm4jm
;
import
java.io.ByteArrayInputStream
;
import
java.io.ByteArrayOutputStream
;
class
SM4
{
public
static
final
int
SM4_ENCRYPT
=
1
;
public
static
final
int
SM4_DECRYPT
=
0
;
private
int
GET_ULONG_BE
(
byte
[]
b
,
int
i
)
{
return
(
b
[
i
]
&
0xff
)
<<
24
|
((
b
[
i
+
1
]
&
0xff
)
<<
16
)
|
((
b
[
i
+
2
]
&
0xff
)
<<
8
)
|
b
[
i
+
3
]
&
0xff
&
0xffffffff
;
}
private
void
PUT_ULONG_BE
(
int
n
,
byte
[]
b
,
int
i
)
{
b
[
i
]
=
(
byte
)
(
0xFF
&
n
>>
24
);
b
[
i
+
1
]
=
(
byte
)
(
0xFF
&
n
>>
16
);
b
[
i
+
2
]
=
(
byte
)
(
0xFF
&
n
>>
8
);
b
[
i
+
3
]
=
(
byte
)
(
0xFF
&
n
);
}
private
int
SHL
(
int
x
,
int
n
)
{
return
(
x
&
0xFFFFFFFF
)
<<
n
;
}
private
int
ROTL
(
int
x
,
int
n
)
{
return
SHL
(
x
,
n
)
|
x
>>
(
32
-
n
);
}
public
static
final
byte
[]
SBOX_TABLE
=
{(
byte
)
0xd6
,
(
byte
)
0x90
,
(
byte
)
0xe9
,
(
byte
)
0xfe
,
(
byte
)
0xcc
,
(
byte
)
0xe1
,
0x3d
,
(
byte
)
0xb7
,
0x16
,
(
byte
)
0xb6
,
0x14
,
(
byte
)
0xc2
,
0x28
,
(
byte
)
0xfb
,
0x2c
,
0x05
,
0x2b
,
0x67
,
(
byte
)
0x9a
,
0x76
,
0x2a
,
(
byte
)
0xbe
,
0x04
,
(
byte
)
0xc3
,
(
byte
)
0xaa
,
0x44
,
0x13
,
0x26
,
0x49
,
(
byte
)
0x86
,
0x06
,
(
byte
)
0x99
,
(
byte
)
0x9c
,
0x42
,
0x50
,
(
byte
)
0xf4
,
(
byte
)
0x91
,
(
byte
)
0xef
,
(
byte
)
0x98
,
0x7a
,
0x33
,
0x54
,
0x0b
,
0x43
,
(
byte
)
0xed
,
(
byte
)
0xcf
,
(
byte
)
0xac
,
0x62
,
(
byte
)
0xe4
,
(
byte
)
0xb3
,
0x1c
,
(
byte
)
0xa9
,
(
byte
)
0xc9
,
0x08
,
(
byte
)
0xe8
,
(
byte
)
0x95
,
(
byte
)
0x80
,
(
byte
)
0xdf
,
(
byte
)
0x94
,
(
byte
)
0xfa
,
0x75
,
(
byte
)
0x8f
,
0x3f
,
(
byte
)
0xa6
,
0x47
,
0x07
,
(
byte
)
0xa7
,
(
byte
)
0xfc
,
(
byte
)
0xf3
,
0x73
,
0x17
,
(
byte
)
0xba
,
(
byte
)
0x83
,
0x59
,
0x3c
,
0x19
,
(
byte
)
0xe6
,
(
byte
)
0x85
,
0x4f
,
(
byte
)
0xa8
,
0x68
,
0x6b
,
(
byte
)
0x81
,
(
byte
)
0xb2
,
0x71
,
0x64
,
(
byte
)
0xda
,
(
byte
)
0x8b
,
(
byte
)
0xf8
,
(
byte
)
0xeb
,
0x0f
,
0x4b
,
0x70
,
0x56
,
(
byte
)
0x9d
,
0x35
,
0x1e
,
0x24
,
0x0e
,
0x5e
,
0x63
,
0x58
,
(
byte
)
0xd1
,
(
byte
)
0xa2
,
0x25
,
0x22
,
0x7c
,
0x3b
,
0x01
,
0x21
,
0x78
,
(
byte
)
0x87
,
(
byte
)
0xd4
,
0x00
,
0x46
,
0x57
,
(
byte
)
0x9f
,
(
byte
)
0xd3
,
0x27
,
0x52
,
0x4c
,
0x36
,
0x02
,
(
byte
)
0xe7
,
(
byte
)
0xa0
,
(
byte
)
0xc4
,
(
byte
)
0xc8
,
(
byte
)
0x9e
,
(
byte
)
0xea
,
(
byte
)
0xbf
,
(
byte
)
0x8a
,
(
byte
)
0xd2
,
0x40
,
(
byte
)
0xc7
,
0x38
,
(
byte
)
0xb5
,
(
byte
)
0xa3
,
(
byte
)
0xf7
,
(
byte
)
0xf2
,
(
byte
)
0xce
,
(
byte
)
0xf9
,
0x61
,
0x15
,
(
byte
)
0xa1
,
(
byte
)
0xe0
,
(
byte
)
0xae
,
0x5d
,
(
byte
)
0xa4
,
(
byte
)
0x9b
,
0x34
,
0x1a
,
0x55
,
(
byte
)
0xad
,
(
byte
)
0x93
,
0x32
,
0x30
,
(
byte
)
0xf5
,
(
byte
)
0x8c
,
(
byte
)
0xb1
,
(
byte
)
0xe3
,
0x1d
,
(
byte
)
0xf6
,
(
byte
)
0xe2
,
0x2e
,
(
byte
)
0x82
,
0x66
,
(
byte
)
0xca
,
0x60
,
(
byte
)
0xc0
,
0x29
,
0x23
,
(
byte
)
0xab
,
0x0d
,
0x53
,
0x4e
,
0x6f
,
(
byte
)
0xd5
,
(
byte
)
0xdb
,
0x37
,
0x45
,
(
byte
)
0xde
,
(
byte
)
0xfd
,
(
byte
)
0x8e
,
0x2f
,
0x03
,
(
byte
)
0xff
,
0x6a
,
0x72
,
0x6d
,
0x6c
,
0x5b
,
0x51
,
(
byte
)
0x8d
,
0x1b
,
(
byte
)
0xaf
,
(
byte
)
0x92
,
(
byte
)
0xbb
,
(
byte
)
0xdd
,
(
byte
)
0xbc
,
0x7f
,
0x11
,
(
byte
)
0xd9
,
0x5c
,
0x41
,
0x1f
,
0x10
,
0x5a
,
(
byte
)
0xd8
,
0x0a
,
(
byte
)
0xc1
,
0x31
,
(
byte
)
0x88
,
(
byte
)
0xa5
,
(
byte
)
0xcd
,
0x7b
,
(
byte
)
0xbd
,
0x2d
,
0x74
,
(
byte
)
0xd0
,
0x12
,
(
byte
)
0xb8
,
(
byte
)
0xe5
,
(
byte
)
0xb4
,
(
byte
)
0xb0
,
(
byte
)
0x89
,
0x69
,
(
byte
)
0x97
,
0x4a
,
0x0c
,
(
byte
)
0x96
,
0x77
,
0x7e
,
0x65
,
(
byte
)
0xb9
,
(
byte
)
0xf1
,
0x09
,
(
byte
)
0xc5
,
0x6e
,
(
byte
)
0xc6
,
(
byte
)
0x84
,
0x18
,
(
byte
)
0xf0
,
0x7d
,
(
byte
)
0xec
,
0x3a
,
(
byte
)
0xdc
,
0x4d
,
0x20
,
0x79
,
(
byte
)
0xee
,
0x5f
,
0x3e
,
(
byte
)
0xd7
,
(
byte
)
0xcb
,
0x39
,
0x48
};
public
static
final
int
[]
FK
=
{
0xa3b1bac6
,
0x56aa3350
,
0x677d9197
,
0xb27022dc
};
public
static
final
int
[]
CK
=
{
0x00070e15
,
0x1c232a31
,
0x383f464d
,
0x545b6269
,
0x70777e85
,
0x8c939aa1
,
0xa8afb6bd
,
0xc4cbd2d9
,
0xe0e7eef5
,
0xfc030a11
,
0x181f262d
,
0x343b4249
,
0x50575e65
,
0x6c737a81
,
0x888f969d
,
0xa4abb2b9
,
0xc0c7ced5
,
0xdce3eaf1
,
0xf8ff060d
,
0x141b2229
,
0x30373e45
,
0x4c535a61
,
0x686f767d
,
0x848b9299
,
0xa0a7aeb5
,
0xbcc3cad1
,
0xd8dfe6ed
,
0xf4fb0209
,
0x10171e25
,
0x2c333a41
,
0x484f565d
,
0x646b7279
};
private
byte
sm4Sbox
(
byte
inch
)
{
int
i
=
inch
&
0xFF
;
byte
retVal
=
SBOX_TABLE
[
i
];
return
retVal
;
}
private
int
sm4Lt
(
int
ka
)
{
int
bb
=
0
;
int
c
=
0
;
byte
[]
a
=
new
byte
[
4
];
byte
[]
b
=
new
byte
[
4
];
PUT_ULONG_BE
(
ka
,
a
,
0
);
b
[
0
]
=
sm4Sbox
(
a
[
0
]);
b
[
1
]
=
sm4Sbox
(
a
[
1
]);
b
[
2
]
=
sm4Sbox
(
a
[
2
]);
b
[
3
]
=
sm4Sbox
(
a
[
3
]);
bb
=
GET_ULONG_BE
(
b
,
0
);
c
=
bb
^
ROTL
(
bb
,
2
)
^
ROTL
(
bb
,
10
)
^
ROTL
(
bb
,
18
)
^
ROTL
(
bb
,
24
);
return
c
;
}
private
int
sm4F
(
int
x0
,
int
x1
,
int
x2
,
int
x3
,
int
rk
)
{
return
x0
^
sm4Lt
(
x1
^
x2
^
x3
^
rk
);
}
private
int
sm4CalciRK
(
int
ka
)
{
int
bb
=
0
;
int
rk
=
0
;
byte
[]
a
=
new
byte
[
4
];
byte
[]
b
=
new
byte
[
4
];
PUT_ULONG_BE
(
ka
,
a
,
0
);
b
[
0
]
=
sm4Sbox
(
a
[
0
]);
b
[
1
]
=
sm4Sbox
(
a
[
1
]);
b
[
2
]
=
sm4Sbox
(
a
[
2
]);
b
[
3
]
=
sm4Sbox
(
a
[
3
]);
bb
=
GET_ULONG_BE
(
b
,
0
);
rk
=
bb
^
ROTL
(
bb
,
13
)
^
ROTL
(
bb
,
23
);
return
rk
;
}
private
void
sm4_setkey
(
int
[]
SK
,
byte
[]
key
)
{
int
[]
mK
=
new
int
[
4
];
int
[]
k
=
new
int
[
36
];
int
i
=
0
;
mK
[
0
]
=
GET_ULONG_BE
(
key
,
0
);
mK
[
1
]
=
GET_ULONG_BE
(
key
,
4
);
mK
[
2
]
=
GET_ULONG_BE
(
key
,
8
);
mK
[
3
]
=
GET_ULONG_BE
(
key
,
12
);
k
[
0
]
=
mK
[
0
]
^
FK
[
0
];
k
[
1
]
=
mK
[
1
]
^
FK
[
1
];
k
[
2
]
=
mK
[
2
]
^
FK
[
2
];
k
[
3
]
=
mK
[
3
]
^
FK
[
3
];
for
(;
i
<
32
;
i
++)
{
k
[(
i
+
4
)]
=
(
k
[
i
]
^
sm4CalciRK
(
k
[(
i
+
1
)]
^
k
[(
i
+
2
)]
^
k
[(
i
+
3
)]
^
(
int
)
CK
[
i
]));
SK
[
i
]
=
k
[(
i
+
4
)];
}
}
private
void
sm4_one_round
(
int
[]
sk
,
byte
[]
input
,
byte
[]
output
)
{
int
i
=
0
;
int
[]
ulbuf
=
new
int
[
36
];
ulbuf
[
0
]
=
GET_ULONG_BE
(
input
,
0
);
ulbuf
[
1
]
=
GET_ULONG_BE
(
input
,
4
);
ulbuf
[
2
]
=
GET_ULONG_BE
(
input
,
8
);
ulbuf
[
3
]
=
GET_ULONG_BE
(
input
,
12
);
while
(
i
<
32
)
{
ulbuf
[(
i
+
4
)]
=
sm4F
(
ulbuf
[
i
],
ulbuf
[(
i
+
1
)],
ulbuf
[(
i
+
2
)],
ulbuf
[(
i
+
3
)],
sk
[
i
]);
i
++;
}
PUT_ULONG_BE
(
ulbuf
[
35
],
output
,
0
);
PUT_ULONG_BE
(
ulbuf
[
34
],
output
,
4
);
PUT_ULONG_BE
(
ulbuf
[
33
],
output
,
8
);
PUT_ULONG_BE
(
ulbuf
[
32
],
output
,
12
);
}
private
byte
[]
padding
(
byte
[]
input
,
int
mode
)
{
if
(
input
==
null
)
{
return
null
;
}
byte
[]
ret
;
if
(
mode
==
SM4_ENCRYPT
)
{
int
p
=
16
-
input
.
length
%
16
;
ret
=
new
byte
[
input
.
length
+
p
];
System
.
arraycopy
(
input
,
0
,
ret
,
0
,
input
.
length
);
for
(
int
i
=
0
;
i
<
p
;
i
++)
{
ret
[
input
.
length
+
i
]
=
(
byte
)
p
;
}
}
else
{
int
p
=
input
[
input
.
length
-
1
];
ret
=
new
byte
[
input
.
length
-
p
];
System
.
arraycopy
(
input
,
0
,
ret
,
0
,
input
.
length
-
p
);
}
return
ret
;
}
public
void
sm4_setkey_enc
(
SM4Context
ctx
,
byte
[]
key
)
throws
Exception
{
if
(
ctx
==
null
)
{
throw
new
Exception
(
"ctx is null!"
);
}
if
(
key
==
null
||
key
.
length
!=
16
)
{
throw
new
Exception
(
"key error!"
);
}
ctx
.
mode
=
SM4_ENCRYPT
;
sm4_setkey
(
ctx
.
sk
,
key
);
}
public
byte
[]
sm4_crypt_ecb
(
SM4Context
ctx
,
byte
[]
input
)
throws
Exception
{
if
(
input
==
null
)
{
throw
new
Exception
(
"input is null!"
);
}
if
((
ctx
.
isPadding
)
&&
(
ctx
.
mode
==
SM4_ENCRYPT
))
{
input
=
padding
(
input
,
SM4_ENCRYPT
);
}
int
length
=
input
.
length
;
ByteArrayInputStream
bins
=
new
ByteArrayInputStream
(
input
);
ByteArrayOutputStream
bous
=
new
ByteArrayOutputStream
();
for
(;
length
>
0
;
length
-=
16
)
{
byte
[]
in
=
new
byte
[
16
];
byte
[]
out
=
new
byte
[
16
];
bins
.
read
(
in
);
sm4_one_round
(
ctx
.
sk
,
in
,
out
);
bous
.
write
(
out
);
}
byte
[]
output
=
bous
.
toByteArray
();
if
(
ctx
.
isPadding
&&
ctx
.
mode
==
SM4_DECRYPT
)
{
output
=
padding
(
output
,
SM4_DECRYPT
);
}
bins
.
close
();
bous
.
close
();
return
output
;
}
public
void
sm4_setkey_dec
(
SM4Context
ctx
,
byte
[]
key
)
throws
Exception
{
if
(
ctx
==
null
)
{
throw
new
Exception
(
"ctx is null!"
);
}
if
(
key
==
null
||
key
.
length
!=
16
)
{
throw
new
Exception
(
"key error!"
);
}
int
i
=
0
;
ctx
.
mode
=
SM4_DECRYPT
;
sm4_setkey
(
ctx
.
sk
,
key
);
for
(
i
=
0
;
i
<
16
;
i
++)
{
SWAP
(
ctx
.
sk
,
i
);
}
}
private
void
SWAP
(
int
[]
sk
,
int
i
)
{
int
t
=
sk
[
i
];
sk
[
i
]
=
sk
[(
31
-
i
)];
sk
[(
31
-
i
)]
=
t
;
}
public
byte
[]
sm4_crypt_cbc
(
SM4Context
ctx
,
byte
[]
iv
,
byte
[]
input
)
throws
Exception
{
if
(
iv
==
null
||
iv
.
length
!=
16
)
{
throw
new
Exception
(
"iv error!"
);
}
if
(
input
==
null
)
{
throw
new
Exception
(
"input is null!"
);
}
if
(
ctx
.
isPadding
&&
ctx
.
mode
==
SM4_ENCRYPT
)
{
input
=
padding
(
input
,
SM4_ENCRYPT
);
}
int
i
;
int
length
=
input
.
length
;
ByteArrayInputStream
bins
=
new
ByteArrayInputStream
(
input
);
ByteArrayOutputStream
bous
=
new
ByteArrayOutputStream
();
if
(
ctx
.
mode
==
SM4_ENCRYPT
)
{
for
(;
length
>
0
;
length
-=
16
)
{
byte
[]
in
=
new
byte
[
16
];
byte
[]
out
=
new
byte
[
16
];
byte
[]
out1
=
new
byte
[
16
];
bins
.
read
(
in
);
for
(
i
=
0
;
i
<
16
;
i
++)
{
out
[
i
]
=
((
byte
)
(
in
[
i
]
^
iv
[
i
]));
}
sm4_one_round
(
ctx
.
sk
,
out
,
out1
);
System
.
arraycopy
(
out1
,
0
,
iv
,
0
,
16
);
bous
.
write
(
out1
);
}
}
else
{
byte
[]
temp
=
new
byte
[
16
];
for
(;
length
>
0
;
length
-=
16
)
{
byte
[]
in
=
new
byte
[
16
];
byte
[]
out
=
new
byte
[
16
];
byte
[]
out1
=
new
byte
[
16
];
bins
.
read
(
in
);
System
.
arraycopy
(
in
,
0
,
temp
,
0
,
16
);
sm4_one_round
(
ctx
.
sk
,
in
,
out
);
for
(
i
=
0
;
i
<
16
;
i
++)
{
out1
[
i
]
=
((
byte
)
(
out
[
i
]
^
iv
[
i
]));
}
System
.
arraycopy
(
temp
,
0
,
iv
,
0
,
16
);
bous
.
write
(
out1
);
}
}
byte
[]
output
=
bous
.
toByteArray
();
if
(
ctx
.
isPadding
&&
ctx
.
mode
==
SM4_DECRYPT
)
{
output
=
padding
(
output
,
SM4_DECRYPT
);
}
bins
.
close
();
bous
.
close
();
return
output
;
}
}
arch-gateway/src/main/java/org/arch/config/sm4jm/SM4Context.java
0 → 100644
View file @
2c8ec2b
package
org
.
arch
.
config
.
sm4jm
;
class
SM4Context
{
public
int
mode
;
public
int
[]
sk
;
public
boolean
isPadding
;
public
SM4Context
()
{
this
.
mode
=
1
;
this
.
isPadding
=
true
;
this
.
sk
=
new
int
[
32
];
}
}
arch-gateway/src/main/java/org/arch/config/sm4jm/SM4Utils.java
0 → 100644
View file @
2c8ec2b
package
org
.
arch
.
config
.
sm4jm
;
import
cn.hutool.json.JSON
;
import
cn.hutool.json.JSONString
;
import
org.apache.commons.codec.binary.Base64
;
import
java.nio.charset.StandardCharsets
;
import
java.util.HashMap
;
import
java.util.Map
;
import
java.util.regex.Matcher
;
import
java.util.regex.Pattern
;
/**
* <p>
* ECB 加密模式
* 不使用自定义 secretKey,一般用于后端自行加解密,如果是前端加密后端解密,则需要自定义secretKey,前后端一致才能正确解密
* 经过ECB加密的密文为:SM4Utils.encryptData_ECB("123456");
* 经过ECB解密的密文为:SM4Utils.decryptData_ECB("UQZqWWcVSu7MIrMzWRD/wA==");
* 使用自定义 secretKey,传入的 secretKey 必须为16位,可包含字母、数字、标点
* 经过ECB加密的密文为:SM4Utils.encryptData_ECB("123456");
* 经过ECB解密的密文为:SM4Utils.decryptData_ECB("UQZqWWcVSu7MIrMzWRD/wA==");
* <p>
* CBC 加密模式(更加安全),需要两个密钥
* 经过CBC加密的密文为:SM4Utils.encryptData_CBC("123456");
* 经过CBC解密的密文为:SM4Utils.decryptData_CBC("hbMK6/IeJ3UTzaTgLb3f3A==");
* 同样可以自定义 secretKey 和 iv,需要两个密钥前后端都一致
* 经过CBC加密的密文为:SM4Utils.encryptData_CBC("123456","asdfghjklzxcvb!_","1234567890123456");
* 经过CBC解密的密文为:SM4Utils.decryptData_CBC("sTyCl3G6TF311kIENzsKNg==","asdfghjklzxcvb!_","1234567890123456");
*/
public
class
SM4Utils
{
/**
* 默认 SECRET_KEY
* 当时用ECB模式的时候,和前端key一致
* secretKey 必须为16位,可包含字母、数字、标点
*/
private
static
final
String
SECRET_KEY
=
"GJwsXX_BzW=gJWJW"
;
/**
* 默认 IV
* 当时用CBC模式的时候,SECRET_KEY和IV都需要传值,解密要和加密的SECRET_KEY和IV一致,更加安全
* iv 必须为 16 位,可包含字母、数字、标点
*/
private
static
final
String
IV
=
"ZkR_SiNoSOFT=568"
;
private
static
final
boolean
HEX_STRING
=
false
;
public
SM4Utils
()
{
}
/**
* 不要在方法里定义正则表达式规则,应定义为常量或字段,能加快正则匹配速度
*/
private
static
final
Pattern
P
=
Pattern
.
compile
(
"\\s*|\t|\r|\n"
);
/**
* ECB模式加密,自定义密钥,加解密密钥需一致
*
* @param plainText 要加密的数据
* @param secretKey 密钥,必须为 16 位,可包含字母、数字、标点
* @return
*/
public
static
String
encryptData_ECB
(
String
plainText
,
String
secretKey
)
{
try
{
SM4Context
ctx
=
new
SM4Context
();
ctx
.
isPadding
=
true
;
ctx
.
mode
=
SM4
.
SM4_ENCRYPT
;
byte
[]
keyBytes
;
keyBytes
=
secretKey
.
getBytes
();
SM4
sm4
=
new
SM4
();
sm4
.
sm4_setkey_enc
(
ctx
,
keyBytes
);
byte
[]
encrypted
=
sm4
.
sm4_crypt_ecb
(
ctx
,
plainText
.
getBytes
(
StandardCharsets
.
UTF_8
));
String
cipherText
=
Base64
.
encodeBase64String
(
encrypted
);
if
(
cipherText
!=
null
&&
cipherText
.
trim
().
length
()
>
0
)
{
Matcher
m
=
P
.
matcher
(
cipherText
);
cipherText
=
m
.
replaceAll
(
""
);
}
return
cipherText
;
}
catch
(
Exception
e
)
{
e
.
printStackTrace
();
return
null
;
}
}
/**
* ECB模式加密,默认密钥
*
* @param plainText 要加密的数据
* @return
*/
public
static
String
encryptData_ECB
(
String
plainText
)
{
try
{
SM4Context
ctx
=
new
SM4Context
();
ctx
.
isPadding
=
true
;
ctx
.
mode
=
SM4
.
SM4_ENCRYPT
;
byte
[]
keyBytes
;
keyBytes
=
SECRET_KEY
.
getBytes
();
SM4
sm4
=
new
SM4
();
sm4
.
sm4_setkey_enc
(
ctx
,
keyBytes
);
byte
[]
encrypted
=
sm4
.
sm4_crypt_ecb
(
ctx
,
plainText
.
getBytes
(
StandardCharsets
.
UTF_8
));
String
cipherText
=
Base64
.
encodeBase64String
(
encrypted
);
if
(
cipherText
!=
null
&&
cipherText
.
trim
().
length
()
>
0
)
{
Matcher
m
=
P
.
matcher
(
cipherText
);
cipherText
=
m
.
replaceAll
(
""
);
}
return
cipherText
;
}
catch
(
Exception
e
)
{
e
.
printStackTrace
();
return
null
;
}
}
/**
* ECB模式解密,自定义密钥,加解密密钥需一致
*
* @param cipherText 要解密的数据
* @param secretKey 密钥,必须为 16 位,可包含字母、数字、标点
* @return
*/
public
static
String
decryptData_ECB
(
String
cipherText
,
String
secretKey
)
{
try
{
SM4Context
ctx
=
new
SM4Context
();
ctx
.
isPadding
=
true
;
ctx
.
mode
=
SM4
.
SM4_DECRYPT
;
byte
[]
keyBytes
;
keyBytes
=
secretKey
.
getBytes
();
SM4
sm4
=
new
SM4
();
sm4
.
sm4_setkey_dec
(
ctx
,
keyBytes
);
byte
[]
decrypted
=
sm4
.
sm4_crypt_ecb
(
ctx
,
Base64
.
decodeBase64
(
cipherText
));
return
new
String
(
decrypted
,
StandardCharsets
.
UTF_8
);
}
catch
(
Exception
e
)
{
e
.
printStackTrace
();
return
null
;
}
}
/**
* ECB模式解密,默认密钥
*
* @param cipherText 要解密的数据
* @return
*/
public
static
String
decryptData_ECB
(
String
cipherText
)
{
try
{
SM4Context
ctx
=
new
SM4Context
();
ctx
.
isPadding
=
true
;
ctx
.
mode
=
SM4
.
SM4_DECRYPT
;
byte
[]
keyBytes
;
keyBytes
=
SECRET_KEY
.
getBytes
();
SM4
sm4
=
new
SM4
();
sm4
.
sm4_setkey_dec
(
ctx
,
keyBytes
);
byte
[]
decrypted
=
sm4
.
sm4_crypt_ecb
(
ctx
,
Base64
.
decodeBase64
(
cipherText
));
return
new
String
(
decrypted
,
StandardCharsets
.
UTF_8
);
}
catch
(
Exception
e
)
{
e
.
printStackTrace
();
return
null
;
}
}
/**
* CBC模式加密,SECRET_KEY和IV都需要传值,解密要和加密的SECRET_KEY和IV一致,更加安全
*
* @param plainText 要加密的数据
* @param secretKey 密钥一,必须为 16 位,可包含字母、数字、标点
* @param iv 密钥二,必须为 16 位,可包含字母、数字、标点
* @return
*/
public
static
String
encryptData_CBC
(
String
plainText
,
String
secretKey
,
String
iv
)
{
try
{
SM4Context
ctx
=
new
SM4Context
();
ctx
.
isPadding
=
true
;
ctx
.
mode
=
SM4
.
SM4_ENCRYPT
;
byte
[]
keyBytes
;
byte
[]
ivBytes
;
keyBytes
=
secretKey
.
getBytes
();
ivBytes
=
iv
.
getBytes
();
SM4
sm4
=
new
SM4
();
sm4
.
sm4_setkey_enc
(
ctx
,
keyBytes
);
byte
[]
encrypted
=
sm4
.
sm4_crypt_cbc
(
ctx
,
ivBytes
,
plainText
.
getBytes
(
StandardCharsets
.
UTF_8
));
String
cipherText
=
Base64
.
encodeBase64String
(
encrypted
);
if
(
cipherText
!=
null
&&
cipherText
.
trim
().
length
()
>
0
)
{
Matcher
m
=
P
.
matcher
(
cipherText
);
cipherText
=
m
.
replaceAll
(
""
);
}
return
cipherText
;
}
catch
(
Exception
e
)
{
e
.
printStackTrace
();
return
null
;
}
}
/**
* CBC模式加密,SECRET_KEY和IV都需要传值,解密要和加密的SECRET_KEY和IV一致,更加安全
*
* @param plainText
* @return
*/
public
static
String
encryptData_CBC
(
String
plainText
)
{
try
{
SM4Context
ctx
=
new
SM4Context
();
ctx
.
isPadding
=
true
;
ctx
.
mode
=
SM4
.
SM4_ENCRYPT
;
byte
[]
keyBytes
;
byte
[]
ivBytes
;
keyBytes
=
SECRET_KEY
.
getBytes
();
ivBytes
=
IV
.
getBytes
();
SM4
sm4
=
new
SM4
();
sm4
.
sm4_setkey_enc
(
ctx
,
keyBytes
);
byte
[]
encrypted
=
sm4
.
sm4_crypt_cbc
(
ctx
,
ivBytes
,
plainText
.
getBytes
(
StandardCharsets
.
UTF_8
));
String
cipherText
=
Base64
.
encodeBase64String
(
encrypted
);
if
(
cipherText
!=
null
&&
cipherText
.
trim
().
length
()
>
0
)
{
Matcher
m
=
P
.
matcher
(
cipherText
);
cipherText
=
m
.
replaceAll
(
""
);
}
return
cipherText
;
}
catch
(
Exception
e
)
{
e
.
printStackTrace
();
return
null
;
}
}
/**
* CBC模式解密,SECRET_KEY和IV都需要传值,解密要和加密的SECRET_KEY和IV一致,更加安全
*
* @param cipherText 要解密的数据
* @param secretKey 密钥一,必须为 16 位,可包含字母、数字、标点
* @param iv 密钥二,必须为 16 位,可包含字母、数字、标点
* @return
*/
public
static
String
decryptData_CBC
(
String
cipherText
,
String
secretKey
,
String
iv
)
{
try
{
SM4Context
ctx
=
new
SM4Context
();
ctx
.
isPadding
=
true
;
ctx
.
mode
=
SM4
.
SM4_DECRYPT
;
byte
[]
keyBytes
;
byte
[]
ivBytes
;
if
(
HEX_STRING
)
{
keyBytes
=
ByteConvertUtil
.
hexStringToBytes
(
secretKey
);
ivBytes
=
ByteConvertUtil
.
hexStringToBytes
(
iv
);
}
else
{
keyBytes
=
secretKey
.
getBytes
();
ivBytes
=
iv
.
getBytes
();
}
SM4
sm4
=
new
SM4
();
sm4
.
sm4_setkey_dec
(
ctx
,
keyBytes
);
byte
[]
decrypted
=
sm4
.
sm4_crypt_cbc
(
ctx
,
ivBytes
,
Base64
.
decodeBase64
(
cipherText
));
return
new
String
(
decrypted
,
StandardCharsets
.
UTF_8
);
}
catch
(
Exception
e
)
{
e
.
printStackTrace
();
return
null
;
}
}
/**
* CBC模式解密,SECRET_KEY和IV都需要传值,解密要和加密的SECRET_KEY和IV一致,更加安全
*
* @param cipherText 要解密的数据
* @return
*/
public
static
String
decryptData_CBC
(
String
cipherText
)
{
try
{
SM4Context
ctx
=
new
SM4Context
();
ctx
.
isPadding
=
true
;
ctx
.
mode
=
SM4
.
SM4_DECRYPT
;
byte
[]
keyBytes
;
byte
[]
ivBytes
;
if
(
HEX_STRING
)
{
keyBytes
=
ByteConvertUtil
.
hexStringToBytes
(
SECRET_KEY
);
ivBytes
=
ByteConvertUtil
.
hexStringToBytes
(
IV
);
}
else
{
keyBytes
=
SECRET_KEY
.
getBytes
();
ivBytes
=
IV
.
getBytes
();
}
SM4
sm4
=
new
SM4
();
sm4
.
sm4_setkey_dec
(
ctx
,
keyBytes
);
byte
[]
decrypted
=
sm4
.
sm4_crypt_cbc
(
ctx
,
ivBytes
,
Base64
.
decodeBase64
(
cipherText
));
return
new
String
(
decrypted
,
StandardCharsets
.
UTF_8
);
}
catch
(
Exception
e
)
{
e
.
printStackTrace
();
return
null
;
}
}
public
static
void
main
(
String
[]
args
)
{
Map
<
String
,
String
>
map
=
new
HashMap
<>();
map
.
put
(
"id"
,
"1"
);
map
.
put
(
"studentNumber"
,
"2378633"
);
map
.
put
(
"userName"
,
"张三"
);
System
.
out
.
println
(
map
);
// String s = "123";
// System.out.println("经过ECB加密的密文为:" + SM4Utils.encryptData_ECB("123456"));
// System.out.println("经过ECB解密的密文为:" + SM4Utils.decryptData_ECB("UQZqWWcVSu7MIrMzWRD/wA=="));
//System.out.println("经过CBC加密的密文为:" + SM4Utils.encryptData_CBC(s, "GJwsXX_BzW=gJWJW", "ZkR_SiNoSOFT=568"));
//System.out.println("经过CBC解密的密文为:" + SM4Utils.decryptData_CBC("4eMPwuNIlq0QbUFuYmvRN0Aff85gYDPfgl9T+w0waMkgzWM8bve56sF6xAVsV5e05rXwnok1dRCFv37V9bL3AA==", "GJwsXX_BzW=gJWJW", "ZkR_SiNoSOFT=568"));
}
}
arch-gateway/src/main/java/org/arch/config/tszf/specialCharFilter.java
0 → 100644
View file @
2c8ec2b
package
org
.
arch
.
config
.
tszf
;
import
io.netty.buffer.ByteBufAllocator
;
import
lombok.AllArgsConstructor
;
import
lombok.Builder
;
import
lombok.Data
;
import
lombok.NoArgsConstructor
;
import
lombok.extern.slf4j.Slf4j
;
import
org.springframework.cloud.gateway.filter.GatewayFilterChain
;
import
org.springframework.cloud.gateway.filter.GlobalFilter
;
import
org.springframework.core.Ordered
;
import
org.springframework.core.io.buffer.DataBuffer
;
import
org.springframework.core.io.buffer.DataBufferUtils
;
import
org.springframework.core.io.buffer.NettyDataBufferFactory
;
import
org.springframework.http.HttpHeaders
;
import
org.springframework.http.HttpMethod
;
import
org.springframework.http.server.reactive.ServerHttpRequest
;
import
org.springframework.http.server.reactive.ServerHttpRequestDecorator
;
import
org.springframework.validation.annotation.Validated
;
import
org.springframework.web.server.ServerWebExchange
;
import
reactor.core.publisher.Flux
;
import
reactor.core.publisher.Mono
;
import
javax.validation.constraints.NotEmpty
;
import
java.net.URI
;
import
java.nio.charset.StandardCharsets
;
import
java.util.List
;
import
java.util.Optional
;
import
java.util.regex.Matcher
;
import
java.util.regex.Pattern
;
import
java.util.regex.PatternSyntaxException
;
//@Component
@Slf4j
//@Order(3)
public
class
specialCharFilter
implements
GlobalFilter
,
Ordered
{
private
List
<
XssWhiteUrl
>
whiteUrls
;
@Override
public
Mono
<
Void
>
filter
(
ServerWebExchange
exchange
,
GatewayFilterChain
chain
)
{
ServerHttpRequest
request
=
exchange
.
getRequest
();
URI
uri
=
request
.
getURI
();
String
method
=
request
.
getMethodValue
();
if
(
this
.
white
(
uri
.
getPath
(),
method
))
{
return
chain
.
filter
(
exchange
);
}
if
((
HttpMethod
.
POST
.
name
().
equals
(
method
)
||
HttpMethod
.
PUT
.
name
().
equals
(
method
)))
{
return
DataBufferUtils
.
join
(
request
.
getBody
()).
flatMap
(
d
->
Mono
.
just
(
Optional
.
of
(
d
))).
defaultIfEmpty
(
Optional
.
empty
())
.
flatMap
(
optional
->
{
// 取出body中的参数
String
bodyString
=
""
;
if
(
optional
.
isPresent
())
{
byte
[]
oldBytes
=
new
byte
[
optional
.
get
().
readableByteCount
()];
optional
.
get
().
read
(
oldBytes
);
bodyString
=
new
String
(
oldBytes
,
StandardCharsets
.
UTF_8
);
}
HttpHeaders
httpHeaders
=
request
.
getHeaders
();
// 执行特殊字符清理
log
.
info
(
"{} - [{}] tszf处理前参数:{}"
,
method
,
uri
.
getPath
(),
bodyString
);
// bodyString = XssUtil.INSTANCE.cleanXss(bodyString);
bodyString
=
this
.
StringFilter
(
bodyString
);
log
.
info
(
"{} - [{}] tszf处理后参数:{}"
,
method
,
uri
.
getPath
(),
bodyString
);
ServerHttpRequest
newRequest
=
request
.
mutate
().
uri
(
uri
).
build
();
// 重新构造body
byte
[]
newBytes
=
bodyString
.
getBytes
(
StandardCharsets
.
UTF_8
);
DataBuffer
bodyDataBuffer
=
toDataBuffer
(
newBytes
);
Flux
<
DataBuffer
>
bodyFlux
=
Flux
.
just
(
bodyDataBuffer
);
// 重新构造header
HttpHeaders
headers
=
new
HttpHeaders
();
headers
.
putAll
(
httpHeaders
);
// 由于修改了传递参数,需要重新设置CONTENT_LENGTH,长度是字节长度,不是字符串长度
int
length
=
newBytes
.
length
;
headers
.
remove
(
HttpHeaders
.
CONTENT_LENGTH
);
headers
.
setContentLength
(
length
);
headers
.
set
(
HttpHeaders
.
CONTENT_TYPE
,
"application/json;charset=utf8"
);
// 重写ServerHttpRequestDecorator,修改了body和header,重写getBody和getHeaders方法
newRequest
=
new
ServerHttpRequestDecorator
(
newRequest
)
{
@Override
public
Flux
<
DataBuffer
>
getBody
()
{
return
bodyFlux
;
}
@Override
public
HttpHeaders
getHeaders
()
{
return
headers
;
}
};
return
chain
.
filter
(
exchange
.
mutate
().
request
(
newRequest
).
build
());
});
}
else
{
return
chain
.
filter
(
exchange
);
}
}
private
String
StringFilter
(
String
str
)
throws
PatternSyntaxException
{
// 只允许字母和数字
// String regEx = "[^a-zA-Z0-9]";
// 清除掉所有特殊字符
String
regEx
=
"[`~!@#$%^&*()+=|{}':;',//[//].<>/?~!@#¥%……&*()——+|{}【】‘;:”“’。,、?]"
;
Pattern
p
=
Pattern
.
compile
(
regEx
);
Matcher
m
=
p
.
matcher
(
str
);
return
m
.
replaceAll
(
""
).
trim
();
}
/**
* 是否是白名单
*
* @param url 路由
* @param method 请求方式
* @return true/false
*/
private
boolean
white
(
String
url
,
String
method
)
{
return
whiteUrls
!=
null
&&
whiteUrls
.
contains
(
XssWhiteUrl
.
builder
().
url
(
url
).
method
(
method
).
build
());
}
/**
* 字节数组转DataBuffer
*
* @param bytes 字节数组
* @return DataBuffer
*/
private
DataBuffer
toDataBuffer
(
byte
[]
bytes
)
{
NettyDataBufferFactory
nettyDataBufferFactory
=
new
NettyDataBufferFactory
(
ByteBufAllocator
.
DEFAULT
);
DataBuffer
buffer
=
nettyDataBufferFactory
.
allocateBuffer
(
bytes
.
length
);
buffer
.
write
(
bytes
);
return
buffer
;
}
@Override
public
int
getOrder
()
{
return
0
;
}
@Data
@Validated
@AllArgsConstructor
@NoArgsConstructor
@Builder
private
static
class
XssWhiteUrl
{
@NotEmpty
private
String
url
;
@NotEmpty
private
String
method
;
}
}
arch-gateway/src/main/java/org/arch/config/xssFilter/JsonUtil.java
0 → 100644
View file @
2c8ec2b
package
org
.
arch
.
config
.
xssFilter
;
import
com.alibaba.fastjson.JSONObject
;
import
org.springframework.util.StringUtils
;
/**
* JSON处理工具类
*
* @author lieber
*/
public
enum
JsonUtil
{
/**
* 实例
*/
INSTANCE
;
/**
* json对象字符串开始标记
*/
private
final
static
String
JSON_OBJECT_START
=
"{"
;
/**
* json对象字符串结束标记
*/
private
final
static
String
JSON_OBJECT_END
=
"}"
;
/**
* json数组字符串开始标记
*/
private
final
static
String
JSON_ARRAY_START
=
"["
;
/**
* json数组字符串结束标记
*/
private
final
static
String
JSON_ARRAY_END
=
"]"
;
/**
* 判断字符串是否json对象字符串
*
* @param val 字符串
* @return true/false
*/
public
boolean
isJsonObj
(
String
val
)
{
if
(
StringUtils
.
isEmpty
(
val
))
{
return
false
;
}
val
=
val
.
trim
();
if
(
val
.
startsWith
(
JSON_OBJECT_START
)
&&
val
.
endsWith
(
JSON_OBJECT_END
))
{
try
{
JSONObject
.
parseObject
(
val
);
return
true
;
}
catch
(
Exception
e
)
{
return
false
;
}
}
return
false
;
}
/**
* 判断字符串是否json数组字符串
*
* @param val 字符串
* @return true/false
*/
public
boolean
isJsonArr
(
String
val
)
{
if
(
StringUtils
.
isEmpty
(
val
))
{
return
false
;
}
val
=
val
.
trim
();
if
(
StringUtils
.
isEmpty
(
val
))
{
return
false
;
}
val
=
val
.
trim
();
if
(
val
.
startsWith
(
JSON_ARRAY_START
)
&&
val
.
endsWith
(
JSON_ARRAY_END
))
{
try
{
JSONObject
.
parseArray
(
val
);
return
true
;
}
catch
(
Exception
e
)
{
return
false
;
}
}
return
false
;
}
/**
* 判断对象是否是json对象
*
* @param obj 待判断对象
* @return true/false
*/
public
boolean
isJsonObj
(
Object
obj
)
{
String
str
=
JSONObject
.
toJSONString
(
obj
);
return
this
.
isJsonObj
(
str
);
}
/**
* 判断字符串是否json字符串
*
* @param str 字符串
* @return true/false
*/
public
boolean
isJson
(
String
str
)
{
if
(
StringUtils
.
isEmpty
(
str
))
{
return
false
;
}
return
this
.
isJsonObj
(
str
)
||
this
.
isJsonArr
(
str
);
}
}
arch-gateway/src/main/java/org/arch/config/xssFilter/XssFilter.java
0 → 100644
View file @
2c8ec2b
package
org
.
arch
.
config
.
xssFilter
;
import
io.netty.buffer.ByteBufAllocator
;
import
lombok.AllArgsConstructor
;
import
lombok.Builder
;
import
lombok.Data
;
import
lombok.NoArgsConstructor
;
import
lombok.extern.slf4j.Slf4j
;
import
org.springframework.cloud.gateway.filter.GatewayFilterChain
;
import
org.springframework.cloud.gateway.filter.GlobalFilter
;
import
org.springframework.core.Ordered
;
import
org.springframework.core.io.buffer.DataBuffer
;
import
org.springframework.core.io.buffer.DataBufferUtils
;
import
org.springframework.core.io.buffer.NettyDataBufferFactory
;
import
org.springframework.http.HttpHeaders
;
import
org.springframework.http.HttpMethod
;
import
org.springframework.http.server.reactive.ServerHttpRequest
;
import
org.springframework.http.server.reactive.ServerHttpRequestDecorator
;
import
org.springframework.validation.annotation.Validated
;
import
org.springframework.web.server.ServerWebExchange
;
import
reactor.core.publisher.Flux
;
import
reactor.core.publisher.Mono
;
import
javax.validation.constraints.NotEmpty
;
import
java.net.URI
;
import
java.nio.charset.StandardCharsets
;
import
java.util.List
;
import
java.util.Optional
;
/**
* XSS过滤
*
*/
//@Component
@Slf4j
//@ConfigurationProperties("config.xss")
@Data
//@Order(4)
public
class
XssFilter
implements
GlobalFilter
,
Ordered
{
private
List
<
XssWhiteUrl
>
whiteUrls
;
@Override
public
Mono
<
Void
>
filter
(
ServerWebExchange
exchange
,
GatewayFilterChain
chain
)
{
ServerHttpRequest
request
=
exchange
.
getRequest
();
URI
uri
=
request
.
getURI
();
String
method
=
request
.
getMethodValue
();
if
(
this
.
white
(
uri
.
getPath
(),
method
))
{
return
chain
.
filter
(
exchange
);
}
if
((
HttpMethod
.
POST
.
name
().
equals
(
method
)
||
HttpMethod
.
PUT
.
name
().
equals
(
method
)))
{
return
DataBufferUtils
.
join
(
request
.
getBody
()).
flatMap
(
d
->
Mono
.
just
(
Optional
.
of
(
d
))).
defaultIfEmpty
(
Optional
.
empty
())
.
flatMap
(
optional
->
{
// 取出body中的参数
String
bodyString
=
""
;
if
(
optional
.
isPresent
())
{
byte
[]
oldBytes
=
new
byte
[
optional
.
get
().
readableByteCount
()];
optional
.
get
().
read
(
oldBytes
);
bodyString
=
new
String
(
oldBytes
,
StandardCharsets
.
UTF_8
);
}
HttpHeaders
httpHeaders
=
request
.
getHeaders
();
// 执行XSS清理
log
.
info
(
"{} - [{}] XSS处理前参数:{}"
,
method
,
uri
.
getPath
(),
bodyString
);
bodyString
=
XssUtil
.
INSTANCE
.
cleanXss
(
bodyString
);
log
.
info
(
"{} - [{}] XSS处理后参数:{}"
,
method
,
uri
.
getPath
(),
bodyString
);
ServerHttpRequest
newRequest
=
request
.
mutate
().
uri
(
uri
).
build
();
// 重新构造body
byte
[]
newBytes
=
bodyString
.
getBytes
(
StandardCharsets
.
UTF_8
);
DataBuffer
bodyDataBuffer
=
toDataBuffer
(
newBytes
);
Flux
<
DataBuffer
>
bodyFlux
=
Flux
.
just
(
bodyDataBuffer
);
// 重新构造header
HttpHeaders
headers
=
new
HttpHeaders
();
headers
.
putAll
(
httpHeaders
);
// 由于修改了传递参数,需要重新设置CONTENT_LENGTH,长度是字节长度,不是字符串长度
int
length
=
newBytes
.
length
;
headers
.
remove
(
HttpHeaders
.
CONTENT_LENGTH
);
headers
.
setContentLength
(
length
);
headers
.
set
(
HttpHeaders
.
CONTENT_TYPE
,
"application/json;charset=utf8"
);
// 重写ServerHttpRequestDecorator,修改了body和header,重写getBody和getHeaders方法
newRequest
=
new
ServerHttpRequestDecorator
(
newRequest
)
{
@Override
public
Flux
<
DataBuffer
>
getBody
()
{
return
bodyFlux
;
}
@Override
public
HttpHeaders
getHeaders
()
{
return
headers
;
}
};
return
chain
.
filter
(
exchange
.
mutate
().
request
(
newRequest
).
build
());
});
}
else
{
return
chain
.
filter
(
exchange
);
}
}
/**
* 是否是白名单
*
* @param url 路由
* @param method 请求方式
* @return true/false
*/
private
boolean
white
(
String
url
,
String
method
)
{
return
whiteUrls
!=
null
&&
whiteUrls
.
contains
(
XssWhiteUrl
.
builder
().
url
(
url
).
method
(
method
).
build
());
}
/**
* 字节数组转DataBuffer
*
* @param bytes 字节数组
* @return DataBuffer
*/
private
DataBuffer
toDataBuffer
(
byte
[]
bytes
)
{
NettyDataBufferFactory
nettyDataBufferFactory
=
new
NettyDataBufferFactory
(
ByteBufAllocator
.
DEFAULT
);
DataBuffer
buffer
=
nettyDataBufferFactory
.
allocateBuffer
(
bytes
.
length
);
buffer
.
write
(
bytes
);
return
buffer
;
}
public
static
final
int
ORDER
=
10
;
@Override
public
int
getOrder
()
{
return
ORDER
;
}
@Data
@Validated
@AllArgsConstructor
@NoArgsConstructor
@Builder
private
static
class
XssWhiteUrl
{
@NotEmpty
private
String
url
;
@NotEmpty
private
String
method
;
}
}
arch-gateway/src/main/java/org/arch/config/xssFilter/XssUtil.java
0 → 100644
View file @
2c8ec2b
package
org
.
arch
.
config
.
xssFilter
;
import
com.alibaba.fastjson.JSONObject
;
import
org.jsoup.Jsoup
;
import
org.jsoup.nodes.Document
;
import
org.jsoup.safety.Safelist
;
import
java.util.ArrayList
;
import
java.util.List
;
import
java.util.Map
;
import
java.util.Objects
;
/**
* xss拦截工具类
*
* @author lieber
*/
public
enum
XssUtil
{
/**
* 实例
*/
INSTANCE
;
private
final
static
String
RICH_TEXT
=
"</"
;
/**
* 自定义白名单
*/
private
final
static
Safelist
CUSTOM_WHITELIST
=
Safelist
.
relaxed
()
.
addAttributes
(
"video"
,
"width"
,
"height"
,
"controls"
,
"alt"
,
"src"
)
.
addAttributes
(
":all"
,
"style"
,
"class"
);
/**
* jsoup不格式化代码
*/
private
final
static
Document
.
OutputSettings
OUTPUT_SETTINGS
=
new
Document
.
OutputSettings
().
prettyPrint
(
false
);
/**
* 清除json对象中的xss攻击字符
*
* @param val json对象字符串
* @return 清除后的json对象字符串
*/
private
String
cleanObj
(
String
val
)
{
JSONObject
jsonObject
=
JSONObject
.
parseObject
(
val
);
for
(
Map
.
Entry
<
String
,
Object
>
entry
:
jsonObject
.
entrySet
())
{
if
(
entry
.
getValue
()
!=
null
&&
entry
.
getValue
()
instanceof
String
)
{
String
str
=
(
String
)
entry
.
getValue
();
str
=
this
.
cleanXss
(
str
);
entry
.
setValue
(
str
);
}
}
return
jsonObject
.
toJSONString
();
}
/**
* 清除json数组中的xss攻击字符
*
* @param val json数组字符串
* @return 清除后的json数组字符串
*/
private
String
cleanArr
(
String
val
)
{
List
<
String
>
list
=
JSONObject
.
parseArray
(
val
,
String
.
class
);
List
<
String
>
result
=
new
ArrayList
<>(
list
.
size
());
for
(
String
str
:
list
)
{
str
=
this
.
cleanXss
(
str
);
result
.
add
(
str
);
}
return
JSONObject
.
toJSONString
(
result
);
}
/**
* 清除xss攻击字符串,此处优化空间较大
*
* @param str 字符串
* @return 清除后无害的字符串
*/
public
String
cleanXss
(
String
str
)
{
if
(
JsonUtil
.
INSTANCE
.
isJsonObj
(
str
))
{
str
=
this
.
cleanObj
(
str
);
}
else
if
(
JsonUtil
.
INSTANCE
.
isJsonArr
(
str
))
{
str
=
this
.
cleanArr
(
str
);
}
else
{
boolean
richText
=
this
.
richText
(
str
);
if
(!
richText
)
{
str
=
str
.
trim
();
str
=
str
.
replaceAll
(
" +"
,
" "
);
}
String
afterClean
=
Jsoup
.
clean
(
str
,
""
,
CUSTOM_WHITELIST
,
OUTPUT_SETTINGS
);
if
(
paramError
(
richText
,
afterClean
,
str
))
{
// throw new BizRunTimeException(ApiCode.PARAM_ERROR, "参数包含特殊字符");
throw
new
RuntimeException
(
"参数包含特殊字符"
);
}
str
=
richText
?
afterClean
:
this
.
backSpecialStr
(
afterClean
);
}
return
str
;
}
/**
* 判断是否是富文本
*
* @param str 待判断字符串
* @return true/false
*/
private
boolean
richText
(
String
str
)
{
return
str
.
contains
(
RICH_TEXT
);
}
/**
* 判断是否参数错误
*
* @param richText 是否富文本
* @param afterClean 清理后字符
* @param str 原字符串
* @return true/false
*/
private
boolean
paramError
(
boolean
richText
,
String
afterClean
,
String
str
)
{
// 如果包含富文本字符,那么不是参数错误
if
(
richText
)
{
return
false
;
}
// 如果清理后的字符和清理前的字符匹配,那么不是参数错误
if
(
Objects
.
equals
(
str
,
afterClean
))
{
return
false
;
}
// 如果仅仅包含可以通过的特殊字符,那么不是参数错误
if
(
Objects
.
equals
(
str
,
this
.
backSpecialStr
(
afterClean
)))
{
return
false
;
}
// 如果还有......
return
true
;
}
/**
* 转义回特殊字符
*
* @param str 已经通过转义字符
* @return 转义后特殊字符
*/
private
String
backSpecialStr
(
String
str
)
{
return
str
.
replaceAll
(
"&"
,
"&"
);
}
}
arch-gateway/src/main/java/org/arch/service/RedisService.java
0 → 100644
View file @
2c8ec2b
package
org
.
arch
.
service
;
import
com.alibaba.fastjson.JSON
;
import
com.alibaba.fastjson.JSONObject
;
import
org.apache.commons.lang3.StringUtils
;
import
org.slf4j.Logger
;
import
org.slf4j.LoggerFactory
;
import
org.springframework.beans.factory.annotation.Autowired
;
import
org.springframework.data.redis.connection.DataType
;
import
org.springframework.data.redis.core.*
;
import
org.springframework.stereotype.Component
;
import
java.io.Serializable
;
import
java.util.*
;
import
java.util.concurrent.TimeUnit
;
/**
* @author IceCream
* @date 2019/8/7 14:56
*/
@Component
public
class
RedisService
{
private
final
Logger
log
=
LoggerFactory
.
getLogger
(
RedisService
.
class
);
@Autowired
private
StringRedisTemplate
stringRedisTemplate
;
@Autowired
private
RedisTemplate
redisTemplate
;
/** -------------------key相关操作--------------------- */
/**
* 删除key
*
* @param key
*/
public
void
delete
(
String
key
)
{
stringRedisTemplate
.
delete
(
key
);
}
/**
* 批量删除key
*
* @param keys
*/
public
void
delete
(
Collection
<
String
>
keys
)
{
stringRedisTemplate
.
delete
(
keys
);
}
/**
* 序列化key
*
* @param key
* @return
*/
public
byte
[]
dump
(
String
key
)
{
return
stringRedisTemplate
.
dump
(
key
);
}
/**
* 是否存在key
*
* @param key
* @return
*/
public
Boolean
hasKey
(
String
key
)
{
return
stringRedisTemplate
.
hasKey
(
key
);
}
/**
* 设置过期时间
*
* @param key
* @param timeout
* @param unit
* @return
*/
public
Boolean
expire
(
String
key
,
long
timeout
,
TimeUnit
unit
)
{
return
stringRedisTemplate
.
expire
(
key
,
timeout
,
unit
);
}
/**
* 设置过期时间
*
* @param key
* @param date
* @return
*/
public
Boolean
expireAt
(
String
key
,
Date
date
)
{
return
stringRedisTemplate
.
expireAt
(
key
,
date
);
}
/**
* 查找匹配的key
*
* @param pattern
* @return
*/
public
Set
<
String
>
keys
(
String
pattern
)
{
return
stringRedisTemplate
.
keys
(
pattern
);
}
/**
* 将当前数据库的 key 移动到给定的数据库 db 当中
*
* @param key
* @param dbIndex
* @return
*/
public
Boolean
move
(
String
key
,
int
dbIndex
)
{
return
stringRedisTemplate
.
move
(
key
,
dbIndex
);
}
/**
* 移除 key 的过期时间,key 将持久保持
*
* @param key
* @return
*/
public
Boolean
persist
(
String
key
)
{
return
stringRedisTemplate
.
persist
(
key
);
}
/**
* 返回 key 的剩余的过期时间
*
* @param key
* @param unit
* @return
*/
public
Long
getExpire
(
String
key
,
TimeUnit
unit
)
{
return
stringRedisTemplate
.
getExpire
(
key
,
unit
);
}
/**
* 返回 key 的剩余的过期时间
*
* @param key
* @return
*/
public
Long
getExpire
(
String
key
)
{
return
stringRedisTemplate
.
getExpire
(
key
);
}
/**
* 从当前数据库中随机返回一个 key
*
* @return
*/
public
String
randomKey
()
{
return
stringRedisTemplate
.
randomKey
();
}
/**
* 修改 key 的名称
*
* @param oldKey
* @param newKey
*/
public
void
rename
(
String
oldKey
,
String
newKey
)
{
stringRedisTemplate
.
rename
(
oldKey
,
newKey
);
}
/**
* 仅当 newkey 不存在时,将 oldKey 改名为 newkey
*
* @param oldKey
* @param newKey
* @return
*/
public
Boolean
renameIfAbsent
(
String
oldKey
,
String
newKey
)
{
return
stringRedisTemplate
.
renameIfAbsent
(
oldKey
,
newKey
);
}
/**
* 返回 key 所储存的值的类型
*
* @param key
* @return
*/
public
DataType
type
(
String
key
)
{
return
stringRedisTemplate
.
type
(
key
);
}
/** -------------------string相关操作--------------------- */
/**
* 设置指定 key 的值
*
* @param key
* @param value
*/
public
void
set
(
String
key
,
String
value
)
{
stringRedisTemplate
.
opsForValue
().
set
(
key
,
value
);
}
/**
* 设置指定 key 的值
*
* @param key
* @param value
* @param seconds 秒值
*/
public
void
set
(
String
key
,
String
value
,
Long
seconds
)
{
stringRedisTemplate
.
opsForValue
().
set
(
key
,
value
);
stringRedisTemplate
.
expire
(
key
,
seconds
,
TimeUnit
.
SECONDS
);
}
/**
* 设置指定 key 的值
*
* @param key
* @param value
* @param seconds 秒值
*/
public
void
set
(
String
key
,
Object
value
,
Long
seconds
)
{
redisTemplate
.
opsForValue
().
set
(
key
,
value
);
redisTemplate
.
expire
(
key
,
seconds
,
TimeUnit
.
SECONDS
);
}
/**
* 获取指定 key 的值
*
* @param key
* @return
*/
public
Object
getObject
(
String
key
)
{
ValueOperations
<
Serializable
,
Object
>
operations
=
redisTemplate
.
opsForValue
();
return
operations
.
get
(
key
);
}
/**
* 是否存在key
*
* @param key
* @return
*/
public
Boolean
exists
(
String
key
)
{
return
redisTemplate
.
hasKey
(
key
);
}
/**
* 获取指定 key 的值
*
* @param key
* @return
*/
public
String
get
(
String
key
)
{
return
stringRedisTemplate
.
opsForValue
().
get
(
key
);
}
/**
* 获取指定 key 的值
*
* @param key
* @return
*/
public
<
T
>
T
get
(
String
key
,
Class
<
T
>
type
)
{
String
json
=
stringRedisTemplate
.
opsForValue
().
get
(
key
);
if
(
StringUtils
.
isEmpty
(
json
))
{
return
null
;
}
return
JSONObject
.
parseObject
(
json
,
type
);
}
/**
* 返回 key 中字符串值的子字符
*
* @param key
* @param start
* @param end
* @return
*/
public
String
getRange
(
String
key
,
long
start
,
long
end
)
{
return
stringRedisTemplate
.
opsForValue
().
get
(
key
,
start
,
end
);
}
/**
* 将给定 key 的值设为 value ,并返回 key 的旧值(old value)
*
* @param key
* @param value
* @return
*/
public
String
getAndSet
(
String
key
,
String
value
)
{
return
stringRedisTemplate
.
opsForValue
().
getAndSet
(
key
,
value
);
}
/**
* 对 key 所储存的字符串值,获取指定偏移量上的位(bit)
*
* @param key
* @param offset
* @return
*/
public
Boolean
getBit
(
String
key
,
long
offset
)
{
return
stringRedisTemplate
.
opsForValue
().
getBit
(
key
,
offset
);
}
/**
* 批量获取
*
* @param keys
* @return
*/
public
List
<
String
>
multiGet
(
Collection
<
String
>
keys
)
{
return
stringRedisTemplate
.
opsForValue
().
multiGet
(
keys
);
}
/**
* 设置ASCII码, 字符串'a'的ASCII码是97, 转为二进制是'01100001', 此方法是将二进制第offset位值变为value
*
* @param key
* @param offset 位置
* @param value 值,true为1, false为0
* @return
*/
public
boolean
setBit
(
String
key
,
long
offset
,
boolean
value
)
{
return
stringRedisTemplate
.
opsForValue
().
setBit
(
key
,
offset
,
value
);
}
/**
* 将值 value 关联到 key ,并将 key 的过期时间设为 timeout
*
* @param key
* @param value
* @param timeout 过期时间
* @param unit 时间单位, 天:TimeUnit.DAYS 小时:TimeUnit.HOURS 分钟:TimeUnit.MINUTES
* 秒:TimeUnit.SECONDS 毫秒:TimeUnit.MILLISECONDS
*/
public
void
setEx
(
String
key
,
String
value
,
long
timeout
,
TimeUnit
unit
)
{
stringRedisTemplate
.
opsForValue
().
set
(
key
,
value
,
timeout
,
unit
);
}
/**
* 只有在 key 不存在时设置 key 的值
*
* @param key
* @param value
* @return 之前已经存在返回false, 不存在返回true
*/
public
boolean
setIfAbsent
(
String
key
,
String
value
)
{
return
stringRedisTemplate
.
opsForValue
().
setIfAbsent
(
key
,
value
);
}
/**
* 用 value 参数覆写给定 key 所储存的字符串值,从偏移量 offset 开始
*
* @param key
* @param value
* @param offset 从指定位置开始覆写
*/
public
void
setRange
(
String
key
,
String
value
,
long
offset
)
{
stringRedisTemplate
.
opsForValue
().
set
(
key
,
value
,
offset
);
}
/**
* 获取字符串的长度
*
* @param key
* @return
*/
public
Long
size
(
String
key
)
{
return
stringRedisTemplate
.
opsForValue
().
size
(
key
);
}
/**
* 批量添加
*
* @param maps
*/
public
void
multiSet
(
Map
<
String
,
String
>
maps
)
{
stringRedisTemplate
.
opsForValue
().
multiSet
(
maps
);
}
/**
* 同时设置一个或多个 key-value 对,当且仅当所有给定 key 都不存在
*
* @param maps
* @return 之前已经存在返回false, 不存在返回true
*/
public
boolean
multiSetIfAbsent
(
Map
<
String
,
String
>
maps
)
{
return
stringRedisTemplate
.
opsForValue
().
multiSetIfAbsent
(
maps
);
}
/**
* 增加(自增长), 负数则为自减
*
* @param key
* @param increment
* @return
*/
public
Long
incrBy
(
String
key
,
long
increment
)
{
return
stringRedisTemplate
.
opsForValue
().
increment
(
key
,
increment
);
}
/**
* @param key
* @param increment
* @return
*/
public
Double
incrByFloat
(
String
key
,
double
increment
)
{
return
stringRedisTemplate
.
opsForValue
().
increment
(
key
,
increment
);
}
/**
* 追加到末尾
*
* @param key
* @param value
* @return
*/
public
Integer
append
(
String
key
,
String
value
)
{
return
stringRedisTemplate
.
opsForValue
().
append
(
key
,
value
);
}
/** -------------------hash相关操作------------------------- */
/**
* 获取存储在哈希表中指定字段的值
*
* @param key
* @param field
* @return
*/
public
Object
hGet
(
String
key
,
String
field
)
{
return
stringRedisTemplate
.
opsForHash
().
get
(
key
,
field
);
}
/**
* 获取所有给定字段的值
*
* @param key
* @return
*/
public
Map
<
Object
,
Object
>
hGetAll
(
String
key
)
{
return
stringRedisTemplate
.
opsForHash
().
entries
(
key
);
}
/**
* 获取所有给定字段的值
*
* @param key
* @param fields
* @return
*/
public
List
<
Object
>
hMultiGet
(
String
key
,
Collection
<
Object
>
fields
)
{
return
stringRedisTemplate
.
opsForHash
().
multiGet
(
key
,
fields
);
}
public
void
hPut
(
String
key
,
String
hashKey
,
String
value
)
{
stringRedisTemplate
.
opsForHash
().
put
(
key
,
hashKey
,
value
);
}
public
void
hPutAll
(
String
key
,
Map
<
String
,
String
>
maps
)
{
stringRedisTemplate
.
opsForHash
().
putAll
(
key
,
maps
);
}
/**
* 仅当hashKey不存在时才设置
*
* @param key
* @param hashKey
* @param value
* @return
*/
public
Boolean
hPutIfAbsent
(
String
key
,
String
hashKey
,
String
value
)
{
return
stringRedisTemplate
.
opsForHash
().
putIfAbsent
(
key
,
hashKey
,
value
);
}
/**
* 删除一个或多个哈希表字段
*
* @param key
* @param fields
* @return
*/
public
Long
hDelete
(
String
key
,
Object
...
fields
)
{
return
stringRedisTemplate
.
opsForHash
().
delete
(
key
,
fields
);
}
/**
* 查看哈希表 key 中,指定的字段是否存在
*
* @param key
* @param field
* @return
*/
public
boolean
hExists
(
String
key
,
String
field
)
{
return
stringRedisTemplate
.
opsForHash
().
hasKey
(
key
,
field
);
}
/**
* 为哈希表 key 中的指定字段的整数值加上增量 increment
*
* @param key
* @param field
* @param increment
* @return
*/
public
Long
hIncrBy
(
String
key
,
Object
field
,
long
increment
)
{
return
stringRedisTemplate
.
opsForHash
().
increment
(
key
,
field
,
increment
);
}
/**
* 为哈希表 key 中的指定字段的整数值加上增量 increment
*
* @param key
* @param field
* @param delta
* @return
*/
public
Double
hIncrByFloat
(
String
key
,
Object
field
,
double
delta
)
{
return
stringRedisTemplate
.
opsForHash
().
increment
(
key
,
field
,
delta
);
}
/**
* 获取所有哈希表中的字段
*
* @param key
* @return
*/
public
Set
<
Object
>
hKeys
(
String
key
)
{
return
stringRedisTemplate
.
opsForHash
().
keys
(
key
);
}
/**
* 获取哈希表中字段的数量
*
* @param key
* @return
*/
public
Long
hSize
(
String
key
)
{
return
stringRedisTemplate
.
opsForHash
().
size
(
key
);
}
/**
* 获取哈希表中所有值
*
* @param key
* @return
*/
public
List
<
Object
>
hValues
(
String
key
)
{
return
stringRedisTemplate
.
opsForHash
().
values
(
key
);
}
/**
* 迭代哈希表中的键值对
*
* @param key
* @param options
* @return
*/
public
Cursor
<
Map
.
Entry
<
Object
,
Object
>>
hScan
(
String
key
,
ScanOptions
options
)
{
return
stringRedisTemplate
.
opsForHash
().
scan
(
key
,
options
);
}
/** ------------------------list相关操作---------------------------- */
/**
* 通过索引获取列表中的元素
*
* @param key
* @param index
* @return
*/
public
String
lIndex
(
String
key
,
long
index
)
{
return
stringRedisTemplate
.
opsForList
().
index
(
key
,
index
);
}
/**
* 获取列表指定范围内的元素
*
* @param key
* @param start 开始位置, 0是开始位置
* @param end 结束位置, -1返回所有
* @return
*/
public
List
<
String
>
lRange
(
String
key
,
long
start
,
long
end
)
{
return
stringRedisTemplate
.
opsForList
().
range
(
key
,
start
,
end
);
}
/**
* 存储在list头部
*
* @param key
* @param value
* @return
*/
public
Long
lLeftPush
(
String
key
,
String
value
)
{
return
stringRedisTemplate
.
opsForList
().
leftPush
(
key
,
value
);
}
/**
* @param key
* @param value
* @return
*/
public
Long
lLeftPushAll
(
String
key
,
String
...
value
)
{
return
stringRedisTemplate
.
opsForList
().
leftPushAll
(
key
,
value
);
}
/**
* @param key
* @param value
* @return
*/
public
Long
lLeftPushAll
(
String
key
,
Collection
<
String
>
value
)
{
return
stringRedisTemplate
.
opsForList
().
leftPushAll
(
key
,
value
);
}
/**
* 当list存在的时候才加入
*
* @param key
* @param value
* @return
*/
public
Long
lLeftPushIfPresent
(
String
key
,
String
value
)
{
return
stringRedisTemplate
.
opsForList
().
leftPushIfPresent
(
key
,
value
);
}
/**
* 如果pivot存在,再pivot前面添加
*
* @param key
* @param pivot
* @param value
* @return
*/
public
Long
lLeftPush
(
String
key
,
String
pivot
,
String
value
)
{
return
stringRedisTemplate
.
opsForList
().
leftPush
(
key
,
pivot
,
value
);
}
/**
* @param key
* @param value
* @return
*/
public
Long
lRightPush
(
String
key
,
String
value
)
{
return
stringRedisTemplate
.
opsForList
().
rightPush
(
key
,
value
);
}
/**
* @param key
* @param value
* @return
*/
public
Long
lRightPushAll
(
String
key
,
String
...
value
)
{
return
stringRedisTemplate
.
opsForList
().
rightPushAll
(
key
,
value
);
}
/**
* @param key
* @param value
* @return
*/
public
Long
lRightPushAll
(
String
key
,
Collection
<
String
>
value
)
{
return
stringRedisTemplate
.
opsForList
().
rightPushAll
(
key
,
value
);
}
/**
* 为已存在的列表添加值
*
* @param key
* @param value
* @return
*/
public
Long
lRightPushIfPresent
(
String
key
,
String
value
)
{
return
stringRedisTemplate
.
opsForList
().
rightPushIfPresent
(
key
,
value
);
}
/**
* 在pivot元素的右边添加值
*
* @param key
* @param pivot
* @param value
* @return
*/
public
Long
lRightPush
(
String
key
,
String
pivot
,
String
value
)
{
return
stringRedisTemplate
.
opsForList
().
rightPush
(
key
,
pivot
,
value
);
}
/**
* 通过索引设置列表元素的值
*
* @param key
* @param index 位置
* @param value
*/
public
void
lSet
(
String
key
,
long
index
,
String
value
)
{
stringRedisTemplate
.
opsForList
().
set
(
key
,
index
,
value
);
}
/**
* 移出并获取列表的第一个元素
*
* @param key
* @return 删除的元素
*/
public
String
lLeftPop
(
String
key
)
{
return
stringRedisTemplate
.
opsForList
().
leftPop
(
key
);
}
/**
* 移出并获取列表的第一个元素, 如果列表没有元素会阻塞列表直到等待超时或发现可弹出元素为止
*
* @param key
* @param timeout 等待时间
* @param unit 时间单位
* @return
*/
public
String
lBLeftPop
(
String
key
,
long
timeout
,
TimeUnit
unit
)
{
return
stringRedisTemplate
.
opsForList
().
leftPop
(
key
,
timeout
,
unit
);
}
/**
* 移除并获取列表最后一个元素
*
* @param key
* @return 删除的元素
*/
public
String
lRightPop
(
String
key
)
{
return
stringRedisTemplate
.
opsForList
().
rightPop
(
key
);
}
/**
* 移出并获取列表的最后一个元素, 如果列表没有元素会阻塞列表直到等待超时或发现可弹出元素为止
*
* @param key
* @param timeout 等待时间
* @param unit 时间单位
* @return
*/
public
String
lBRightPop
(
String
key
,
long
timeout
,
TimeUnit
unit
)
{
return
stringRedisTemplate
.
opsForList
().
rightPop
(
key
,
timeout
,
unit
);
}
/**
* 移除列表的最后一个元素,并将该元素添加到另一个列表并返回
*
* @param sourceKey
* @param destinationKey
* @return
*/
public
String
lRightPopAndLeftPush
(
String
sourceKey
,
String
destinationKey
)
{
return
stringRedisTemplate
.
opsForList
().
rightPopAndLeftPush
(
sourceKey
,
destinationKey
);
}
/**
* 从列表中弹出一个值,将弹出的元素插入到另外一个列表中并返回它; 如果列表没有元素会阻塞列表直到等待超时或发现可弹出元素为止
*
* @param sourceKey
* @param destinationKey
* @param timeout
* @param unit
* @return
*/
public
String
lBRightPopAndLeftPush
(
String
sourceKey
,
String
destinationKey
,
long
timeout
,
TimeUnit
unit
)
{
return
stringRedisTemplate
.
opsForList
().
rightPopAndLeftPush
(
sourceKey
,
destinationKey
,
timeout
,
unit
);
}
/**
* 删除集合中值等于value得元素
*
* @param key
* @param index index=0, 删除所有值等于value的元素; index>0, 从头部开始删除第一个值等于value的元素;
* index<0, 从尾部开始删除第一个值等于value的元素;
* @param value
* @return
*/
public
Long
lRemove
(
String
key
,
long
index
,
String
value
)
{
return
stringRedisTemplate
.
opsForList
().
remove
(
key
,
index
,
value
);
}
/**
* 裁剪list
*
* @param key
* @param start
* @param end
*/
public
void
lTrim
(
String
key
,
long
start
,
long
end
)
{
stringRedisTemplate
.
opsForList
().
trim
(
key
,
start
,
end
);
}
/**
* 获取列表长度
*
* @param key
* @return
*/
public
Long
lLen
(
String
key
)
{
return
stringRedisTemplate
.
opsForList
().
size
(
key
);
}
/** --------------------set相关操作-------------------------- */
/**
* set添加元素
*
* @param key
* @param values
* @return
*/
public
Long
sAdd
(
String
key
,
String
...
values
)
{
return
stringRedisTemplate
.
opsForSet
().
add
(
key
,
values
);
}
/**
* set移除元素
*
* @param key
* @param values
* @return
*/
public
Long
sRemove
(
String
key
,
Object
...
values
)
{
return
stringRedisTemplate
.
opsForSet
().
remove
(
key
,
values
);
}
/**
* 移除并返回集合的一个随机元素
*
* @param key
* @return
*/
public
String
sPop
(
String
key
)
{
return
stringRedisTemplate
.
opsForSet
().
pop
(
key
);
}
/**
* 将元素value从一个集合移到另一个集合
*
* @param key
* @param value
* @param destKey
* @return
*/
public
Boolean
sMove
(
String
key
,
String
value
,
String
destKey
)
{
return
stringRedisTemplate
.
opsForSet
().
move
(
key
,
value
,
destKey
);
}
/**
* 获取集合的大小
*
* @param key
* @return
*/
public
Long
sSize
(
String
key
)
{
return
stringRedisTemplate
.
opsForSet
().
size
(
key
);
}
/**
* 判断集合是否包含value
*
* @param key
* @param value
* @return
*/
public
Boolean
sIsMember
(
String
key
,
Object
value
)
{
return
stringRedisTemplate
.
opsForSet
().
isMember
(
key
,
value
);
}
/**
* 获取两个集合的交集
*
* @param key
* @param otherKey
* @return
*/
public
Set
<
String
>
sIntersect
(
String
key
,
String
otherKey
)
{
return
stringRedisTemplate
.
opsForSet
().
intersect
(
key
,
otherKey
);
}
/**
* 获取key集合与多个集合的交集
*
* @param key
* @param otherKeys
* @return
*/
public
Set
<
String
>
sIntersect
(
String
key
,
Collection
<
String
>
otherKeys
)
{
return
stringRedisTemplate
.
opsForSet
().
intersect
(
key
,
otherKeys
);
}
/**
* key集合与otherKey集合的交集存储到destKey集合中
*
* @param key
* @param otherKey
* @param destKey
* @return
*/
public
Long
sIntersectAndStore
(
String
key
,
String
otherKey
,
String
destKey
)
{
return
stringRedisTemplate
.
opsForSet
().
intersectAndStore
(
key
,
otherKey
,
destKey
);
}
/**
* key集合与多个集合的交集存储到destKey集合中
*
* @param key
* @param otherKeys
* @param destKey
* @return
*/
public
Long
sIntersectAndStore
(
String
key
,
Collection
<
String
>
otherKeys
,
String
destKey
)
{
return
stringRedisTemplate
.
opsForSet
().
intersectAndStore
(
key
,
otherKeys
,
destKey
);
}
/**
* 获取两个集合的并集
*
* @param key
* @param otherKeys
* @return
*/
public
Set
<
String
>
sUnion
(
String
key
,
String
otherKeys
)
{
return
stringRedisTemplate
.
opsForSet
().
union
(
key
,
otherKeys
);
}
/**
* 获取key集合与多个集合的并集
*
* @param key
* @param otherKeys
* @return
*/
public
Set
<
String
>
sUnion
(
String
key
,
Collection
<
String
>
otherKeys
)
{
return
stringRedisTemplate
.
opsForSet
().
union
(
key
,
otherKeys
);
}
/**
* key集合与otherKey集合的并集存储到destKey中
*
* @param key
* @param otherKey
* @param destKey
* @return
*/
public
Long
sUnionAndStore
(
String
key
,
String
otherKey
,
String
destKey
)
{
return
stringRedisTemplate
.
opsForSet
().
unionAndStore
(
key
,
otherKey
,
destKey
);
}
/**
* key集合与多个集合的并集存储到destKey中
*
* @param key
* @param otherKeys
* @param destKey
* @return
*/
public
Long
sUnionAndStore
(
String
key
,
Collection
<
String
>
otherKeys
,
String
destKey
)
{
return
stringRedisTemplate
.
opsForSet
().
unionAndStore
(
key
,
otherKeys
,
destKey
);
}
/**
* 获取两个集合的差集
*
* @param key
* @param otherKey
* @return
*/
public
Set
<
String
>
sDifference
(
String
key
,
String
otherKey
)
{
return
stringRedisTemplate
.
opsForSet
().
difference
(
key
,
otherKey
);
}
/**
* 获取key集合与多个集合的差集
*
* @param key
* @param otherKeys
* @return
*/
public
Set
<
String
>
sDifference
(
String
key
,
Collection
<
String
>
otherKeys
)
{
return
stringRedisTemplate
.
opsForSet
().
difference
(
key
,
otherKeys
);
}
/**
* key集合与otherKey集合的差集存储到destKey中
*
* @param key
* @param otherKey
* @param destKey
* @return
*/
public
Long
sDifference
(
String
key
,
String
otherKey
,
String
destKey
)
{
return
stringRedisTemplate
.
opsForSet
().
differenceAndStore
(
key
,
otherKey
,
destKey
);
}
/**
* key集合与多个集合的差集存储到destKey中
*
* @param key
* @param otherKeys
* @param destKey
* @return
*/
public
Long
sDifference
(
String
key
,
Collection
<
String
>
otherKeys
,
String
destKey
)
{
return
stringRedisTemplate
.
opsForSet
().
differenceAndStore
(
key
,
otherKeys
,
destKey
);
}
/**
* 获取集合所有元素
*
* @param key
* @return
*/
public
Set
<
String
>
setMembers
(
String
key
)
{
return
stringRedisTemplate
.
opsForSet
().
members
(
key
);
}
/**
* 随机获取集合中的一个元素
*
* @param key
* @return
*/
public
String
sRandomMember
(
String
key
)
{
return
stringRedisTemplate
.
opsForSet
().
randomMember
(
key
);
}
/**
* 随机获取集合中count个元素
*
* @param key
* @param count
* @return
*/
public
List
<
String
>
sRandomMembers
(
String
key
,
long
count
)
{
return
stringRedisTemplate
.
opsForSet
().
randomMembers
(
key
,
count
);
}
/**
* 随机获取集合中count个元素并且去除重复的
*
* @param key
* @param count
* @return
*/
public
Set
<
String
>
sDistinctRandomMembers
(
String
key
,
long
count
)
{
return
stringRedisTemplate
.
opsForSet
().
distinctRandomMembers
(
key
,
count
);
}
/**
* @param key
* @param options
* @return
*/
public
Cursor
<
String
>
sScan
(
String
key
,
ScanOptions
options
)
{
return
stringRedisTemplate
.
opsForSet
().
scan
(
key
,
options
);
}
/**------------------zSet相关操作--------------------------------*/
/**
* 添加元素,有序集合是按照元素的score值由小到大排列
*
* @param key
* @param value
* @param score
* @return
*/
public
Boolean
zAdd
(
String
key
,
String
value
,
double
score
)
{
return
stringRedisTemplate
.
opsForZSet
().
add
(
key
,
value
,
score
);
}
/**
* @param key
* @param values
* @return
*/
public
Long
zAdd
(
String
key
,
Set
<
ZSetOperations
.
TypedTuple
<
String
>>
values
)
{
return
stringRedisTemplate
.
opsForZSet
().
add
(
key
,
values
);
}
/**
* @param key
* @param values
* @return
*/
public
Long
zRemove
(
String
key
,
Object
...
values
)
{
return
stringRedisTemplate
.
opsForZSet
().
remove
(
key
,
values
);
}
/**
* 增加元素的score值,并返回增加后的值
*
* @param key
* @param value
* @param delta
* @return
*/
public
Double
zIncrementScore
(
String
key
,
String
value
,
double
delta
)
{
return
stringRedisTemplate
.
opsForZSet
().
incrementScore
(
key
,
value
,
delta
);
}
/**
* 返回元素在集合的排名,有序集合是按照元素的score值由小到大排列
*
* @param key
* @param value
* @return 0表示第一位
*/
public
Long
zRank
(
String
key
,
Object
value
)
{
return
stringRedisTemplate
.
opsForZSet
().
rank
(
key
,
value
);
}
/**
* 返回元素在集合的排名,按元素的score值由大到小排列
*
* @param key
* @param value
* @return
*/
public
Long
zReverseRank
(
String
key
,
Object
value
)
{
return
stringRedisTemplate
.
opsForZSet
().
reverseRank
(
key
,
value
);
}
/**
* 获取集合的元素, 从小到大排序
*
* @param key
* @param start 开始位置
* @param end 结束位置, -1查询所有
* @return
*/
public
Set
<
String
>
zRange
(
String
key
,
long
start
,
long
end
)
{
return
stringRedisTemplate
.
opsForZSet
().
range
(
key
,
start
,
end
);
}
/**
* 获取集合元素, 并且把score值也获取
*
* @param key
* @param start
* @param end
* @return
*/
public
Set
<
ZSetOperations
.
TypedTuple
<
String
>>
zRangeWithScores
(
String
key
,
long
start
,
long
end
)
{
return
stringRedisTemplate
.
opsForZSet
().
rangeWithScores
(
key
,
start
,
end
);
}
/**
* 根据Score值查询集合元素
*
* @param key
* @param min 最小值
* @param max 最大值
* @return
*/
public
Set
<
String
>
zRangeByScore
(
String
key
,
double
min
,
double
max
)
{
return
stringRedisTemplate
.
opsForZSet
().
rangeByScore
(
key
,
min
,
max
);
}
/**
* 根据Score值查询集合元素, 从小到大排序
*
* @param key
* @param min 最小值
* @param max 最大值
* @return
*/
public
Set
<
ZSetOperations
.
TypedTuple
<
String
>>
zRangeByScoreWithScores
(
String
key
,
double
min
,
double
max
)
{
return
stringRedisTemplate
.
opsForZSet
().
rangeByScoreWithScores
(
key
,
min
,
max
);
}
/**
* @param key
* @param min
* @param max
* @param start
* @param end
* @return
*/
public
Set
<
ZSetOperations
.
TypedTuple
<
String
>>
zRangeByScoreWithScores
(
String
key
,
double
min
,
double
max
,
long
start
,
long
end
)
{
return
stringRedisTemplate
.
opsForZSet
().
rangeByScoreWithScores
(
key
,
min
,
max
,
start
,
end
);
}
/**
* 获取集合的元素, 从大到小排序
*
* @param key
* @param start
* @param end
* @return
*/
public
Set
<
String
>
zReverseRange
(
String
key
,
long
start
,
long
end
)
{
return
stringRedisTemplate
.
opsForZSet
().
reverseRange
(
key
,
start
,
end
);
}
/**
* 获取集合的元素, 从大到小排序, 并返回score值
*
* @param key
* @param start
* @param end
* @return
*/
public
Set
<
ZSetOperations
.
TypedTuple
<
String
>>
zReverseRangeWithScores
(
String
key
,
long
start
,
long
end
)
{
return
stringRedisTemplate
.
opsForZSet
().
reverseRangeWithScores
(
key
,
start
,
end
);
}
/**
* 根据Score值查询集合元素, 从大到小排序
*
* @param key
* @param min
* @param max
* @return
*/
public
Set
<
String
>
zReverseRangeByScore
(
String
key
,
double
min
,
double
max
)
{
return
stringRedisTemplate
.
opsForZSet
().
reverseRangeByScore
(
key
,
min
,
max
);
}
/**
* 根据Score值查询集合元素, 从大到小排序
*
* @param key
* @param min
* @param max
* @return
*/
public
Set
<
ZSetOperations
.
TypedTuple
<
String
>>
zReverseRangeByScoreWithScores
(
String
key
,
double
min
,
double
max
)
{
return
stringRedisTemplate
.
opsForZSet
().
reverseRangeByScoreWithScores
(
key
,
min
,
max
);
}
/**
* @param key
* @param min
* @param max
* @param start
* @param end
* @return
*/
public
Set
<
String
>
zReverseRangeByScore
(
String
key
,
double
min
,
double
max
,
long
start
,
long
end
)
{
return
stringRedisTemplate
.
opsForZSet
().
reverseRangeByScore
(
key
,
min
,
max
,
start
,
end
);
}
/**
* 根据score值获取集合元素数量
*
* @param key
* @param min
* @param max
* @return
*/
public
Long
zCount
(
String
key
,
double
min
,
double
max
)
{
return
stringRedisTemplate
.
opsForZSet
().
count
(
key
,
min
,
max
);
}
/**
* 获取集合大小
*
* @param key
* @return
*/
public
Long
zSize
(
String
key
)
{
return
stringRedisTemplate
.
opsForZSet
().
size
(
key
);
}
/**
* 获取集合大小
*
* @param key
* @return
*/
public
Long
zZCard
(
String
key
)
{
return
stringRedisTemplate
.
opsForZSet
().
zCard
(
key
);
}
/**
* 获取集合中value元素的score值
*
* @param key
* @param value
* @return
*/
public
Double
zScore
(
String
key
,
Object
value
)
{
return
stringRedisTemplate
.
opsForZSet
().
score
(
key
,
value
);
}
/**
* 移除指定索引位置的成员
*
* @param key
* @param start
* @param end
* @return
*/
public
Long
zRemoveRange
(
String
key
,
long
start
,
long
end
)
{
return
stringRedisTemplate
.
opsForZSet
().
removeRange
(
key
,
start
,
end
);
}
/**
* 根据指定的score值的范围来移除成员
*
* @param key
* @param min
* @param max
* @return
*/
public
Long
zRemoveRangeByScore
(
String
key
,
double
min
,
double
max
)
{
return
stringRedisTemplate
.
opsForZSet
().
removeRangeByScore
(
key
,
min
,
max
);
}
/**
* 获取key和otherKey的并集并存储在destKey中
*
* @param key
* @param otherKey
* @param destKey
* @return
*/
public
Long
zUnionAndStore
(
String
key
,
String
otherKey
,
String
destKey
)
{
return
stringRedisTemplate
.
opsForZSet
().
unionAndStore
(
key
,
otherKey
,
destKey
);
}
/**
* @param key
* @param otherKeys
* @param destKey
* @return
*/
public
Long
zUnionAndStore
(
String
key
,
Collection
<
String
>
otherKeys
,
String
destKey
)
{
return
stringRedisTemplate
.
opsForZSet
()
.
unionAndStore
(
key
,
otherKeys
,
destKey
);
}
/**
* 交集
*
* @param key
* @param otherKey
* @param destKey
* @return
*/
public
Long
zIntersectAndStore
(
String
key
,
String
otherKey
,
String
destKey
)
{
return
stringRedisTemplate
.
opsForZSet
().
intersectAndStore
(
key
,
otherKey
,
destKey
);
}
/**
* 交集
*
* @param key
* @param otherKeys
* @param destKey
* @return
*/
public
Long
zIntersectAndStore
(
String
key
,
Collection
<
String
>
otherKeys
,
String
destKey
)
{
return
stringRedisTemplate
.
opsForZSet
().
intersectAndStore
(
key
,
otherKeys
,
destKey
);
}
/**
* @param key
* @param options
* @return
*/
public
Cursor
<
ZSetOperations
.
TypedTuple
<
String
>>
zScan
(
String
key
,
ScanOptions
options
)
{
return
stringRedisTemplate
.
opsForZSet
().
scan
(
key
,
options
);
}
/* ************基于Redis发布订阅实现异步消息系统的同步调用*************/
/**
* 发布消息
*
* @param key key值
* @param value value
*/
public
void
release
(
String
key
,
Object
value
)
{
log
.
info
(
"redis-key={}-value={}"
,
key
,
value
);
stringRedisTemplate
.
convertAndSend
(
key
,
JSON
.
toJSONString
(
value
));
}
/**
* redis获取自增序列,获取唯一Id
*
* @param key
* @param hashKey
* @return
*/
public
Long
incrementHash
(
String
key
,
String
hashKey
)
{
return
stringRedisTemplate
.
opsForHash
().
increment
(
key
,
hashKey
,
1L
);
}
}
arch-gateway/src/main/java/org/arch/systemLog/GatewayLog.java
0 → 100644
View file @
2c8ec2b
package
org
.
arch
.
systemLog
;
import
lombok.AllArgsConstructor
;
import
lombok.Builder
;
import
lombok.Data
;
import
lombok.NoArgsConstructor
;
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public
class
GatewayLog
{
/**请求来源**/
private
String
origin
;
/**访问实例*/
private
String
targetServer
;
/**请求路径*/
private
String
requestPath
;
/**请求方法*/
private
String
requestMethod
;
/**协议 */
private
String
schema
;
/**请求类型 */
private
String
requestContentType
;
/**请求头 */
private
String
headers
;
/**请求体*/
private
String
requestBody
;
/**响应体*/
private
String
responseData
;
/**请求ip*/
private
String
ip
;
/**IP所属城市*/
private
String
city
;
/**开始时间*/
private
Long
startTime
;
/**结束时间*/
private
Long
endTime
;
/**请求时间*/
private
String
requestTime
;
/**响应时间*/
private
String
responseTime
;
/**执行时间*/
private
long
executeTime
;
/**路由配置*/
private
String
routeConfig
;
/**响应状态*/
private
String
status
;
}
arch-gateway/src/main/java/org/arch/util/Base64ConvertUtil.java
0 → 100644
View file @
2c8ec2b
package
org
.
arch
.
util
;
import
java.io.UnsupportedEncodingException
;
import
java.util.Base64
;
/**
* Base64工具
* @author dolyw.com
* @date 2018/8/21 15:14
*/
public
class
Base64ConvertUtil
{
private
Base64ConvertUtil
()
{}
/**
* 加密JDK1.8
* @param str
* @return java.lang.String
* @author dolyw.com
* @date 2018/8/21 15:28
*/
public
static
String
encode
(
String
str
)
throws
UnsupportedEncodingException
{
byte
[]
encodeBytes
=
Base64
.
getEncoder
().
encode
(
str
.
getBytes
(
"utf-8"
));
return
new
String
(
encodeBytes
);
}
/**
* 解密JDK1.8
* @param str
* @return java.lang.String
* @author dolyw.com
* @date 2018/8/21 15:28
*/
public
static
String
decode
(
String
str
)
throws
UnsupportedEncodingException
{
byte
[]
decodeBytes
=
Base64
.
getDecoder
().
decode
(
str
.
getBytes
(
"utf-8"
));
return
new
String
(
decodeBytes
);
}
}
arch-gateway/src/main/java/org/arch/util/JwtUtil.java
0 → 100644
View file @
2c8ec2b
package
org
.
arch
.
util
;
import
com.auth0.jwt.JWT
;
import
com.auth0.jwt.JWTVerifier
;
import
com.auth0.jwt.algorithms.Algorithm
;
import
com.auth0.jwt.exceptions.JWTDecodeException
;
import
com.auth0.jwt.interfaces.DecodedJWT
;
import
org.slf4j.Logger
;
import
org.slf4j.LoggerFactory
;
import
org.springframework.beans.factory.annotation.Value
;
import
org.springframework.stereotype.Component
;
import
org.springframework.web.context.request.ServletRequestAttributes
;
import
javax.servlet.http.HttpServletRequest
;
import
java.io.UnsupportedEncodingException
;
import
java.util.Date
;
import
static
org
.
springframework
.
web
.
context
.
request
.
RequestContextHolder
.
getRequestAttributes
;
/**
* JAVA-JWT工具类
* @author Wang926454
* @date 2018/8/30 11:45
*/
@Component
public
class
JwtUtil
{
/**
* logger
*/
private
static
final
Logger
logger
=
LoggerFactory
.
getLogger
(
JwtUtil
.
class
);
/**
* 过期时间改为从配置文件获取
*/
private
static
String
accessTokenExpireTime
;
/**
* JWT认证加密私钥(Base64加密)
*/
private
static
String
encryptJWTKey
;
@Value
(
"${accessTokenExpireTime}"
)
public
void
setAccessTokenExpireTime
(
String
accessTokenExpireTime
)
{
JwtUtil
.
accessTokenExpireTime
=
accessTokenExpireTime
;
}
public
static
HttpServletRequest
getRequest
()
{
// RequestAttributes requestAttributes = getRequestAttributes();
return
((
ServletRequestAttributes
)
getRequestAttributes
()).
getRequest
();
}
public
static
String
getToken
()
{
HttpServletRequest
request
=
getRequest
();
return
request
.
getHeader
(
"Authorization"
);
}
@Value
(
"${encryptJWTKey}"
)
public
void
setEncryptJWTKey
(
String
encryptJWTKey
)
{
JwtUtil
.
encryptJWTKey
=
encryptJWTKey
;
}
/**
* 校验token是否正确
* @param token Token
* @return boolean 是否正确
* @author Wang926454
* @date 2018/8/31 9:05
*/
public
static
boolean
verify
(
String
token
)
{
try
{
// 帐号加JWT私钥解密
String
secret
=
getClaim
(
token
,
"account"
)
+
Base64ConvertUtil
.
decode
(
encryptJWTKey
);
Algorithm
algorithm
=
Algorithm
.
HMAC256
(
secret
);
JWTVerifier
verifier
=
JWT
.
require
(
algorithm
).
build
();
verifier
.
verify
(
token
);
return
true
;
}
catch
(
Exception
e
)
{
logger
.
error
(
"JWTToken认证解密出现UnsupportedEncodingException异常:{}"
,
e
.
getMessage
());
return
false
;
// throw new RuntimeException("JWTToken认证解密出现UnsupportedEncodingException异常:" + e.getMessage());
}
}
/**
* 获得Token中的信息无需secret解密也能获得
* @param token
* @param claim
* @return java.lang.String
* @author Wang926454
* @date 2018/9/7 16:54
*/
public
static
String
getClaim
(
String
token
,
String
claim
)
{
try
{
DecodedJWT
jwt
=
JWT
.
decode
(
token
);
// 只能输出String类型,如果是其他类型返回null
return
jwt
.
getClaim
(
claim
).
asString
();
}
catch
(
JWTDecodeException
e
)
{
logger
.
error
(
"解密Token中的公共信息出现JWTDecodeException异常:{},token:{}"
,
e
.
getMessage
(),
token
);
throw
new
RuntimeException
(
"解密Token中的公共信息出现JWTDecodeException异常:"
+
e
.
getMessage
()+
",token---->"
+
token
);
}
}
/**
* 用户
* @param account
* @param currentTimeMillis
* @return
*/
public
static
String
sign
(
String
account
,
String
currentTimeMillis
)
throws
Exception
{
if
(
StringUtils
.
isBlank
(
account
)){
throw
new
Exception
(
"用户账户信息为空!"
);
}
try
{
// 帐号加JWT私钥加密
String
secret
=
account
+
Base64ConvertUtil
.
decode
(
encryptJWTKey
);
// 此处过期时间是以毫秒为单位,所以乘以1000
Date
date
=
new
Date
(
System
.
currentTimeMillis
()
+
Long
.
parseLong
(
accessTokenExpireTime
)
*
1000
);
Algorithm
algorithm
=
Algorithm
.
HMAC256
(
secret
);
// 附带account帐号信息
return
JWT
.
create
()
.
withClaim
(
"account"
,
account
)
.
withClaim
(
"currentTimeMillis"
,
currentTimeMillis
)
.
withExpiresAt
(
date
)
.
sign
(
algorithm
);
}
catch
(
UnsupportedEncodingException
e
)
{
logger
.
error
(
"JWTToken加密出现UnsupportedEncodingException异常:{}"
,
e
.
getMessage
());
throw
new
RuntimeException
(
"JWTToken加密出现UnsupportedEncodingException异常:"
+
e
.
getMessage
());
}
}
}
arch-gateway/src/main/java/org/arch/util/StringUtils.java
0 → 100644
View file @
2c8ec2b
/**
* Copyright (C) 2018-2020
* All rights reserved, Designed By www.yixiang.co
* 注意:
* 本软件为www.yixiang.co开发研制
*/
package
org
.
arch
.
util
;
import
javax.servlet.http.HttpServletRequest
;
import
java.net.InetAddress
;
import
java.net.UnknownHostException
;
import
java.util.Calendar
;
import
java.util.Date
;
/**
* @author Zheng Jie
* 字符串工具类, 继承org.apache.commons.lang3.StringUtils类
*/
public
class
StringUtils
extends
org
.
apache
.
commons
.
lang3
.
StringUtils
{
private
static
final
char
SEPARATOR
=
'_'
;
private
static
final
String
UNKNOWN
=
"unknown"
;
/**
* 驼峰命名法工具
*
* @return toCamelCase(" hello_world ") == "helloWorld"
* toCapitalizeCamelCase("hello_world") == "HelloWorld"
* toUnderScoreCase("helloWorld") = "hello_world"
*/
public
static
String
toCamelCase
(
String
s
)
{
if
(
s
==
null
)
{
return
null
;
}
s
=
s
.
toLowerCase
();
StringBuilder
sb
=
new
StringBuilder
(
s
.
length
());
boolean
upperCase
=
false
;
for
(
int
i
=
0
;
i
<
s
.
length
();
i
++)
{
char
c
=
s
.
charAt
(
i
);
if
(
c
==
SEPARATOR
)
{
upperCase
=
true
;
}
else
if
(
upperCase
)
{
sb
.
append
(
Character
.
toUpperCase
(
c
));
upperCase
=
false
;
}
else
{
sb
.
append
(
c
);
}
}
return
sb
.
toString
();
}
/**
* 驼峰命名法工具
*
* @return toCamelCase(" hello_world ") == "helloWorld"
* toCapitalizeCamelCase("hello_world") == "HelloWorld"
* toUnderScoreCase("helloWorld") = "hello_world"
*/
public
static
String
toCapitalizeCamelCase
(
String
s
)
{
if
(
s
==
null
)
{
return
null
;
}
s
=
toCamelCase
(
s
);
return
s
.
substring
(
0
,
1
).
toUpperCase
()
+
s
.
substring
(
1
);
}
/**
* 驼峰命名法工具
*
* @return toCamelCase(" hello_world ") == "helloWorld"
* toCapitalizeCamelCase("hello_world") == "HelloWorld"
* toUnderScoreCase("helloWorld") = "hello_world"
*/
static
String
toUnderScoreCase
(
String
s
)
{
if
(
s
==
null
)
{
return
null
;
}
StringBuilder
sb
=
new
StringBuilder
();
boolean
upperCase
=
false
;
for
(
int
i
=
0
;
i
<
s
.
length
();
i
++)
{
char
c
=
s
.
charAt
(
i
);
boolean
nextUpperCase
=
true
;
if
(
i
<
(
s
.
length
()
-
1
))
{
nextUpperCase
=
Character
.
isUpperCase
(
s
.
charAt
(
i
+
1
));
}
if
((
i
>
0
)
&&
Character
.
isUpperCase
(
c
))
{
if
(!
upperCase
||
!
nextUpperCase
)
{
sb
.
append
(
SEPARATOR
);
}
upperCase
=
true
;
}
else
{
upperCase
=
false
;
}
sb
.
append
(
Character
.
toLowerCase
(
c
));
}
return
sb
.
toString
();
}
/**
* 获取ip地址
*/
public
static
String
getIp
(
HttpServletRequest
request
)
{
String
ip
=
request
.
getHeader
(
"x-forwarded-for"
);
if
(
ip
==
null
||
ip
.
length
()
==
0
||
UNKNOWN
.
equalsIgnoreCase
(
ip
))
{
ip
=
request
.
getHeader
(
"Proxy-Client-IP"
);
}
if
(
ip
==
null
||
ip
.
length
()
==
0
||
UNKNOWN
.
equalsIgnoreCase
(
ip
))
{
ip
=
request
.
getHeader
(
"WL-Proxy-Client-IP"
);
}
if
(
ip
==
null
||
ip
.
length
()
==
0
||
UNKNOWN
.
equalsIgnoreCase
(
ip
))
{
ip
=
request
.
getRemoteAddr
();
}
String
comma
=
","
;
String
localhost
=
"127.0.0.1"
;
if
(
ip
.
contains
(
comma
))
{
ip
=
ip
.
split
(
","
)[
0
];
}
if
(
localhost
.
equals
(
ip
))
{
// 获取本机真正的ip地址
try
{
ip
=
InetAddress
.
getLocalHost
().
getHostAddress
();
}
catch
(
UnknownHostException
e
)
{
e
.
printStackTrace
();
}
}
return
ip
;
}
/**
* 获得当天是周几
*/
public
static
String
getWeekDay
(){
String
[]
weekDays
=
{
"Sun"
,
"Mon"
,
"Tue"
,
"Wed"
,
"Thu"
,
"Fri"
,
"Sat"
};
Calendar
cal
=
Calendar
.
getInstance
();
cal
.
setTime
(
new
Date
());
int
w
=
cal
.
get
(
Calendar
.
DAY_OF_WEEK
)
-
1
;
if
(
w
<
0
){
w
=
0
;
}
return
weekDays
[
w
];
}
}
pom.xml
View file @
2c8ec2b
...
...
@@ -72,9 +72,36 @@
<ooxml-security.version>
1.1
</ooxml-security.version>
<ooxml-schemas.version>
1.4
</ooxml-schemas.version>
<xmlbean.version>
3.1.0
</xmlbean.version>
<java-jwt.version>
3.2.0
</java-jwt.version>
<jjwt.version>
0.7.0
</jjwt.version>
<javax.servlet-api.version>
3.1.0
</javax.servlet-api.version>
<jsoup.version>
1.16.1
</jsoup.version>
</properties>
<dependencyManagement>
<dependencies>
<!--jwt-->
<dependency>
<groupId>
com.auth0
</groupId>
<artifactId>
java-jwt
</artifactId>
<version>
${java-jwt.version}
</version>
</dependency>
<dependency>
<groupId>
io.jsonwebtoken
</groupId>
<artifactId>
jjwt
</artifactId>
<version>
${jjwt.version}
</version>
</dependency>
<dependency>
<groupId>
javax.servlet
</groupId>
<artifactId>
javax.servlet-api
</artifactId>
<version>
${javax.servlet-api.version}
</version>
</dependency>
<dependency>
<groupId>
org.jsoup
</groupId>
<artifactId>
jsoup
</artifactId>
<version>
${jsoup.version}
</version>
</dependency>
<!-- 文字识别 -->
<dependency>
<groupId>
io.github.mymonstercat
</groupId>
...
...
@@ -428,10 +455,6 @@
<artifactId>
jedis
</artifactId>
<version>
${jedis.version}
</version>
</dependency>
<dependency>
<groupId>
org.apache.commons
</groupId>
<artifactId>
commons-lang3
</artifactId>
</dependency>
<!--监控sql日志-->
<dependency>
<groupId>
org.bgee.log4jdbc-log4j2
</groupId>
...
...
@@ -455,12 +478,6 @@
<artifactId>
xmlbeans
</artifactId>
<version>
${xmlbean.version}
</version>
</dependency>
<!-- fastjson -->
<dependency>
<groupId>
com.alibaba
</groupId>
<artifactId>
fastjson
</artifactId>
<version>
${fastjson.version}
</version>
</dependency>
</dependencies>
</dependencyManagement>
...
...
@@ -490,6 +507,10 @@
<groupId>
org.springframework.boot
</groupId>
<artifactId>
spring-boot-starter-validation
</artifactId>
</dependency>
<dependency>
<groupId>
org.apache.commons
</groupId>
<artifactId>
commons-lang3
</artifactId>
</dependency>
<!--lombok插件-->
<dependency>
<groupId>
org.projectlombok
</groupId>
...
...
@@ -509,6 +530,13 @@
</exclusion>
</exclusions>
</dependency>
<!-- fastjson -->
<dependency>
<groupId>
com.alibaba
</groupId>
<artifactId>
fastjson
</artifactId>
<version>
${fastjson.version}
</version>
</dependency>
</dependencies>
<build>
<pluginManagement>
...
...
Write
Preview
Markdown
is supported
Attach a file
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 post a comment