Skip to content
Toggle navigation
Projects
Groups
Snippets
Help
yangxiujun
/
paidan_demo
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 a3a53293
authored
Oct 11, 2023
by
刘鑫
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
CI: 添加外部接口AK校验, 并且不在校验白名单内的接口不再放行
1 parent
7c3debd7
Hide whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
223 additions
and
118 deletions
project-gateway/src/main/java/com/dituhui/pea/gateway/config/AuthFilter.java
project-gateway/src/main/java/com/dituhui/pea/gateway/utils/SignUtil.java
project-gateway/src/main/java/com/dituhui/pea/gateway/config/AuthFilter.java
View file @
a3a5329
package
com
.
dituhui
.
pea
.
gateway
.
config
;
import
java.util.Set
;
import
com.alibaba.fastjson.JSON
;
import
com.dituhui.pea.common.Result
;
import
com.dituhui.pea.constants.Globals
;
import
com.dituhui.pea.enums.RedisKeyGroup
;
import
com.dituhui.pea.gateway.commom.RedisService
;
import
com.dituhui.pea.pojo.UserLoginDTO
;
import
com.google.common.collect.Maps
;
import
com.google.common.collect.Sets
;
import
com.google.gson.Gson
;
import
lombok.extern.slf4j.Slf4j
;
import
org.apache.commons.lang3.StringUtils
;
import
org.springframework.beans.factory.annotation.Autowired
;
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.HttpHeaders
;
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.util.MultiValueMap
;
import
org.springframework.web.server.ServerWebExchange
;
import
com.dituhui.pea.constants.Globals
;
import
com.dituhui.pea.enums.RedisKeyGroup
;
import
com.dituhui.pea.gateway.commom.RedisService
;
import
com.dituhui.pea.pojo.UserLoginDTO
;
import
com.google.common.collect.Sets
;
import
com.google.gson.Gson
;
import
lombok.extern.slf4j.Slf4j
;
import
reactor.core.publisher.Mono
;
import
java.nio.charset.StandardCharsets
;
import
java.util.Map
;
import
java.util.Set
;
@Component
@Slf4j
public
class
AuthFilter
implements
GlobalFilter
,
Ordered
{
/**
* 白名单
*/
private
static
final
Set
<
String
>
authWhiteList
=
Sets
.
newHashSet
(
"/pea-user/login"
,
"/pea-user/login/"
,
"/pea-user/refreshAppkey"
,
"/pea-user/refreshAppkey/"
);
private
static
final
Gson
gson
=
new
Gson
();
@Autowired
RedisService
redisService
;
@Override
public
Mono
<
Void
>
filter
(
ServerWebExchange
exchange
,
GatewayFilterChain
chain
)
{
String
url
=
exchange
.
getRequest
().
getPath
().
toString
();
// 判断是否属于白名单中
if
(
authWhiteList
.
contains
(
url
))
{
log
.
info
(
"whiteList:{} ip:{}"
,
url
,
getRemoteIP
(
exchange
));
return
chain
.
filter
(
exchange
);
}
// 下面的代码从Http Header的Authorization中获取token,也可以从其他header,cookie等中获取,看客户端怎么传递token
HttpHeaders
headers
=
exchange
.
getRequest
().
getHeaders
();
String
authHeader
=
headers
.
getFirst
(
HttpHeaders
.
AUTHORIZATION
);
// W3C的HTTP1.0规范: Authorization : <type> <authorization-parameters>
// Basic用于http-basic 认证;
// Bearer 常见于OAuth和JWT授权;
// AwS4-HMAC - SHA256 AwS授权
String
authToken
=
null
;
if
(
authHeader
!=
null
&&
authHeader
.
startsWith
(
"Bearer "
))
{
authToken
=
authHeader
.
substring
(
7
);
}
if
(
StringUtils
.
isEmpty
(
authToken
))
{
authToken
=
exchange
.
getRequest
().
getQueryParams
().
getFirst
(
"token"
);
}
UserLoginDTO
userDTO
=
null
;
if
(
StringUtils
.
isNotEmpty
(
authToken
))
{
if
(
log
.
isTraceEnabled
())
{
log
.
trace
(
"token is {}"
,
authToken
);
}
// 查询token对应的用户
String
value
=
redisService
.
get
(
RedisKeyGroup
.
authToken
+
":"
+
authToken
);
if
(
null
!=
value
)
{
userDTO
=
gson
.
fromJson
(
value
,
UserLoginDTO
.
class
);
}
}
// ak登录处理
if
(
StringUtils
.
isEmpty
(
authToken
))
{
String
ak
=
exchange
.
getRequest
().
getQueryParams
().
getFirst
(
"ak"
);
if
(
log
.
isTraceEnabled
())
{
log
.
trace
(
"ak is {}"
,
ak
);
}
if
(
StringUtils
.
isNotEmpty
(
ak
))
{
// 验证ak,设置userDTO
String
value
=
redisService
.
get
(
RedisKeyGroup
.
appKey
+
":"
+
ak
);
if
(
StringUtils
.
isNotEmpty
(
value
))
{
// 验证成功,设置为管理员
// AppDTO appDTO = gson.fromJson(value, AppDTO.class);
// String secret = appDTO.getSecret();
userDTO
=
new
UserLoginDTO
();
userDTO
.
setId
(
Globals
.
SUPER_ADMIN_ID
);
}
}
}
if
(
userDTO
==
null
)
{
log
.
info
(
"未授权访问{} ip:{}"
,
url
,
getRemoteIP
(
exchange
));
}
else
{
log
.
info
(
"用户:{} id:{} 访问{}"
,
userDTO
.
getAccount
(),
userDTO
.
getId
(),
url
);
// 获取当前的请求对象信息
ServerHttpRequest
.
Builder
builder
=
exchange
.
getRequest
().
mutate
();
// 向header中设置新的key,存储解析好的token对应基本信息
builder
.
header
(
"userId"
,
userDTO
.
getId
());
// 向下游传递
// Authentication authentication = new UsernamePasswordAuthenticationToken(userDTO.getAccount(), null, null);
// SecurityContextHolder.getContext().setAuthentication(authentication);
return
chain
.
filter
(
exchange
.
mutate
().
request
(
builder
.
build
()).
build
());
}
return
chain
.
filter
(
exchange
);
}
/**
* 客户端ip
*
* @param exchange
* @return
*/
private
String
getRemoteIP
(
ServerWebExchange
exchange
)
{
String
clientIp
=
""
;
if
(
StringUtils
.
isNotEmpty
(
exchange
.
getRequest
().
getHeaders
().
getFirst
(
"x-forwarded-for"
)))
{
clientIp
=
exchange
.
getRequest
().
getHeaders
().
getFirst
(
"x-forwarded-for"
);
}
else
if
(
StringUtils
.
isNotEmpty
(
exchange
.
getRequest
().
getHeaders
().
getFirst
(
"X-Forwarded-For"
)))
{
clientIp
=
exchange
.
getRequest
().
getHeaders
().
getFirst
(
"X-Forwarded-For"
);
}
else
if
(
StringUtils
.
isNotEmpty
(
exchange
.
getRequest
().
getRemoteAddress
().
getAddress
().
getHostAddress
()))
{
clientIp
=
exchange
.
getRequest
().
getRemoteAddress
().
getAddress
().
getHostAddress
();
}
if
(
"0:0:0:0:0:0:0:1"
.
equals
(
clientIp
))
{
clientIp
=
"127.0.0.1"
;
}
return
clientIp
;
}
@Override
public
int
getOrder
()
{
return
-
1
;
}
/**
* 白名单
*/
private
static
final
Set
<
String
>
authWhiteList
=
Sets
.
newHashSet
(
"/pea-user/login"
,
"/pea-user/login/"
,
"/pea-user/refreshAppkey"
,
"/pea-user/refreshAppkey/"
);
private
static
final
Gson
gson
=
new
Gson
();
@Autowired
RedisService
redisService
;
@Override
public
Mono
<
Void
>
filter
(
ServerWebExchange
exchange
,
GatewayFilterChain
chain
)
{
String
url
=
exchange
.
getRequest
().
getPath
().
toString
();
// 判断是否属于白名单中
if
(
authWhiteList
.
contains
(
url
))
{
log
.
info
(
"whiteList:{} ip:{}"
,
url
,
getRemoteIP
(
exchange
));
return
chain
.
filter
(
exchange
);
}
// 下面的代码从Http Header的Authorization中获取token,也可以从其他header,cookie等中获取,看客户端怎么传递token
HttpHeaders
headers
=
exchange
.
getRequest
().
getHeaders
();
String
authHeader
=
headers
.
getFirst
(
HttpHeaders
.
AUTHORIZATION
);
// W3C的HTTP1.0规范: Authorization : <type> <authorization-parameters>
// Basic用于http-basic 认证;
// Bearer 常见于OAuth和JWT授权;
// AwS4-HMAC - SHA256 AwS授权
String
authToken
=
null
;
if
(
authHeader
!=
null
&&
authHeader
.
startsWith
(
"Bearer "
))
{
authToken
=
authHeader
.
substring
(
7
);
}
if
(
StringUtils
.
isEmpty
(
authToken
))
{
authToken
=
exchange
.
getRequest
().
getQueryParams
().
getFirst
(
"token"
);
}
UserLoginDTO
userDTO
=
null
;
if
(
StringUtils
.
isNotEmpty
(
authToken
))
{
if
(
log
.
isTraceEnabled
())
{
log
.
trace
(
"token is {}"
,
authToken
);
}
// 查询token对应的用户
String
value
=
redisService
.
get
(
RedisKeyGroup
.
authToken
+
":"
+
authToken
);
if
(
null
!=
value
)
{
userDTO
=
gson
.
fromJson
(
value
,
UserLoginDTO
.
class
);
}
}
// ak登录处理
if
(
StringUtils
.
isEmpty
(
authToken
))
{
final
String
ak
=
getParams
(
exchange
,
"ak"
,
headers
);
if
(
log
.
isTraceEnabled
())
{
log
.
trace
(
"ak is {}"
,
ak
);
}
if
(
StringUtils
.
isNotEmpty
(
ak
))
{
// 验证ak,设置userDTO
String
value
=
redisService
.
get
(
RedisKeyGroup
.
appKey
+
":"
+
ak
);
if
(
StringUtils
.
isNotEmpty
(
value
))
{
// 验证成功,设置为管理员
// AppDTO appDTO = gson.fromJson(value, AppDTO.class);
// String secret = appDTO.getSecret();
//TODO 参数签名校验
final
String
sign
=
getParams
(
exchange
,
"sign"
,
headers
);
//计算签名
userDTO
=
new
UserLoginDTO
();
userDTO
.
setId
(
Globals
.
SUPER_ADMIN_ID
);
}
}
}
if
(
userDTO
==
null
)
{
log
.
info
(
"未授权访问{} ip:{}"
,
url
,
getRemoteIP
(
exchange
));
return
noPower
(
exchange
);
}
else
{
log
.
info
(
"用户:{} id:{} 访问{}"
,
userDTO
.
getAccount
(),
userDTO
.
getId
(),
url
);
// 获取当前的请求对象信息
ServerHttpRequest
.
Builder
builder
=
exchange
.
getRequest
().
mutate
();
// 向header中设置新的key,存储解析好的token对应基本信息
builder
.
header
(
"userId"
,
userDTO
.
getId
());
// 向下游传递
// Authentication authentication = new UsernamePasswordAuthenticationToken(userDTO.getAccount(), null, null);
// SecurityContextHolder.getContext().setAuthentication(authentication);
return
chain
.
filter
(
exchange
.
mutate
().
request
(
builder
.
build
()).
build
());
}
}
/**
* 解析所有参数
*
*/
private
Map
<
String
,
String
>
parseGetParams
(
ServerWebExchange
exchange
)
{
// params
Map
<
String
,
String
>
params
=
Maps
.
newHashMap
();
//请求路劲参数
Map
<
String
,
String
>
urlRequestParams
=
exchange
.
getRequest
().
getQueryParams
().
toSingleValueMap
();
return
params
;
}
private
String
getParams
(
ServerWebExchange
exchange
,
String
paramKey
,
HttpHeaders
headers
)
{
String
param
=
exchange
.
getRequest
().
getQueryParams
().
getFirst
(
paramKey
);
if
(
StringUtils
.
isBlank
(
param
))
{
param
=
headers
.
getFirst
(
paramKey
);
}
return
param
;
}
/**
* 网关拒绝,返回Result
*/
private
Mono
<
Void
>
noPower
(
ServerWebExchange
serverWebExchange
)
{
// 权限不够拦截
serverWebExchange
.
getResponse
().
setStatusCode
(
HttpStatus
.
UNAUTHORIZED
);
Result
<?>
data
=
Result
.
failed
();
DataBuffer
buffer
=
serverWebExchange
.
getResponse
().
bufferFactory
().
wrap
(
JSON
.
toJSONString
(
data
).
getBytes
(
StandardCharsets
.
UTF_8
));
ServerHttpResponse
response
=
serverWebExchange
.
getResponse
();
response
.
setStatusCode
(
HttpStatus
.
UNAUTHORIZED
);
//指定编码,否则在浏览器中会中文乱码
response
.
getHeaders
().
add
(
"Content-Type"
,
"application/json;charset=UTF-8"
);
return
response
.
writeWith
(
Mono
.
just
(
buffer
));
}
/**
* 客户端ip
*
* @param exchange
* @return
*/
private
String
getRemoteIP
(
ServerWebExchange
exchange
)
{
String
clientIp
=
""
;
if
(
StringUtils
.
isNotEmpty
(
exchange
.
getRequest
().
getHeaders
().
getFirst
(
"x-forwarded-for"
)))
{
clientIp
=
exchange
.
getRequest
().
getHeaders
().
getFirst
(
"x-forwarded-for"
);
}
else
if
(
StringUtils
.
isNotEmpty
(
exchange
.
getRequest
().
getHeaders
().
getFirst
(
"X-Forwarded-For"
)))
{
clientIp
=
exchange
.
getRequest
().
getHeaders
().
getFirst
(
"X-Forwarded-For"
);
}
else
if
(
StringUtils
.
isNotEmpty
(
exchange
.
getRequest
().
getRemoteAddress
().
getAddress
().
getHostAddress
()))
{
clientIp
=
exchange
.
getRequest
().
getRemoteAddress
().
getAddress
().
getHostAddress
();
}
if
(
"0:0:0:0:0:0:0:1"
.
equals
(
clientIp
))
{
clientIp
=
"127.0.0.1"
;
}
return
clientIp
;
}
@Override
public
int
getOrder
()
{
return
-
1
;
}
}
project-gateway/src/main/java/com/dituhui/pea/gateway/utils/SignUtil.java
0 → 100644
View file @
a3a5329
/*
* Begin license text.
* Copyright (c) 2020 — 2021 Liu Xin && Zhang Lei lsy_xin@163.com
* All rights reserved
* End license text.
*/
package
com
.
dituhui
.
pea
.
gateway
.
utils
;
import
org.apache.commons.codec.digest.DigestUtils
;
import
org.apache.commons.lang3.StringUtils
;
import
java.io.IOException
;
import
java.util.Arrays
;
import
java.util.Map
;
/**
* @author zl
*/
public
class
SignUtil
{
/**
* 对输入参数签名
*
* @param params 参数
* @param secret 密钥
* @return
* @throws IOException
*/
public
static
String
signRequest
(
Map
<
String
,
String
>
params
,
String
secret
)
{
try
{
// 第一步:参数排序
String
[]
keys
=
params
.
keySet
().
toArray
(
new
String
[
0
]);
Arrays
.
sort
(
keys
);
// 第二步:把所有参数名和参数值串在一起
StringBuilder
query
=
new
StringBuilder
();
for
(
String
key
:
keys
)
{
String
value
=
params
.
get
(
key
);
if
(
StringUtils
.
isNotEmpty
(
key
)
&&
!
StringUtils
.
equalsIgnoreCase
(
key
,
"sign"
)
&&
StringUtils
.
isNotEmpty
(
value
))
{
query
.
append
(
key
).
append
(
value
);
}
}
// 第三步:使用MD5/HMAC加密
return
DigestUtils
.
md5Hex
(
query
.
toString
()
+
secret
);
}
catch
(
Exception
e
)
{
e
.
printStackTrace
();
return
null
;
}
}
}
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