Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
Y
yd-communication
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
xingmin
yd-communication
Commits
30c7bd23
Commit
30c7bd23
authored
Aug 26, 2026
by
zhangxingmin
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
push
parent
22b90e6a
Show whitespace changes
Inline
Side-by-side
Showing
7 changed files
with
564 additions
and
0 deletions
+564
-0
yd-communication-api/src/main/java/com/yd/communication/api/controller/ApiCoSessionController.java
+25
-0
yd-communication-api/src/main/java/com/yd/communication/api/service/ApiCoSessionService.java
+6
-0
yd-communication-api/src/main/java/com/yd/communication/api/service/impl/ApiCoSessionServiceImpl.java
+88
-0
yd-communication-feign/src/main/java/com/yd/communication/feign/client/ApiCoSessionFeignClient.java
+25
-0
yd-communication-feign/src/main/java/com/yd/communication/feign/fallback/ApiCoSessionFeignFallbackFactory.java
+12
-0
yd-communication-service/src/main/java/com/yd/communication/service/utils/CffpTokenUtil.java
+207
-0
yd-communication-service/src/main/java/com/yd/communication/service/utils/SfpTokenUtil.java
+201
-0
No files found.
yd-communication-api/src/main/java/com/yd/communication/api/controller/ApiCoSessionController.java
View file @
30c7bd23
...
@@ -8,6 +8,7 @@ import com.yd.communication.feign.response.*;
...
@@ -8,6 +8,7 @@ import com.yd.communication.feign.response.*;
import
org.springframework.validation.annotation.Validated
;
import
org.springframework.validation.annotation.Validated
;
import
org.springframework.web.bind.annotation.*
;
import
org.springframework.web.bind.annotation.*
;
import
javax.annotation.Resource
;
import
javax.annotation.Resource
;
import
javax.servlet.http.HttpServletRequest
;
/**
/**
...
@@ -44,6 +45,30 @@ public class ApiCoSessionController implements ApiCoSessionFeignClient {
...
@@ -44,6 +45,30 @@ public class ApiCoSessionController implements ApiCoSessionFeignClient {
}
}
/**
/**
* 根据房间号和密码获取会话详情
*
* @param roomId 房间号
* @param roomPwd 房间密码
* @return 完整会话信息
*/
@Override
public
Result
<
SessionDetailResponse
>
get
(
String
roomId
,
String
roomPwd
)
{
return
apiCoSessionService
.
get
(
roomId
,
roomPwd
);
}
/**
* 判断资源创建者和参与者是否是同一个人(供参与者调用)
*
* @param roomId 房间号
* @param roomPwd 房间密码
* @return true-是同一人 false-不是同一人
*/
@Override
public
Result
<
Boolean
>
isMy
(
String
roomId
,
String
roomPwd
,
HttpServletRequest
httpRequest
)
{
return
apiCoSessionService
.
isMy
(
roomId
,
roomPwd
,
httpRequest
);
}
/**
* 获取会话状态
* 获取会话状态
* @param request
* @param request
* @return
* @return
...
...
yd-communication-api/src/main/java/com/yd/communication/api/service/ApiCoSessionService.java
View file @
30c7bd23
...
@@ -6,6 +6,8 @@ import com.yd.communication.feign.request.*;
...
@@ -6,6 +6,8 @@ import com.yd.communication.feign.request.*;
import
com.yd.communication.feign.response.*
;
import
com.yd.communication.feign.response.*
;
import
com.yd.communication.service.model.CoSession
;
import
com.yd.communication.service.model.CoSession
;
import
javax.servlet.http.HttpServletRequest
;
public
interface
ApiCoSessionService
{
public
interface
ApiCoSessionService
{
...
@@ -26,4 +28,8 @@ public interface ApiCoSessionService {
...
@@ -26,4 +28,8 @@ public interface ApiCoSessionService {
void
updateCurrentPage
(
String
roomId
,
String
newPageJson
,
String
operatorId
);
void
updateCurrentPage
(
String
roomId
,
String
newPageJson
,
String
operatorId
);
CoSession
getByRoomId
(
String
roomId
);
CoSession
getByRoomId
(
String
roomId
);
Result
<
SessionDetailResponse
>
get
(
String
roomId
,
String
roomPwd
);
Result
<
Boolean
>
isMy
(
String
roomId
,
String
roomPwd
,
HttpServletRequest
httpRequest
);
}
}
yd-communication-api/src/main/java/com/yd/communication/api/service/impl/ApiCoSessionServiceImpl.java
View file @
30c7bd23
...
@@ -25,7 +25,9 @@ import com.yd.communication.service.model.CoSession;
...
@@ -25,7 +25,9 @@ import com.yd.communication.service.model.CoSession;
import
com.yd.communication.service.service.ICoOperationLogService
;
import
com.yd.communication.service.service.ICoOperationLogService
;
import
com.yd.communication.service.service.ICoSessionService
;
import
com.yd.communication.service.service.ICoSessionService
;
import
com.yd.communication.service.service.IRecordingTaskService
;
import
com.yd.communication.service.service.IRecordingTaskService
;
import
com.yd.communication.service.utils.CffpTokenUtil
;
import
com.yd.communication.service.utils.RandomUtil
;
import
com.yd.communication.service.utils.RandomUtil
;
import
com.yd.communication.service.utils.SfpTokenUtil
;
import
com.yd.oss.feign.client.ApiOssFeignClient
;
import
com.yd.oss.feign.client.ApiOssFeignClient
;
import
com.yd.oss.feign.request.ApiUploadFileRequest
;
import
com.yd.oss.feign.request.ApiUploadFileRequest
;
import
com.yd.oss.feign.response.ApiUploadResponse
;
import
com.yd.oss.feign.response.ApiUploadResponse
;
...
@@ -43,6 +45,7 @@ import org.springframework.web.client.RestTemplate;
...
@@ -43,6 +45,7 @@ import org.springframework.web.client.RestTemplate;
import
org.springframework.web.multipart.MultipartFile
;
import
org.springframework.web.multipart.MultipartFile
;
import
javax.annotation.Resource
;
import
javax.annotation.Resource
;
import
javax.servlet.http.HttpServletRequest
;
import
java.time.LocalDateTime
;
import
java.time.LocalDateTime
;
import
java.util.Date
;
import
java.util.Date
;
import
java.util.UUID
;
import
java.util.UUID
;
...
@@ -731,6 +734,91 @@ public class ApiCoSessionServiceImpl implements ApiCoSessionService {
...
@@ -731,6 +734,91 @@ public class ApiCoSessionServiceImpl implements ApiCoSessionService {
}
}
}
}
/**
* 根据房间号和密码获取会话详情
*
* @param roomId 房间号
* @param roomPwd 房间密码
* @return 完整会话信息
*/
@Override
public
Result
<
SessionDetailResponse
>
get
(
String
roomId
,
String
roomPwd
)
{
log
.
info
(
"【根据房间号和密码获取会话详情】roomId={}, roomPwd={}"
,
roomId
,
roomPwd
);
if
(
StringUtils
.
isBlank
(
roomId
))
{
throw
new
BusinessException
(
"房间号不能为空"
);
}
if
(
StringUtils
.
isBlank
(
roomPwd
))
{
throw
new
BusinessException
(
"房间密码不能为空"
);
}
//查询会话详情
LambdaQueryWrapper
<
CoSession
>
wrapper
=
new
LambdaQueryWrapper
<>();
wrapper
.
eq
(
CoSession:
:
getRoomId
,
roomId
)
.
eq
(
CoSession:
:
getRoomPwd
,
roomPwd
)
.
last
(
" limit 1 "
);
CoSession
session
=
iCoSessionService
.
getOne
(
wrapper
);
if
(
session
==
null
)
{
throw
new
BusinessException
(
"会话信息不存在"
);
}
SessionDetailResponse
response
=
new
SessionDetailResponse
();
BeanUtils
.
copyProperties
(
session
,
response
);
return
Result
.
success
(
response
);
}
/**
* 判断资源创建者和参与者是否是同一个人
*
* @param roomId 房间号
* @param roomPwd 房间密码
* @return true-是同一人 false-不是同一人
*/
@Override
public
Result
<
Boolean
>
isMy
(
String
roomId
,
String
roomPwd
,
HttpServletRequest
httpRequest
)
{
log
.
info
(
"【判断资源创建者和参与者是否是同一个人】roomId={}, roomPwd={}"
,
roomId
,
roomPwd
);
if
(
StringUtils
.
isBlank
(
roomId
))
{
throw
new
BusinessException
(
"房间号不能为空"
);
}
if
(
StringUtils
.
isBlank
(
roomPwd
))
{
throw
new
BusinessException
(
"房间密码不能为空"
);
}
//解析SFP参与者的token信息,提取用户ID
//解析 Token
String
authorization
=
httpRequest
.
getHeader
(
"X-Authorization"
);
if
(
StringUtils
.
isBlank
(
authorization
))
{
throw
new
BusinessException
(
"访问者(参与者)token信息不能为空"
);
}
//参与者用户ID
Long
userId
=
null
;
String
userIdStr
=
SfpTokenUtil
.
getUserIdFromToken
(
authorization
);
if
(
StringUtils
.
isNotBlank
(
userIdStr
))
{
try
{
userId
=
Long
.
valueOf
(
userIdStr
);
}
catch
(
NumberFormatException
ignored
)
{
log
.
info
(
"【判断资源创建者和参与者是否是同一个人】errorMsg={}"
,
ignored
.
getMessage
());
}
}
if
(
userId
==
null
)
{
throw
new
BusinessException
(
"访问者(参与者)token的用户ID解析为空"
);
}
//查询会话信息
LambdaQueryWrapper
<
CoSession
>
wrapper
=
new
LambdaQueryWrapper
<>();
wrapper
.
eq
(
CoSession:
:
getRoomId
,
roomId
)
.
eq
(
CoSession:
:
getRoomPwd
,
roomPwd
)
.
last
(
" limit 1 "
);
CoSession
session
=
iCoSessionService
.
getOne
(
wrapper
);
if
(
session
==
null
)
{
throw
new
BusinessException
(
"会话信息不存在"
);
}
//比较参与者的用户ID和创建者的用户ID是否相同,相同代表同一个人
String
creatorId
=
session
.
getOwnerId
();
if
(
userId
.
equals
(
creatorId
))
{
//是同一个人
return
Result
.
success
(
true
);
}
return
Result
.
success
(
false
);
}
private
boolean
autoStartRecording
()
{
private
boolean
autoStartRecording
()
{
return
true
;
// 从配置读取
return
true
;
// 从配置读取
}
}
...
...
yd-communication-feign/src/main/java/com/yd/communication/feign/client/ApiCoSessionFeignClient.java
View file @
30c7bd23
...
@@ -8,6 +8,8 @@ import org.springframework.cloud.openfeign.FeignClient;
...
@@ -8,6 +8,8 @@ import org.springframework.cloud.openfeign.FeignClient;
import
org.springframework.validation.annotation.Validated
;
import
org.springframework.validation.annotation.Validated
;
import
org.springframework.web.bind.annotation.*
;
import
org.springframework.web.bind.annotation.*
;
import
javax.servlet.http.HttpServletRequest
;
/**
/**
* 通信服务-协同会话信息 Feign 客户端
* 通信服务-协同会话信息 Feign 客户端
...
@@ -37,6 +39,29 @@ public interface ApiCoSessionFeignClient {
...
@@ -37,6 +39,29 @@ public interface ApiCoSessionFeignClient {
Result
<
JoinResponse
>
join
(
@Validated
@RequestBody
JoinRequest
request
);
Result
<
JoinResponse
>
join
(
@Validated
@RequestBody
JoinRequest
request
);
/**
/**
* 根据房间号和密码获取会话详情
*
* @param roomId 房间号
* @param roomPwd 房间密码
* @return 完整会话信息
*/
@GetMapping
(
"/detail/{roomId}/{roomPwd}"
)
Result
<
SessionDetailResponse
>
get
(
@PathVariable
(
"roomId"
)
String
roomId
,
@PathVariable
(
"roomPwd"
)
String
roomPwd
);
/**
* 判断资源创建者和参与者是否是同一个人(供参与者调用)
*
* @param roomId 房间号
* @param roomPwd 房间密码
* @return true-是同一人 false-不是同一人
*/
@GetMapping
(
"/isMy/{roomId}/{roomPwd}"
)
Result
<
Boolean
>
isMy
(
@PathVariable
(
"roomId"
)
String
roomId
,
@PathVariable
(
"roomPwd"
)
String
roomPwd
,
HttpServletRequest
httpRequest
);
/**
* 获取会话状态
* 获取会话状态
* @param request
* @param request
* @return
* @return
...
...
yd-communication-feign/src/main/java/com/yd/communication/feign/fallback/ApiCoSessionFeignFallbackFactory.java
View file @
30c7bd23
...
@@ -8,6 +8,8 @@ import lombok.extern.slf4j.Slf4j;
...
@@ -8,6 +8,8 @@ import lombok.extern.slf4j.Slf4j;
import
org.springframework.cloud.openfeign.FallbackFactory
;
import
org.springframework.cloud.openfeign.FallbackFactory
;
import
org.springframework.stereotype.Component
;
import
org.springframework.stereotype.Component
;
import
javax.servlet.http.HttpServletRequest
;
/**
/**
* 通信服务-协同会话信息Feign降级处理
* 通信服务-协同会话信息Feign降级处理
*/
*/
...
@@ -24,6 +26,16 @@ public class ApiCoSessionFeignFallbackFactory implements FallbackFactory<ApiCoSe
...
@@ -24,6 +26,16 @@ public class ApiCoSessionFeignFallbackFactory implements FallbackFactory<ApiCoSe
}
}
@Override
@Override
public
Result
<
SessionDetailResponse
>
get
(
String
roomId
,
String
roomPwd
)
{
return
null
;
}
@Override
public
Result
<
Boolean
>
isMy
(
String
roomId
,
String
roomPwd
,
HttpServletRequest
httpRequest
)
{
return
null
;
}
@Override
public
Result
<
JoinResponse
>
join
(
JoinRequest
request
)
{
public
Result
<
JoinResponse
>
join
(
JoinRequest
request
)
{
return
null
;
return
null
;
}
}
...
...
yd-communication-service/src/main/java/com/yd/communication/service/utils/CffpTokenUtil.java
0 → 100644
View file @
30c7bd23
package
com
.
yd
.
communication
.
service
.
utils
;
import
io.jsonwebtoken.*
;
import
lombok.extern.slf4j.Slf4j
;
import
org.springframework.stereotype.Service
;
import
javax.annotation.PostConstruct
;
import
java.util.Date
;
import
java.util.HashMap
;
import
java.util.Map
;
/**
* CFFP 项目专用 JWT Token 工具类
* 完全在代码内部获取环境标识(System.getProperty),硬编码不同环境的配置
* 支持生成 Token 和解析 Token(获取 userId、cffpUserId 等)
*
* @author yourname
*/
@Slf4j
@Service
public
class
CffpTokenUtil
{
// JWT 标准声明 Key
private
static
final
String
CLAIM_KEY_SUBJECT
=
"sub"
;
private
static
final
String
CLAIM_KEY_CREATED
=
"created"
;
// 自定义声明 Key(与 CffpTokenFilter 保持一致)
private
static
final
String
CLAIM_KEY_USERID
=
"UserId"
;
private
static
final
String
CLAIM_KEY_CFFP_USERID
=
"cffpUserId"
;
// 静态配置字段(一套配置,根据环境加载不同的值)
private
static
String
seal
;
private
static
String
issuer
;
private
static
Long
expiration
;
/**
* 初始化:通过 System.getProperty 获取环境,硬编码对应的配置
* 该方法在 Spring 容器启动完成后自动执行
*/
@PostConstruct
public
void
init
()
{
// 从系统属性中获取 spring.profiles.active,如果获取不到则默认为 "default"
String
activeProfile
=
System
.
getProperty
(
"spring.profiles.active"
,
"default"
);
// 判断是否为生产环境
boolean
isProd
=
"prod"
.
equalsIgnoreCase
(
activeProfile
)
||
"production"
.
equalsIgnoreCase
(
activeProfile
)
||
activeProfile
.
toLowerCase
().
contains
(
"prod"
);
if
(
isProd
)
{
// 生产环境配置
seal
=
"zhb123!@#"
;
issuer
=
"cffpwealthcenter"
;
expiration
=
2592000L
;
log
.
info
(
"CffpTokenUtil 加载生产环境配置, issuer: {}, expiration: {} 秒"
,
issuer
,
expiration
);
}
else
{
// 测试/开发环境配置
seal
=
"zhb123!@#"
;
issuer
=
"zuihuibi"
;
expiration
=
86400000L
;
log
.
info
(
"CffpTokenUtil 加载测试环境配置, issuer: {}, expiration: {} 秒"
,
issuer
,
expiration
);
}
}
// ======================== 生成 Token ========================
/**
* 生成 JWT Token(自动添加 issuer 前缀,如 "zuihuibi {token}")
*
* @param ticket 用户标识(通常为登录名或唯一标识)
* @param userId 用户 ID(字符串)
* @param cffpUserId CFFP 用户 ID(可选)
* @return 完整 Token 字符串(含前缀)
*/
public
static
String
generateToken
(
String
ticket
,
String
userId
,
String
cffpUserId
)
{
Map
<
String
,
Object
>
claims
=
new
HashMap
<>();
claims
.
put
(
CLAIM_KEY_SUBJECT
,
ticket
);
claims
.
put
(
CLAIM_KEY_USERID
,
userId
);
if
(
cffpUserId
!=
null
)
{
claims
.
put
(
CLAIM_KEY_CFFP_USERID
,
cffpUserId
);
}
claims
.
put
(
CLAIM_KEY_CREATED
,
new
Date
());
String
token
=
Jwts
.
builder
()
.
setClaims
(
claims
)
.
setExpiration
(
new
Date
(
System
.
currentTimeMillis
()
+
expiration
*
1000
))
.
signWith
(
SignatureAlgorithm
.
HS512
,
seal
)
.
compact
();
return
issuer
+
" "
+
token
;
}
// ======================== 解析 Token ========================
/**
* 从 Token 中解析 Claims
*
* @param token 原始 Token(可能包含 issuer 前缀)
* @return Map, key 包含 "resultCode"(SUCCESS/EXPIRED/INVALID)和 "claims"(解析成功时为 Claims 对象)
*/
public
static
Map
<
String
,
Object
>
getClaimsFromToken
(
String
token
)
{
Map
<
String
,
Object
>
map
=
new
HashMap
<>();
String
resultCode
=
"SUCCESS"
;
Claims
claims
=
null
;
if
(
token
==
null
||
token
.
isEmpty
())
{
map
.
put
(
"resultCode"
,
"INVALID"
);
map
.
put
(
"claims"
,
null
);
return
map
;
}
try
{
// 去除 issuer 前缀(如果存在)
String
realToken
=
token
;
if
(
token
.
startsWith
(
issuer
+
" "
))
{
realToken
=
token
.
substring
(
issuer
.
length
()
+
1
);
}
Jws
<
Claims
>
jwsClaims
=
Jwts
.
parser
()
.
setSigningKey
(
seal
)
.
parseClaimsJws
(
realToken
);
claims
=
jwsClaims
.
getBody
();
}
catch
(
ExpiredJwtException
e
)
{
resultCode
=
"EXPIRED"
;
}
catch
(
UnsupportedJwtException
|
MalformedJwtException
|
SignatureException
|
IllegalArgumentException
e
)
{
resultCode
=
"INVALID"
;
}
catch
(
Exception
e
)
{
resultCode
=
"INVALID"
;
}
map
.
put
(
"resultCode"
,
resultCode
);
map
.
put
(
"claims"
,
claims
);
return
map
;
}
/**
* 从 Token 中获取用户 ID(String 形式)
*
* @param token 原始 Token
* @return 用户 ID 字符串,解析失败返回 null
*/
public
static
String
getUserIdFromToken
(
String
token
)
{
Map
<
String
,
Object
>
map
=
getClaimsFromToken
(
token
);
if
(
"SUCCESS"
.
equals
(
map
.
get
(
"resultCode"
)))
{
Claims
claims
=
(
Claims
)
map
.
get
(
"claims"
);
if
(
claims
!=
null
)
{
Object
userId
=
claims
.
get
(
CLAIM_KEY_USERID
);
return
userId
!=
null
?
userId
.
toString
()
:
null
;
}
}
return
null
;
}
/**
* 从 Token 中获取 CFFP 用户 ID
*
* @param token 原始 Token
* @return CFFP 用户 ID 字符串,解析失败返回 null
*/
public
static
String
getCffpUserIdFromToken
(
String
token
)
{
Map
<
String
,
Object
>
map
=
getClaimsFromToken
(
token
);
if
(
"SUCCESS"
.
equals
(
map
.
get
(
"resultCode"
)))
{
Claims
claims
=
(
Claims
)
map
.
get
(
"claims"
);
if
(
claims
!=
null
)
{
Object
cffpUserId
=
claims
.
get
(
CLAIM_KEY_CFFP_USERID
);
return
cffpUserId
!=
null
?
cffpUserId
.
toString
()
:
null
;
}
}
return
null
;
}
/**
* 验证 Token 是否有效(未过期、格式正确)
*
* @param token 原始 Token
* @return true 表示有效,false 表示无效或过期
*/
public
static
boolean
validateToken
(
String
token
)
{
Map
<
String
,
Object
>
map
=
getClaimsFromToken
(
token
);
return
"SUCCESS"
.
equals
(
map
.
get
(
"resultCode"
));
}
/**
* 检查 Token 是否过期
*
* @param token 原始 Token
* @return true 表示已过期,false 表示未过期或解析失败
*/
public
static
boolean
isTokenExpired
(
String
token
)
{
Map
<
String
,
Object
>
map
=
getClaimsFromToken
(
token
);
String
resultCode
=
(
String
)
map
.
get
(
"resultCode"
);
if
(
"EXPIRED"
.
equals
(
resultCode
))
{
return
true
;
}
if
(
"SUCCESS"
.
equals
(
resultCode
))
{
Claims
claims
=
(
Claims
)
map
.
get
(
"claims"
);
if
(
claims
!=
null
)
{
Date
expirationDate
=
claims
.
getExpiration
();
return
expirationDate
!=
null
&&
expirationDate
.
before
(
new
Date
());
}
}
return
false
;
}
}
\ No newline at end of file
yd-communication-service/src/main/java/com/yd/communication/service/utils/SfpTokenUtil.java
0 → 100644
View file @
30c7bd23
package
com
.
yd
.
communication
.
service
.
utils
;
import
io.jsonwebtoken.*
;
import
lombok.extern.slf4j.Slf4j
;
import
org.springframework.stereotype.Service
;
import
javax.annotation.PostConstruct
;
import
java.util.Date
;
import
java.util.HashMap
;
import
java.util.Map
;
/**
* SFP 项目专用 JWT Token 工具类
* 完全在代码内部获取环境标识(System.getProperty),硬编码不同环境的配置
* 支持生成 Token 和解析 Token(获取 userId、customerId 等)
*
* @author yourname
*/
@Slf4j
@Service
public
class
SfpTokenUtil
{
// JWT 标准声明 Key
private
static
final
String
CLAIM_KEY_SUBJECT
=
"sub"
;
private
static
final
String
CLAIM_KEY_CREATED
=
"created"
;
// 自定义声明 Key(与 JwtTokenUtil 保持一致)
private
static
final
String
CLAIM_KEY_USERID
=
"UserId"
;
private
static
final
String
CLAIM_KEY_CUSTOMERID
=
"CustomerId"
;
// 静态配置字段
private
static
String
seal
;
private
static
String
issuer
;
private
static
Long
expiration
;
/**
* 初始化:通过 System.getProperty 获取环境,硬编码对应的配置
* 该方法在 Spring 容器启动完成后自动执行
*/
@PostConstruct
public
void
init
()
{
// 从系统属性中获取 spring.profiles.active,如果获取不到则默认为 "default"
String
activeProfile
=
System
.
getProperty
(
"spring.profiles.active"
,
"default"
);
// 判断是否为生产环境(可自定义判断规则,如包含 "prod" 或 "production")
boolean
isProd
=
"prod"
.
equalsIgnoreCase
(
activeProfile
)
||
"production"
.
equalsIgnoreCase
(
activeProfile
)
||
activeProfile
.
toLowerCase
().
contains
(
"prod"
);
if
(
isProd
)
{
// 生产环境配置(请替换为实际的生产密钥)
seal
=
"SFP2023!@#"
;
issuer
=
"sfpfamilyfinancialplanning"
;
expiration
=
2592000L
;
// 24小时
log
.
info
(
"SfpTokenUtil 加载生产环境配置, issuer: {}, expiration: {} 秒"
,
issuer
,
expiration
);
}
else
{
// 测试/开发环境配置(请替换为实际的测试密钥)
seal
=
"zhb123!@#"
;
issuer
=
"zuihuibi"
;
expiration
=
2592000L
;
log
.
info
(
"SfpTokenUtil 加载测试环境配置, issuer: {}, expiration: {} 秒"
,
issuer
,
expiration
);
}
}
// ======================== 生成 Token ========================
/**
* 生成 JWT Token(自动添加 issuer 前缀,如 "zuihuibi {token}")
*
* @param ticket 用户标识(通常为登录名或唯一标识)
* @param userId 用户 ID(字符串)
* @param customerId 客户 ID(可选)
* @return 完整 Token 字符串(含前缀)
*/
public
static
String
generateToken
(
String
ticket
,
String
userId
,
String
customerId
)
{
Map
<
String
,
Object
>
claims
=
new
HashMap
<>();
claims
.
put
(
CLAIM_KEY_SUBJECT
,
ticket
);
claims
.
put
(
CLAIM_KEY_USERID
,
userId
);
if
(
customerId
!=
null
)
{
claims
.
put
(
CLAIM_KEY_CUSTOMERID
,
customerId
);
}
claims
.
put
(
CLAIM_KEY_CREATED
,
new
Date
());
String
token
=
Jwts
.
builder
()
.
setClaims
(
claims
)
.
setExpiration
(
new
Date
(
System
.
currentTimeMillis
()
+
expiration
*
1000
))
.
signWith
(
SignatureAlgorithm
.
HS512
,
seal
)
.
compact
();
return
issuer
+
" "
+
token
;
}
// ======================== 解析 Token ========================
/**
* 从 Token 中解析 Claims(包含所有声明信息)
*
* @param token 原始 Token(可能包含 issuer 前缀)
* @return Map, key 包含 "resultCode"(SUCCESS/EXPIRED/INVALID)和 "claims"(解析成功时为 Claims 对象)
*/
public
static
Map
<
String
,
Object
>
getClaimsFromToken
(
String
token
)
{
Map
<
String
,
Object
>
map
=
new
HashMap
<>();
String
resultCode
=
"SUCCESS"
;
Claims
claims
=
null
;
try
{
// 去除 issuer 前缀(如果存在)
String
realToken
=
token
;
if
(
token
.
startsWith
(
issuer
+
" "
))
{
realToken
=
token
.
substring
(
issuer
.
length
()
+
1
);
}
Jws
<
Claims
>
jwsClaims
=
Jwts
.
parser
()
.
setSigningKey
(
seal
)
.
parseClaimsJws
(
realToken
);
claims
=
jwsClaims
.
getBody
();
}
catch
(
ExpiredJwtException
e
)
{
resultCode
=
"EXPIRED"
;
}
catch
(
UnsupportedJwtException
|
MalformedJwtException
|
SignatureException
|
IllegalArgumentException
e
)
{
resultCode
=
"INVALID"
;
}
catch
(
Exception
e
)
{
resultCode
=
"INVALID"
;
}
map
.
put
(
"resultCode"
,
resultCode
);
map
.
put
(
"claims"
,
claims
);
return
map
;
}
/**
* 从 Token 中获取用户 ID(String 形式)
*
* @param token 原始 Token
* @return 用户 ID 字符串,解析失败返回 null
*/
public
static
String
getUserIdFromToken
(
String
token
)
{
Map
<
String
,
Object
>
map
=
getClaimsFromToken
(
token
);
if
(
"SUCCESS"
.
equals
(
map
.
get
(
"resultCode"
)))
{
Claims
claims
=
(
Claims
)
map
.
get
(
"claims"
);
if
(
claims
!=
null
)
{
Object
userId
=
claims
.
get
(
CLAIM_KEY_USERID
);
return
userId
!=
null
?
userId
.
toString
()
:
null
;
}
}
return
null
;
}
/**
* 从 Token 中获取客户 ID
*
* @param token 原始 Token
* @return 客户 ID 字符串,解析失败返回 null
*/
public
static
String
getCustomerIdFromToken
(
String
token
)
{
Map
<
String
,
Object
>
map
=
getClaimsFromToken
(
token
);
if
(
"SUCCESS"
.
equals
(
map
.
get
(
"resultCode"
)))
{
Claims
claims
=
(
Claims
)
map
.
get
(
"claims"
);
if
(
claims
!=
null
)
{
Object
customerId
=
claims
.
get
(
CLAIM_KEY_CUSTOMERID
);
return
customerId
!=
null
?
customerId
.
toString
()
:
null
;
}
}
return
null
;
}
/**
* 验证 Token 是否有效(未过期、格式正确)
*
* @param token 原始 Token
* @return true 表示有效,false 表示无效或过期
*/
public
static
boolean
validateToken
(
String
token
)
{
Map
<
String
,
Object
>
map
=
getClaimsFromToken
(
token
);
return
"SUCCESS"
.
equals
(
map
.
get
(
"resultCode"
));
}
/**
* 检查 Token 是否过期
*
* @param token 原始 Token
* @return true 表示已过期,false 表示未过期或解析失败
*/
public
static
boolean
isTokenExpired
(
String
token
)
{
Map
<
String
,
Object
>
map
=
getClaimsFromToken
(
token
);
String
resultCode
=
(
String
)
map
.
get
(
"resultCode"
);
if
(
"EXPIRED"
.
equals
(
resultCode
))
{
return
true
;
}
if
(
"SUCCESS"
.
equals
(
resultCode
))
{
Claims
claims
=
(
Claims
)
map
.
get
(
"claims"
);
if
(
claims
!=
null
)
{
Date
expirationDate
=
claims
.
getExpiration
();
return
expirationDate
!=
null
&&
expirationDate
.
before
(
new
Date
());
}
}
return
false
;
}
}
\ No newline at end of file
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