Compare commits
3 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 2d84bda99a | |||
| e3c8350d03 | |||
| a8e29a641a |
@@ -5,6 +5,11 @@
|
|||||||
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
||||||
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||||
|
|
||||||
|
## [1.0.58] - 2026-06-18
|
||||||
|
|
||||||
|
### 修复
|
||||||
|
- 修复已登录用户授权长期停留在「未激活」的问题:此前仅全新登录才会自动发放 30 天试用,靠本地令牌自动续登的老用户始终拿不到,现在续登时也会补发
|
||||||
|
|
||||||
## [1.0.57] - 2026-06-18
|
## [1.0.57] - 2026-06-18
|
||||||
|
|
||||||
### 新功能
|
### 新功能
|
||||||
|
|||||||
@@ -419,6 +419,11 @@ func (s *AuthService) RefreshTokens(refreshToken string) (*TokenPair, error) {
|
|||||||
Update("last_seen_at", time.Now())
|
Update("last_seen_at", time.Now())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 自动续登(refresh)路径同样补发首次试用:老用户用本地 refresh token 自动登录、
|
||||||
|
// 从不走 Login(),否则永远停留在「未激活」。须在 issueTokens 之前,使新 JWT 的
|
||||||
|
// lic_exp 带上试用到期日。
|
||||||
|
s.ensureTrialOnFirstUse(user.ShopID)
|
||||||
|
|
||||||
return s.issueTokens(user.ID, user.ShopID, user.Role, claims.SID)
|
return s.issueTokens(user.ID, user.ShopID, user.Role, claims.SID)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -300,68 +300,37 @@ class _AppShellState extends ConsumerState<AppShell> {
|
|||||||
}).toList(),
|
}).toList(),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
// 当前登录账号(顶栏移下来的用户名):点击弹门店/账号/版本面板
|
// 当前登录账号:点击弹下拉菜单(退出登录)
|
||||||
if (user != null) ...[
|
if (user != null) ...[
|
||||||
const Divider(height: 1, color: Colors.white24),
|
const Divider(height: 1, color: Colors.white24),
|
||||||
SizedBox(
|
PopupMenuButton<String>(
|
||||||
height: 48,
|
tooltip: '账号菜单',
|
||||||
child: Material(
|
position: PopupMenuPosition.over,
|
||||||
color: Colors.transparent,
|
offset: const Offset(0, -8),
|
||||||
child: InkWell(
|
shape: RoundedRectangleBorder(
|
||||||
onTap: () => _showShopPanel(context, user,
|
borderRadius: BorderRadius.circular(6)),
|
||||||
version: appVersion),
|
color: Colors.white,
|
||||||
hoverColor: Colors.white.withAlpha(13),
|
elevation: 8,
|
||||||
splashColor: Colors.white.withAlpha(26),
|
onSelected: (v) {
|
||||||
child: Row(
|
if (v == 'logout') {
|
||||||
children: [
|
|
||||||
SizedBox(
|
|
||||||
width: _sidebarExpanded ? 16 : 3),
|
|
||||||
Expanded(
|
|
||||||
child: Row(
|
|
||||||
mainAxisAlignment: _sidebarExpanded
|
|
||||||
? MainAxisAlignment.start
|
|
||||||
: MainAxisAlignment.center,
|
|
||||||
children: [
|
|
||||||
const Icon(Icons.person_outline,
|
|
||||||
color: Colors.white60,
|
|
||||||
size: 20),
|
|
||||||
if (_sidebarExpanded) ...[
|
|
||||||
const SizedBox(width: 12),
|
|
||||||
Expanded(
|
|
||||||
child: Text(
|
|
||||||
user.username,
|
|
||||||
style: const TextStyle(
|
|
||||||
color: Colors.white70,
|
|
||||||
fontSize: 14),
|
|
||||||
overflow:
|
|
||||||
TextOverflow.ellipsis,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
// 退出登录(侧栏底部常驻;统一为左侧导航唯一退出入口)
|
|
||||||
const Divider(height: 1, color: Colors.white24),
|
|
||||||
SizedBox(
|
|
||||||
height: 48,
|
|
||||||
child: Material(
|
|
||||||
color: Colors.transparent,
|
|
||||||
child: InkWell(
|
|
||||||
onTap: () {
|
|
||||||
ref
|
ref
|
||||||
.read(authStateProvider.notifier)
|
.read(authStateProvider.notifier)
|
||||||
.logout();
|
.logout();
|
||||||
context.go('/login');
|
context.go('/login');
|
||||||
},
|
}
|
||||||
hoverColor: Colors.white.withAlpha(13),
|
},
|
||||||
splashColor: Colors.white.withAlpha(26),
|
itemBuilder: (context) => const [
|
||||||
|
PopupMenuItem<String>(
|
||||||
|
value: 'logout',
|
||||||
|
padding: EdgeInsets.zero,
|
||||||
|
child: _HoverMenuItem(
|
||||||
|
icon: Icons.logout,
|
||||||
|
label: '退出登录',
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
child: SizedBox(
|
||||||
|
height: 48,
|
||||||
child: Row(
|
child: Row(
|
||||||
children: [
|
children: [
|
||||||
SizedBox(width: _sidebarExpanded ? 16 : 3),
|
SizedBox(width: _sidebarExpanded ? 16 : 3),
|
||||||
@@ -371,14 +340,24 @@ class _AppShellState extends ConsumerState<AppShell> {
|
|||||||
? MainAxisAlignment.start
|
? MainAxisAlignment.start
|
||||||
: MainAxisAlignment.center,
|
: MainAxisAlignment.center,
|
||||||
children: [
|
children: [
|
||||||
const Icon(Icons.logout,
|
const Icon(Icons.person_outline,
|
||||||
color: Colors.white60, size: 20),
|
color: Colors.white60, size: 20),
|
||||||
if (_sidebarExpanded) ...[
|
if (_sidebarExpanded) ...[
|
||||||
const SizedBox(width: 12),
|
const SizedBox(width: 12),
|
||||||
const Text('退出登录',
|
Expanded(
|
||||||
style: TextStyle(
|
child: Text(
|
||||||
|
user.username,
|
||||||
|
style: const TextStyle(
|
||||||
color: Colors.white70,
|
color: Colors.white70,
|
||||||
fontSize: 14)),
|
fontSize: 14),
|
||||||
|
overflow: TextOverflow.ellipsis,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const Icon(
|
||||||
|
Icons.keyboard_arrow_up,
|
||||||
|
color: Colors.white38,
|
||||||
|
size: 18),
|
||||||
|
const SizedBox(width: 12),
|
||||||
],
|
],
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
@@ -387,7 +366,7 @@ class _AppShellState extends ConsumerState<AppShell> {
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
],
|
||||||
const SizedBox(height: 8),
|
const SizedBox(height: 8),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
|
|||||||
@@ -6,6 +6,8 @@ JWT_SECRET=CHANGE_ME_RANDOM_32CHARS
|
|||||||
JWT_ACCESS_EXPIRE_MIN=60
|
JWT_ACCESS_EXPIRE_MIN=60
|
||||||
JWT_REFRESH_EXPIRE_H=168
|
JWT_REFRESH_EXPIRE_H=168
|
||||||
LICENSE_HMAC_SECRET=CHANGE_ME_RANDOM_32CHARS
|
LICENSE_HMAC_SECRET=CHANGE_ME_RANDOM_32CHARS
|
||||||
|
LICENSE_ED25519_PUBLIC_KEY=zFkRV0E+oMjHbixiBamf2ZAq+n7En2V7EJRIurgtVxo=
|
||||||
|
LICENSE_ED25519_PRIVATE_KEY=CHANGE_ME_ED25519_PRIVATE_FROM_BITWARDEN
|
||||||
STORAGE_UPLOAD_DIR=/opt/jiu/images
|
STORAGE_UPLOAD_DIR=/opt/jiu/images
|
||||||
STORAGE_BASE_URL=https://jiu.51yanmei.com/images
|
STORAGE_BASE_URL=https://jiu.51yanmei.com/images
|
||||||
STORAGE_PUBLIC_URL=https://jiu.51yanmei.com
|
STORAGE_PUBLIC_URL=https://jiu.51yanmei.com
|
||||||
|
|||||||
@@ -15,8 +15,8 @@ set -euo pipefail
|
|||||||
|
|
||||||
# ---- 可配置项 ----
|
# ---- 可配置项 ----
|
||||||
RBW="${RBW_BIN:-/opt/homebrew/bin/rbw}"
|
RBW="${RBW_BIN:-/opt/homebrew/bin/rbw}"
|
||||||
BW_ITEM="${JIU_BW_ITEM:-DB_PASSWORD}" # 存放 jiu 密钥字段的 Bitwarden 条目
|
BW_ITEM="${JIU_BW_ITEM:-jiu db password}" # 存放 jiu 密钥字段的 Bitwarden 条目
|
||||||
SECRET_KEYS="DATABASE_DSN JWT_SECRET LICENSE_HMAC_SECRET DB_PASSWORD"
|
SECRET_KEYS="DATABASE_DSN JWT_SECRET LICENSE_HMAC_SECRET LICENSE_ED25519_PRIVATE_KEY DB_PASSWORD"
|
||||||
|
|
||||||
EC2_HOST="${EC2_HOST:-18.136.60.128}"
|
EC2_HOST="${EC2_HOST:-18.136.60.128}"
|
||||||
EC2_USER="${EC2_USER:-ec2-user}"
|
EC2_USER="${EC2_USER:-ec2-user}"
|
||||||
|
|||||||
Reference in New Issue
Block a user