Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
W
wecloud_im_server
Overview
Overview
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
hewei
wecloud_im_server
Commits
651bb9ab
Commit
651bb9ab
authored
Apr 18, 2022
by
罗长华
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
JwtFilter -> SecurityFilter 整合
parent
a6aca6bb
Hide whitespace changes
Inline
Side-by-side
Showing
5 changed files
with
101 additions
and
145 deletions
+101
-145
bootstrap/src/main/java/io/geekidea/springbootplus/config/ShiroConfig.java
+2
-7
framework/src/main/java/io/geekidea/springbootplus/framework/shiro/jwt/SecurityFilter.java
+94
-23
framework/src/main/java/io/geekidea/springbootplus/framework/shiro/signature/SignatureAuthFilter.java
+0
-115
im-sdk/src/main/java/com/wecloud/im/sdk/internal/ImHeaders.java
+2
-0
im-sdk/src/main/java/com/wecloud/im/sdk/internal/WecloudImOperation.java
+3
-0
No files found.
bootstrap/src/main/java/io/geekidea/springbootplus/config/ShiroConfig.java
View file @
651bb9ab
...
@@ -22,11 +22,10 @@ import io.geekidea.springbootplus.config.properties.ShiroProperties;
...
@@ -22,11 +22,10 @@ import io.geekidea.springbootplus.config.properties.ShiroProperties;
import
io.geekidea.springbootplus.framework.shiro.cache.AppLoginRedisService
;
import
io.geekidea.springbootplus.framework.shiro.cache.AppLoginRedisService
;
import
io.geekidea.springbootplus.framework.shiro.exception.ShiroConfigException
;
import
io.geekidea.springbootplus.framework.shiro.exception.ShiroConfigException
;
import
io.geekidea.springbootplus.framework.shiro.jwt.JwtCredentialsMatcher
;
import
io.geekidea.springbootplus.framework.shiro.jwt.JwtCredentialsMatcher
;
import
io.geekidea.springbootplus.framework.shiro.jwt.
Jwt
Filter
;
import
io.geekidea.springbootplus.framework.shiro.jwt.
Security
Filter
;
import
io.geekidea.springbootplus.framework.shiro.jwt.realm.JwtRealmAppUser
;
import
io.geekidea.springbootplus.framework.shiro.jwt.realm.JwtRealmAppUser
;
import
io.geekidea.springbootplus.framework.shiro.service.ShiroLoginService
;
import
io.geekidea.springbootplus.framework.shiro.service.ShiroLoginService
;
import
io.geekidea.springbootplus.framework.shiro.signature.ApplicationService
;
import
io.geekidea.springbootplus.framework.shiro.signature.ApplicationService
;
import
io.geekidea.springbootplus.framework.shiro.signature.SignatureAuthFilter
;
import
io.geekidea.springbootplus.framework.shiro.signature.SignatureAuthRealm
;
import
io.geekidea.springbootplus.framework.shiro.signature.SignatureAuthRealm
;
import
io.geekidea.springbootplus.framework.util.IniUtil
;
import
io.geekidea.springbootplus.framework.util.IniUtil
;
import
lombok.extern.slf4j.Slf4j
;
import
lombok.extern.slf4j.Slf4j
;
...
@@ -214,8 +213,7 @@ public class ShiroConfig {
...
@@ -214,8 +213,7 @@ public class ShiroConfig {
*/
*/
private
Map
<
String
,
Filter
>
getFilterMap
(
ShiroLoginService
shiroLoginService
,
ApplicationService
applicationService
)
{
private
Map
<
String
,
Filter
>
getFilterMap
(
ShiroLoginService
shiroLoginService
,
ApplicationService
applicationService
)
{
Map
<
String
,
Filter
>
filterMap
=
new
LinkedHashMap
<>();
Map
<
String
,
Filter
>
filterMap
=
new
LinkedHashMap
<>();
filterMap
.
put
(
JWT_FILTER_NAME
,
new
JwtFilter
(
shiroLoginService
));
filterMap
.
put
(
JWT_FILTER_NAME
,
new
SecurityFilter
(
shiroLoginService
,
applicationService
));
filterMap
.
put
(
"signatureAuthFilter"
,
new
SignatureAuthFilter
(
applicationService
));
return
filterMap
;
return
filterMap
;
}
}
...
@@ -278,9 +276,6 @@ public class ShiroConfig {
...
@@ -278,9 +276,6 @@ public class ShiroConfig {
// 如果启用shiro,则设置最后一个设置为JWTFilter,否则全部路径放行
// 如果启用shiro,则设置最后一个设置为JWTFilter,否则全部路径放行
if
(
shiroProperties
.
isEnable
())
{
if
(
shiroProperties
.
isEnable
())
{
filterChainDefinitionMap
.
put
(
"/imClient/registerClient"
,
"signatureAuthFilter"
);
filterChainDefinitionMap
.
put
(
"/token/getToken"
,
"signatureAuthFilter"
);
filterChainDefinitionMap
.
put
(
"/user/modifyUser"
,
"signatureAuthFilter"
);
filterChainDefinitionMap
.
put
(
"/**"
,
JWT_FILTER_NAME
);
filterChainDefinitionMap
.
put
(
"/**"
,
JWT_FILTER_NAME
);
}
else
{
}
else
{
filterChainDefinitionMap
.
put
(
"/**"
,
ANON
);
filterChainDefinitionMap
.
put
(
"/**"
,
ANON
);
...
...
framework/src/main/java/io/geekidea/springbootplus/framework/shiro/jwt/
Jwt
Filter.java
→
framework/src/main/java/io/geekidea/springbootplus/framework/shiro/jwt/
Security
Filter.java
View file @
651bb9ab
...
@@ -19,22 +19,28 @@ package io.geekidea.springbootplus.framework.shiro.jwt;
...
@@ -19,22 +19,28 @@ package io.geekidea.springbootplus.framework.shiro.jwt;
import
io.geekidea.springbootplus.framework.common.api.ApiCode
;
import
io.geekidea.springbootplus.framework.common.api.ApiCode
;
import
io.geekidea.springbootplus.framework.common.api.ApiResult
;
import
io.geekidea.springbootplus.framework.common.api.ApiResult
;
import
io.geekidea.springbootplus.framework.shiro.service.ShiroLoginService
;
import
io.geekidea.springbootplus.framework.shiro.service.ShiroLoginService
;
import
io.geekidea.springbootplus.framework.shiro.signature.Application
;
import
io.geekidea.springbootplus.framework.shiro.signature.ApplicationService
;
import
io.geekidea.springbootplus.framework.shiro.signature.SignatureAuthToken
;
import
io.geekidea.springbootplus.framework.shiro.signature.SignatureChecker
;
import
io.geekidea.springbootplus.framework.shiro.util.JwtTokenUtil
;
import
io.geekidea.springbootplus.framework.shiro.util.JwtTokenUtil
;
import
io.geekidea.springbootplus.framework.shiro.util.JwtUtil
;
import
io.geekidea.springbootplus.framework.shiro.util.JwtUtil
;
import
io.geekidea.springbootplus.framework.util.HttpServletResponseUtil
;
import
io.geekidea.springbootplus.framework.util.HttpServletResponseUtil
;
import
lombok.extern.slf4j.Slf4j
;
import
lombok.extern.slf4j.Slf4j
;
import
javax.servlet.ServletRequest
;
import
javax.servlet.ServletResponse
;
import
javax.servlet.http.HttpServletRequest
;
import
javax.servlet.http.HttpServletResponse
;
import
org.apache.commons.lang3.StringUtils
;
import
org.apache.commons.lang3.StringUtils
;
import
org.apache.shiro.authc.AuthenticationException
;
import
org.apache.shiro.authc.AuthenticationException
;
import
org.apache.shiro.authc.AuthenticationToken
;
import
org.apache.shiro.authc.AuthenticationToken
;
import
org.apache.shiro.subject.Subject
;
import
org.apache.shiro.subject.Subject
;
import
org.apache.shiro.web.filter.authc.AuthenticatingFilter
;
import
org.apache.shiro.web.filter.authc.AuthenticatingFilter
;
import
org.apache.shiro.web.servlet.ShiroHttpServletRequest
;
import
org.apache.shiro.web.util.WebUtils
;
import
org.apache.shiro.web.util.WebUtils
;
import
javax.servlet.ServletRequest
;
import
javax.servlet.ServletResponse
;
import
javax.servlet.http.HttpServletRequest
;
import
javax.servlet.http.HttpServletResponse
;
/**
/**
* Shiro JWT授权过滤器
* Shiro JWT授权过滤器
*
*
...
@@ -43,12 +49,17 @@ import javax.servlet.http.HttpServletResponse;
...
@@ -43,12 +49,17 @@ import javax.servlet.http.HttpServletResponse;
* @since 1.3.0.RELEASE
* @since 1.3.0.RELEASE
**/
**/
@Slf4j
@Slf4j
public
class
Jwt
Filter
extends
AuthenticatingFilter
{
public
class
Security
Filter
extends
AuthenticatingFilter
{
private
final
ShiroLoginService
shiroLoginService
;
private
final
ShiroLoginService
shiroLoginService
;
public
JwtFilter
(
ShiroLoginService
shiroLoginService
)
{
private
static
final
String
AUTHORIZATION
=
"Authorization"
;
private
ApplicationService
applicationService
;
public
SecurityFilter
(
ShiroLoginService
shiroLoginService
,
ApplicationService
applicationService
)
{
this
.
shiroLoginService
=
shiroLoginService
;
this
.
shiroLoginService
=
shiroLoginService
;
this
.
applicationService
=
applicationService
;
}
}
/**
/**
...
@@ -62,21 +73,65 @@ public class JwtFilter extends AuthenticatingFilter {
...
@@ -62,21 +73,65 @@ public class JwtFilter extends AuthenticatingFilter {
*/
*/
@Override
@Override
protected
AuthenticationToken
createToken
(
ServletRequest
servletRequest
,
ServletResponse
servletResponse
)
{
protected
AuthenticationToken
createToken
(
ServletRequest
servletRequest
,
ServletResponse
servletResponse
)
{
// 从http请求头中取得token
String
token
=
JwtTokenUtil
.
getToken
();
if
(
StringUtils
.
isBlank
(
token
))
{
throw
new
AuthenticationException
(
"token不能为空"
);
}
if
(
JwtUtil
.
isExpired
(
token
))
{
throw
new
AuthenticationException
(
"JWT Token已过期,token:"
+
token
);
}
// 从redis 获取jwt数据
// 从请求头中取出x-im-from
JwtToken
jwtToken
=
shiroLoginService
.
getJwtTokenForRedis
(
token
);
ShiroHttpServletRequest
ShiroHttpServletRequest
=
(
ShiroHttpServletRequest
)
servletRequest
;
if
(
jwtToken
==
null
)
{
throw
new
AuthenticationException
(
"Redis Token不存在,token:"
+
token
);
HttpServletRequest
request
=
(
HttpServletRequest
)
ShiroHttpServletRequest
.
getRequest
();
String
from
=
request
.
getHeader
(
"x-im-from"
);
if
(
"server"
.
equals
(
from
))
{
// 服务端发起的请求,校验签名
String
authorization
=
request
.
getHeader
(
AUTHORIZATION
);
if
(
StringUtils
.
isBlank
(
authorization
))
{
throw
new
AuthenticationException
(
"token不能为空"
);
}
// 校验Signature是否完整 合规
if
(!
authorization
.
startsWith
(
"WECLOUD-IM AppKey"
))
{
throw
new
AuthenticationException
(
"token错误"
);
}
if
(!
authorization
.
contains
(
", Signature:"
))
{
throw
new
AuthenticationException
(
"token 未包含签名信息"
);
}
String
appKey
=
getAppKeyFromAuthorization
(
authorization
);
String
clientSignature
=
getSignatureFromAuthorization
(
authorization
);
// 校验通过 获取并校验Application信息
Application
application
=
applicationService
.
getApplication
(
appKey
);
if
(
application
==
null
)
{
throw
new
AuthenticationException
(
"application does not exist"
);
}
if
(!
application
.
isActive
())
{
throw
new
AuthenticationException
(
"application is unavailable"
);
}
Long
appId
=
application
.
getId
();
String
appSecret
=
application
.
getAppSecret
();
SignatureChecker
.
check
(
request
,
clientSignature
,
appSecret
);
// 构建SignatureAuthToken
return
new
SignatureAuthToken
(
appKey
,
appId
);
}
else
{
// 客户端发起的请求,校验token
// 从http请求头中取得token
String
token
=
JwtTokenUtil
.
getToken
();
if
(
StringUtils
.
isBlank
(
token
))
{
throw
new
AuthenticationException
(
"token不能为空"
);
}
if
(
JwtUtil
.
isExpired
(
token
))
{
throw
new
AuthenticationException
(
"JWT Token已过期,token:"
+
token
);
}
// 从redis 获取jwt数据
JwtToken
jwtToken
=
shiroLoginService
.
getJwtTokenForRedis
(
token
);
if
(
jwtToken
==
null
)
{
throw
new
AuthenticationException
(
"Redis Token不存在,token:"
+
token
);
}
return
JwtToken
.
build
(
token
,
jwtToken
.
getSalt
(),
jwtToken
.
getExpireSecond
(),
jwtToken
.
getClientId
(),
jwtToken
.
getAppKey
(),
jwtToken
.
getPlatform
());
}
}
return
JwtToken
.
build
(
token
,
jwtToken
.
getSalt
(),
jwtToken
.
getExpireSecond
(),
jwtToken
.
getClientId
(),
jwtToken
.
getAppKey
(),
jwtToken
.
getPlatform
());
}
}
...
@@ -144,9 +199,11 @@ public class JwtFilter extends AuthenticatingFilter {
...
@@ -144,9 +199,11 @@ public class JwtFilter extends AuthenticatingFilter {
protected
boolean
onLoginSuccess
(
AuthenticationToken
token
,
Subject
subject
,
ServletRequest
request
,
ServletResponse
response
)
throws
Exception
{
protected
boolean
onLoginSuccess
(
AuthenticationToken
token
,
Subject
subject
,
ServletRequest
request
,
ServletResponse
response
)
throws
Exception
{
String
url
=
WebUtils
.
toHttp
(
request
).
getRequestURI
();
String
url
=
WebUtils
.
toHttp
(
request
).
getRequestURI
();
log
.
info
(
"鉴权成功,token:{},url:{}"
,
token
,
url
);
log
.
info
(
"鉴权成功,token:{},url:{}"
,
token
,
url
);
// 刷新token
if
(
token
instanceof
JwtToken
)
{
JwtToken
jwtToken
=
(
JwtToken
)
token
;
// 刷新token
HttpServletResponse
httpServletResponse
=
WebUtils
.
toHttp
(
response
);
JwtToken
jwtToken
=
(
JwtToken
)
token
;
HttpServletResponse
httpServletResponse
=
WebUtils
.
toHttp
(
response
);
}
// shiroLoginService.refreshToken(jwtToken, httpServletResponse);
// shiroLoginService.refreshToken(jwtToken, httpServletResponse);
return
true
;
return
true
;
}
}
...
@@ -165,4 +222,18 @@ public class JwtFilter extends AuthenticatingFilter {
...
@@ -165,4 +222,18 @@ public class JwtFilter extends AuthenticatingFilter {
log
.
error
(
"登录失败,token:"
+
token
+
",error:"
+
e
.
getMessage
(),
e
);
log
.
error
(
"登录失败,token:"
+
token
+
",error:"
+
e
.
getMessage
(),
e
);
return
false
;
return
false
;
}
}
private
String
getAppKeyFromAuthorization
(
String
authorization
)
{
// 处理token
String
[]
tokenInfo
=
authorization
.
split
(
","
);
// appkey 格式是固定的,直接替换
return
tokenInfo
[
0
].
replace
(
"WECLOUD-IM AppKey:"
,
""
).
trim
();
}
private
String
getSignatureFromAuthorization
(
String
authorization
)
{
// 处理token
String
[]
tokenInfo
=
authorization
.
split
(
","
);
// 客户端传入的签名信息
return
tokenInfo
[
1
].
replace
(
"Signature:"
,
""
).
trim
();
}
}
}
framework/src/main/java/io/geekidea/springbootplus/framework/shiro/signature/SignatureAuthFilter.java
deleted
100644 → 0
View file @
a6aca6bb
package
io
.
geekidea
.
springbootplus
.
framework
.
shiro
.
signature
;
import
lombok.extern.slf4j.Slf4j
;
import
javax.servlet.ServletRequest
;
import
javax.servlet.ServletResponse
;
import
javax.servlet.http.HttpServletRequest
;
import
javax.validation.constraints.NotNull
;
import
org.apache.commons.lang3.StringUtils
;
import
org.apache.shiro.authc.AuthenticationException
;
import
org.apache.shiro.authc.AuthenticationToken
;
import
org.apache.shiro.web.filter.authc.AuthenticatingFilter
;
import
org.apache.shiro.web.servlet.ShiroHttpServletRequest
;
import
org.apache.shiro.web.util.WebUtils
;
/**
* shiro 用户签名认证
* @Author luozh
* @Date 2022年04月14日 16:43
* @Version 1.0
*/
@Slf4j
public
class
SignatureAuthFilter
extends
AuthenticatingFilter
{
private
static
final
String
AUTHORIZATION
=
"Authorization"
;
private
ApplicationService
applicationService
;
public
SignatureAuthFilter
(
@NotNull
ApplicationService
applicationService
)
{
if
(
applicationService
==
null
)
{
throw
new
IllegalArgumentException
(
"application service must not be null"
);
}
this
.
applicationService
=
applicationService
;
}
@Override
protected
AuthenticationToken
createToken
(
ServletRequest
servletRequest
,
ServletResponse
servletResponse
)
throws
Exception
{
ShiroHttpServletRequest
ShiroHttpServletRequest
=
(
ShiroHttpServletRequest
)
servletRequest
;
HttpServletRequest
request
=
(
HttpServletRequest
)
ShiroHttpServletRequest
.
getRequest
();
String
authorization
=
request
.
getHeader
(
AUTHORIZATION
);
if
(
StringUtils
.
isBlank
(
authorization
))
{
throw
new
AuthenticationException
(
"token不能为空"
);
}
// 校验Signature是否完整 合规
if
(!
authorization
.
startsWith
(
"WECLOUD-IM AppKey"
))
{
throw
new
AuthenticationException
(
"token错误"
);
}
if
(!
authorization
.
contains
(
", Signature:"
))
{
throw
new
AuthenticationException
(
"token 未包含签名信息"
);
}
String
appKey
=
getAppKeyFromAuthorization
(
authorization
);
String
clientSignature
=
getSignatureFromAuthorization
(
authorization
);
// 校验通过 获取并校验Application信息
Application
application
=
applicationService
.
getApplication
(
appKey
);
if
(
application
==
null
)
{
throw
new
AuthenticationException
(
"application does not exist"
);
}
if
(!
application
.
isActive
())
{
throw
new
AuthenticationException
(
"application is unavailable"
);
}
Long
appId
=
application
.
getId
();
String
appSecret
=
application
.
getAppSecret
();
SignatureChecker
.
check
(
request
,
clientSignature
,
appSecret
);
// 构建SignatureAuthToken
return
new
SignatureAuthToken
(
appKey
,
appId
);
}
@Override
protected
boolean
isAccessAllowed
(
ServletRequest
request
,
ServletResponse
response
,
Object
mappedValue
)
{
String
url
=
WebUtils
.
toHttp
(
request
).
getRequestURI
();
log
.
info
(
"isAccessAllowed url:{}"
,
url
);
if
(
this
.
isLoginRequest
(
request
,
response
))
{
return
true
;
}
boolean
allowed
=
false
;
try
{
allowed
=
executeLogin
(
request
,
response
);
}
catch
(
IllegalStateException
e
)
{
//not found any token
log
.
error
(
"Token不能为空"
,
e
);
}
catch
(
Exception
e
)
{
log
.
error
(
"访问错误"
,
e
);
}
return
true
;
}
@Override
protected
boolean
onAccessDenied
(
ServletRequest
servletRequest
,
ServletResponse
servletResponse
)
throws
Exception
{
return
false
;
}
private
String
getAppKeyFromAuthorization
(
String
authorization
)
{
// 处理token
String
[]
tokenInfo
=
authorization
.
split
(
","
);
// appkey 格式是固定的,直接替换
return
tokenInfo
[
0
].
replace
(
"WECLOUD-IM AppKey:"
,
""
).
trim
();
}
private
String
getSignatureFromAuthorization
(
String
authorization
)
{
// 处理token
String
[]
tokenInfo
=
authorization
.
split
(
","
);
// 客户端传入的签名信息
return
tokenInfo
[
1
].
replace
(
"Signature:"
,
""
).
trim
();
}
}
im-sdk/src/main/java/com/wecloud/im/sdk/internal/ImHeaders.java
View file @
651bb9ab
...
@@ -12,5 +12,7 @@ public interface ImHeaders extends HttpHeaders {
...
@@ -12,5 +12,7 @@ public interface ImHeaders extends HttpHeaders {
static
final
String
WECLOUD_SIGN
=
"x-wecloud-sign"
;
static
final
String
WECLOUD_SIGN
=
"x-wecloud-sign"
;
static
final
String
X_IM_FROM
=
"x-im-from"
;
static
final
String
IM_PREFIX
=
"x-im-"
;
static
final
String
IM_PREFIX
=
"x-im-"
;
}
}
im-sdk/src/main/java/com/wecloud/im/sdk/internal/WecloudImOperation.java
View file @
651bb9ab
...
@@ -14,6 +14,7 @@ import com.wecloud.im.sdk.common.RequestMessage;
...
@@ -14,6 +14,7 @@ import com.wecloud.im.sdk.common.RequestMessage;
import
com.wecloud.im.sdk.common.auth.Credentials
;
import
com.wecloud.im.sdk.common.auth.Credentials
;
import
com.wecloud.im.sdk.exception.WecloudException
;
import
com.wecloud.im.sdk.exception.WecloudException
;
import
static
com
.
wecloud
.
im
.
sdk
.
internal
.
ImHeaders
.
X_IM_FROM
;
import
static
com
.
wecloud
.
im
.
sdk
.
utils
.
HttpHeaders
.
CONTENT_TYPE
;
import
static
com
.
wecloud
.
im
.
sdk
.
utils
.
HttpHeaders
.
CONTENT_TYPE
;
/**
/**
...
@@ -44,6 +45,8 @@ public abstract class WecloudImOperation {
...
@@ -44,6 +45,8 @@ public abstract class WecloudImOperation {
if
(
HttpMethod
.
POST
.
equals
(
request
.
getMethod
()))
{
if
(
HttpMethod
.
POST
.
equals
(
request
.
getMethod
()))
{
request
.
addHeader
(
CONTENT_TYPE
,
"application/json; charset=utf-8"
);
request
.
addHeader
(
CONTENT_TYPE
,
"application/json; charset=utf-8"
);
}
}
// 添加来源请求头
request
.
addHeader
(
X_IM_FROM
,
"server"
);
// 添加签名请求头
// 添加签名请求头
RequestSigner
signer
=
new
RequestSigner
(
request
.
getMethod
().
name
(),
request
.
getEndpoint
(),
credentials
);
RequestSigner
signer
=
new
RequestSigner
(
request
.
getMethod
().
name
(),
request
.
getEndpoint
(),
credentials
);
signer
.
sign
(
request
);
signer
.
sign
(
request
);
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment