记得上下班打卡 | git大法好,push需谨慎
Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
L
liquidnet-bus-v1
Project
Project
Details
Activity
Releases
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
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
董敬伟
liquidnet-bus-v1
Commits
60674a7b
Commit
60674a7b
authored
May 26, 2026
by
姜秀龙
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
feat(adam): 静默登录 去掉时间限制
parent
3b6f11a9
Changes
5
Hide whitespace changes
Inline
Side-by-side
Showing
5 changed files
with
8 additions
and
103 deletions
+8
-103
adam_multi_session_and_silent_login_design.md
docs/adam_multi_session_and_silent_login_design.md
+0
-77
application-dev.yml
liquidnet-bus-config/liquidnet-config/application-dev.yml
+0
-1
application-test.yml
liquidnet-bus-config/liquidnet-config/application-test.yml
+0
-1
SilentMobileOtpV2Support.java
...uidnet/service/adam/support/SilentMobileOtpV2Support.java
+7
-22
TestAdam.java
...m/liquidnet-service-adam-impl/src/test/java/TestAdam.java
+1
-2
No files found.
docs/adam_multi_session_and_silent_login_design.md
deleted
100644 → 0
View file @
3b6f11a9
# 粉丝俱乐部 ↔ 正在现场 技术设计(已定稿)
服务前缀:
`/adam`
、
`/order`
、
`/kylin`
、
`/goblin`
**已定**
:多端 JTI · 静默登录
`silent_mobile`
· 订单来源标记 · A 侧列表用 B token 调
**原接口**
、不过滤来源(不新建列表接口)
---
## 一、多端登录(JTI)
| 模块 | 改动 |
|------|------|
|
**adam**
`AdamLoginController#ssoProcess`
、各
`login/*`
| JWT 加
`jti`
,Redis
`session:{jti}`
;去掉
`adam:identity:sso:{uid}`
互踢 |
|
**adam**
`AdamAuthorityInterceptor`
、各业务拦截器 | 验 JWT 后查
`jti`
是否有效 |
---
## 二、静默登录
**链路**
:
`A 前端 → A 后端 → POST /adam/login/silent_mobile`
(A 前端不调 B)
| 接口 | 说明 |
|------|------|
|
`POST /adam/login/silent_mobile`
|
`otp = DES(手机号11位+Unix秒)`
,密钥仅 A/Adam 服务端配置化 |
| A 自建如
`POST /api/launch-zhengzai`
| 代调 silent_mobile,把
**B token**
给 WebView / 前端 |
A 侧订单:持
**B token**
调现有
`GET /kylin/order/list`
、
`POST /goblin/order/list`
等,
**不加来源筛选**
。
---
## 三、订单来源标记
### 入参(`PayOrderParam` / `GoblinOrderParam`)
| 字段 | 落库 |
|------|------|
|
`referrerApp`
| ✅ → 演出/商品均为
`order_source`
;
**与 referrerUserId 同时传**
才写入,否则
`''`
|
|
`referrerUserId`
| ✅ →
`referrer_user_id`
;未传写
`''`
|
### 落库与实现位置
| 表 | 粉丝俱乐部来源 | 客户端来源(不变) | 新增 |
|----|----------------|-------------------|------|
|
`kylin_order_tickets`
|
`order_source`
|
`order_type`
(header) |
`referrer_user_id`
|
|
`goblin_store_order`
|
`order_source`
|
`source`
(header) |
`referrer_user_id`
|
`POST /order/pre`
、
`POST /goblin/pre`
→
`KylinOrderTicketsServiceImpl#order`
、
`GoblinOrderServiceImpl`
建单处赋值。
### 列表 / 详情返回
| 类型 | VO |
|------|-----|
| 演出 |
`KylinOrderListVo`
、
`KylinOrderTicketVo`
(详情内)字段
`referrerApp`
、
`referrerUserId`
|
| 商品 |
`GoblinAppOrderListVo`
、
`GoblinStoreOrderVo`
(详情内)字段
`referrerApp`
、
`referrerUserId`
|
DDL:
`docu/order_referrer_kylin.sql`
、
`docu/order_referrer_goblin.sql`
---
## 四、分批实现(建议每批一个 commit)
| 顺序 | 范围 | 建议 commit message |
|------|------|---------------------|
| 1 | JTI 多端登录(adam 签发 + Redis 会话 + 拦截器去掉互踢) |
`feat(adam): 多端登录 JTI 会话,取消单设备互踢`
|
| 2 |
`silent_mobile`
密钥配置化(若需)+ 文档/注释 |
`chore(adam): silent_mobile 密钥配置化`
(可选,与 1 合并亦可) |
| 3 | 演出订单 DDL + 落库 + 列表详情 VO |
`feat(kylin): 演出订单粉丝俱乐部来源标记`
|
| 4 | 商品订单 DDL + 落库 + 列表详情 VO |
`feat(goblin): 商品订单粉丝俱乐部来源标记`
|
> A 项目(粉丝俱乐部)侧:`launch-zhengzai`、WebView 传参、持 B token 调原列表接口 — **在 A 仓库单独 commit**,不在本仓库。
---
## 变更记录
| 日期 | 说明 |
|------|------|
| 2026-05-16 | 定稿;移除新建列表接口;A 用 B token 调原接口 |
liquidnet-bus-config/liquidnet-config/application-dev.yml
View file @
60674a7b
...
@@ -15,7 +15,6 @@ liquidnet:
...
@@ -15,7 +15,6 @@ liquidnet:
adam
:
adam
:
# 静默登录 v2,与粉丝俱乐部 A 后端同配,生产请在配置中心设置
# 静默登录 v2,与粉丝俱乐部 A 后端同配,生产请在配置中心设置
silent-otp-v2-secret
:
4bG9EhEd3gtd51lO9dbHHbVy7G7QffRs
silent-otp-v2-secret
:
4bG9EhEd3gtd51lO9dbHHbVy7G7QffRs
silent-otp-v2-window-seconds
:
10
mysql
:
mysql
:
urlHostAndPort
:
java-test.mysql.polardb.rds.aliyuncs.com:3306
urlHostAndPort
:
java-test.mysql.polardb.rds.aliyuncs.com:3306
username
:
zhengzai
username
:
zhengzai
...
...
liquidnet-bus-config/liquidnet-config/application-test.yml
View file @
60674a7b
...
@@ -14,7 +14,6 @@ liquidnet:
...
@@ -14,7 +14,6 @@ liquidnet:
blacklist_grace_period
:
5
blacklist_grace_period
:
5
adam
:
adam
:
silent-otp-v2-secret
:
4bG9EhEd3gtd51lO9dbHHbVy7G7QffRs
silent-otp-v2-secret
:
4bG9EhEd3gtd51lO9dbHHbVy7G7QffRs
silent-otp-v2-window-seconds
:
10
mysql
:
mysql
:
urlHostAndPort
:
java-test.mysql.polardb.rds.aliyuncs.com:3306
urlHostAndPort
:
java-test.mysql.polardb.rds.aliyuncs.com:3306
username
:
zhengzai
username
:
zhengzai
...
...
liquidnet-bus-service/liquidnet-service-adam/liquidnet-service-adam-impl/src/main/java/com/liquidnet/service/adam/support/SilentMobileOtpV2Support.java
View file @
60674a7b
...
@@ -8,10 +8,9 @@ import javax.crypto.Mac;
...
@@ -8,10 +8,9 @@ import javax.crypto.Mac;
import
javax.crypto.spec.SecretKeySpec
;
import
javax.crypto.spec.SecretKeySpec
;
import
java.nio.charset.StandardCharsets
;
import
java.nio.charset.StandardCharsets
;
import
java.security.MessageDigest
;
import
java.security.MessageDigest
;
import
java.time.Instant
;
/**
/**
* 静默登录 v2:otp = hex(HMAC-SHA256(secret, mobile
+ Unix秒UTC)),与 v1 DES 隔离
。
* 静默登录 v2:otp = hex(HMAC-SHA256(secret, mobile
)),与 v1 DES 隔离。A/B 两侧均不带时间戳
。
*/
*/
@Component
@Component
public
class
SilentMobileOtpV2Support
{
public
class
SilentMobileOtpV2Support
{
...
@@ -21,9 +20,6 @@ public class SilentMobileOtpV2Support {
...
@@ -21,9 +20,6 @@ public class SilentMobileOtpV2Support {
@Value
(
"${liquidnet.adam.silent-otp-v2-secret:}"
)
@Value
(
"${liquidnet.adam.silent-otp-v2-secret:}"
)
private
String
secret
;
private
String
secret
;
@Value
(
"${liquidnet.adam.silent-otp-v2-window-seconds:10}"
)
private
int
windowSeconds
;
public
boolean
verify
(
String
mobile
,
String
otp
)
{
public
boolean
verify
(
String
mobile
,
String
otp
)
{
if
(
StringUtils
.
isBlank
(
secret
)
||
StringUtils
.
isBlank
(
mobile
)
||
StringUtils
.
isBlank
(
otp
))
{
if
(
StringUtils
.
isBlank
(
secret
)
||
StringUtils
.
isBlank
(
mobile
)
||
StringUtils
.
isBlank
(
otp
))
{
return
false
;
return
false
;
...
@@ -31,35 +27,24 @@ public class SilentMobileOtpV2Support {
...
@@ -31,35 +27,24 @@ public class SilentMobileOtpV2Support {
if
(!
otp
.
matches
(
"^[0-9a-fA-F]{64}$"
))
{
if
(!
otp
.
matches
(
"^[0-9a-fA-F]{64}$"
))
{
return
false
;
return
false
;
}
}
long
now
=
Instant
.
now
().
getEpochSecond
();
long
from
=
now
-
windowSeconds
;
if
(
from
<
0
)
{
from
=
0
;
}
byte
[]
otpBytes
=
hexToBytes
(
otp
);
byte
[]
otpBytes
=
hexToBytes
(
otp
);
if
(
otpBytes
==
null
)
{
if
(
otpBytes
==
null
)
{
return
false
;
return
false
;
}
}
for
(
long
ts
=
from
;
ts
<=
now
;
ts
++)
{
byte
[]
expected
=
sign
(
mobile
);
byte
[]
expected
=
sign
(
mobile
,
ts
);
return
expected
!=
null
&&
MessageDigest
.
isEqual
(
expected
,
otpBytes
);
if
(
expected
!=
null
&&
MessageDigest
.
isEqual
(
expected
,
otpBytes
))
{
return
true
;
}
}
return
false
;
}
}
public
String
signHex
(
String
mobile
,
long
epochSecondUtc
)
{
public
String
signHex
(
String
mobile
)
{
byte
[]
raw
=
sign
(
mobile
,
epochSecondUtc
);
byte
[]
raw
=
sign
(
mobile
);
return
raw
==
null
?
null
:
bytesToHex
(
raw
);
return
raw
==
null
?
null
:
bytesToHex
(
raw
);
}
}
private
byte
[]
sign
(
String
mobile
,
long
epochSecondUtc
)
{
private
byte
[]
sign
(
String
mobile
)
{
try
{
try
{
String
payload
=
mobile
+
epochSecondUtc
;
Mac
mac
=
Mac
.
getInstance
(
HMAC_SHA256
);
Mac
mac
=
Mac
.
getInstance
(
HMAC_SHA256
);
mac
.
init
(
new
SecretKeySpec
(
secret
.
getBytes
(
StandardCharsets
.
UTF_8
),
HMAC_SHA256
));
mac
.
init
(
new
SecretKeySpec
(
secret
.
getBytes
(
StandardCharsets
.
UTF_8
),
HMAC_SHA256
));
return
mac
.
doFinal
(
payload
.
getBytes
(
StandardCharsets
.
UTF_8
));
return
mac
.
doFinal
(
mobile
.
getBytes
(
StandardCharsets
.
UTF_8
));
}
catch
(
Exception
e
)
{
}
catch
(
Exception
e
)
{
return
null
;
return
null
;
}
}
...
...
liquidnet-bus-service/liquidnet-service-adam/liquidnet-service-adam-impl/src/test/java/TestAdam.java
View file @
60674a7b
...
@@ -116,7 +116,6 @@ public class TestAdam {
...
@@ -116,7 +116,6 @@ public class TestAdam {
@Test
@Test
public
void
testLoginBySilentMobileV2
()
{
public
void
testLoginBySilentMobileV2
()
{
String
mobile
=
"15811009011"
;
String
mobile
=
"15811009011"
;
long
ts
=
LocalDateTime
.
now
().
toEpochSecond
(
ZoneOffset
.
UTC
);
String
secret
=
System
.
getenv
(
"LIQUIDNET_ADAM_SILENT_OTP_V2_SECRET"
);
String
secret
=
System
.
getenv
(
"LIQUIDNET_ADAM_SILENT_OTP_V2_SECRET"
);
if
(
secret
==
null
||
secret
.
isEmpty
())
{
if
(
secret
==
null
||
secret
.
isEmpty
())
{
System
.
out
.
println
(
"skip v2 test: set env LIQUIDNET_ADAM_SILENT_OTP_V2_SECRET"
);
System
.
out
.
println
(
"skip v2 test: set env LIQUIDNET_ADAM_SILENT_OTP_V2_SECRET"
);
...
@@ -124,7 +123,7 @@ public class TestAdam {
...
@@ -124,7 +123,7 @@ public class TestAdam {
}
}
javax
.
crypto
.
Mac
mac
=
javax
.
crypto
.
Mac
.
getInstance
(
"HmacSHA256"
);
javax
.
crypto
.
Mac
mac
=
javax
.
crypto
.
Mac
.
getInstance
(
"HmacSHA256"
);
mac
.
init
(
new
javax
.
crypto
.
spec
.
SecretKeySpec
(
secret
.
getBytes
(
java
.
nio
.
charset
.
StandardCharsets
.
UTF_8
),
"HmacSHA256"
));
mac
.
init
(
new
javax
.
crypto
.
spec
.
SecretKeySpec
(
secret
.
getBytes
(
java
.
nio
.
charset
.
StandardCharsets
.
UTF_8
),
"HmacSHA256"
));
byte
[]
raw
=
mac
.
doFinal
(
(
mobile
+
ts
)
.
getBytes
(
java
.
nio
.
charset
.
StandardCharsets
.
UTF_8
));
byte
[]
raw
=
mac
.
doFinal
(
mobile
.
getBytes
(
java
.
nio
.
charset
.
StandardCharsets
.
UTF_8
));
StringBuilder
otp
=
new
StringBuilder
();
StringBuilder
otp
=
new
StringBuilder
();
for
(
byte
b
:
raw
)
{
for
(
byte
b
:
raw
)
{
otp
.
append
(
String
.
format
(
"%02x"
,
b
&
0xff
));
otp
.
append
(
String
.
format
(
"%02x"
,
b
&
0xff
));
...
...
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