feat: 登录会话持久化 + Caddy 反代部署方案

This commit is contained in:
root
2026-10-16 11:27:15 +08:00
parent de3add8881
commit 2660dc6fa9
7 changed files with 79 additions and 34 deletions
+4 -18
View File
@@ -21,24 +21,12 @@ import { categoryLabel, type Attendance, type LogItem, type Memo } from './db/sc
const toasts = useToasts()
// ---- 用户会话 ----
// ---- 用户会话(持久化登录,退出走顶栏按钮)----
const session = ref<Session | null>(getSession())
const IDLE_LOGOUT_MS = 30 * 60 * 1000
let sessionIdleTimer: number | null = null
function armSessionTimer() {
if (sessionIdleTimer !== null) window.clearTimeout(sessionIdleTimer)
if (!session.value) return
sessionIdleTimer = window.setTimeout(() => { doLogout(true) }, IDLE_LOGOUT_MS)
}
function onActivity() {
if (session.value) armSessionTimer()
}
async function onLogin(s: Session) {
session.value = s
location.hash = '#/calendar'
route.value = 'calendar'
armSessionTimer()
await refreshClock()
await refreshTip()
startSyncTimer()
@@ -49,12 +37,12 @@ async function onLogin(s: Session) {
showToast('已迁移原有数据 ' + mt + ' 条')
}
}
async function doLogout(auto: boolean) {
async function doLogout() {
await logoutUser()
session.value = null
route.value = 'calendar'
location.hash = '#/calendar'
showToast(auto ? '长时间未操作已自动退出' : '已退出登录')
showToast('已退出登录')
}
// ---- 自动同步:登录后与每 5 分钟,静默执行 ----
@@ -212,10 +200,8 @@ async function refreshTip() {
onMounted(async () => {
window.addEventListener('keydown', onGlobalKey)
window.addEventListener('click', onActivity)
if (session.value) {
openUserDatabase(session.value.userId)
armSessionTimer()
await refreshClock()
await refreshTip()
startSyncTimer()
@@ -268,7 +254,7 @@ onMounted(async () => {
填写本周周记
</button>
<span class="user-chip num">{{ session?.username }}</span>
<button class="btn btn-sm" @click="doLogout(false)">退出</button>
<button class="btn btn-sm" @click="doLogout">退出</button>
<button class="btn btn-primary btn-sm" :disabled="clockDone" @click="doClock">
<Icon :name="clockDone ? 'check-circle' : 'clock'" :size="14" />
<span class="num">{{ clockLabel }}</span>
+5 -4
View File
@@ -31,10 +31,11 @@ export interface Session {
username: string
}
// 会话存 sessionStorage:关闭标签页即退出,刷新页面保持登录
// 会话持久化到 localStorage:关闭浏览器后仍保持登录,无需每次使用都登录
// 安全边界:密码库主密码不随会话保存,每次启动仍需解锁
export function getSession(): Session | null {
try {
const raw = sessionStorage.getItem(SESSION_KEY)
const raw = localStorage.getItem(SESSION_KEY)
if (!raw) return null
const s = JSON.parse(raw)
if (s && s.userId && s.username) return s as Session
@@ -42,10 +43,10 @@ export function getSession(): Session | null {
return null
}
function setSession(s: Session): void {
sessionStorage.setItem(SESSION_KEY, JSON.stringify(s))
localStorage.setItem(SESSION_KEY, JSON.stringify(s))
}
function clearSession(): void {
sessionStorage.removeItem(SESSION_KEY)
localStorage.removeItem(SESSION_KEY)
}
export function openUserDatabase(userId: string): void {
+1 -1
View File
@@ -347,7 +347,7 @@ async function doImport() {
<div class="ai-grid">
<div class="rule-item">
<label>同步服务地址</label>
<input class="input" v-model="syncBase" placeholder="如 http://124.221.192.176:3780" />
<input class="input" v-model="syncBase" placeholder="如 https://sync.linyux.cn 或 https://gitea.linyux.cn/sync-api" />
</div>
<div class="rule-item">
<label>云端用户名</label>
+12
View File
@@ -0,0 +1,12 @@
# 方式一:独立子域名(DNS 添加 sync.linyux.cn A 记录后使用)
sync.linyux.cn {
reverse_proxy 127.0.0.1:3780
}
# 方式二:复用现有域名路径(并入 gitea.linyux.cn 的站点块,不要单独建站)
# gitea.linyux.cn {
# handle_path /sync-api/* {
# reverse_proxy 127.0.0.1:3780
# }
# # ...原有 Gitea 反代配置
# }
+41 -11
View File
@@ -1,6 +1,6 @@
# 同步服务端部署指南
# 同步服务端部署指南(Docker + Caddy 自动 HTTPS)
## 部署(在 124.221.192.176 上执行)
## 一、部署同步服务
1. 上传 server 目录到服务器(如 ~/internlog-sync/)
2. 启动:
@@ -10,21 +10,51 @@
3. 验证:curl http://127.0.0.1:3780/api/health 应返回 {"ok":true}
数据保存在 ./data/(用户注册表 + 每用户数据文件),直接打包该目录即备份。
数据保存在 ./data/(用户注册表 + 每用户数据文件),整目录复制即备份。
## 建议:启用 HTTPS
## 二、Caddy 反向代理(自动申请与续期 HTTPS 证书)
客户端在手机浏览器使用时,建议用 nginx 反向代理复用现有证书:
### 方式一:独立子域名(推荐)
location /sync-api/ {
proxy_pass http://127.0.0.1:3780/;
proxy_set_header Host $host;
先在 DNS 添加 A 记录:sync.linyux.cn → 124.221.192.176
Caddyfile:
sync.linyux.cn {
reverse_proxy 127.0.0.1:3780
}
客户端同步地址填 https://gitea.linyux.cn/sync-api 即可全程加密。
不加代理时客户端可临时填 http://124.221.192.176:3780(明文,仅建议内网或过渡期使用)。
客户端同步地址填:https://sync.linyux.cn
## 接口
### 方式二:复用现有域名路径(不新增 DNS 记录)
在 gitea.linyux.cn 现有 Caddy 站点块中加入 handle_path(原有 Gitea 反代配置保持不变):
gitea.linyux.cn {
handle_path /sync-api/* {
reverse_proxy 127.0.0.1:3780
}
# ...原有 Gitea 配置
}
客户端同步地址填:https://gitea.linyux.cn/sync-api
### 启动 Caddy
- 宿主机已运行 Caddy:修改 Caddyfile 后 caddy reload 即可(参考 server/Caddyfile.example)
- 未运行 Caddy:docker compose 里已附注释掉的 caddy 服务段,取消注释后 docker compose up -d
注意:证书自动申请要求 80/443 端口公网可达,且域名已解析到本服务器。
## 三、客户端配置
应用 → 设置 → 多端数据同步:
1. 同步服务地址:https://sync.linyux.cn(或方式二的 https://gitea.linyux.cn/sync-api)
2. 注册云端账号(或填写已注册的账号密码)
3. 立即同步;此后登录状态下每 5 分钟自动同步
## 四、接口
- POST /api/auth/register {username, password}
- POST /api/auth/login {username, password}
+15
View File
@@ -7,3 +7,18 @@ services:
volumes:
- ./data:/app/data
restart: unless-stopped
# 可选:Caddy 自动 HTTPS。若宿主机已有 Caddy/nginx 占用 80/443,请改用
# 现有反代添加站点块(见 DEPLOY.md),不要启用本段。
#
# caddy:
# image: caddy:2-alpine
# container_name: internlog-caddy
# ports:
# - "80:80"
# - "443:443"
# volumes:
# - ./Caddyfile:/etc/caddy/Caddyfile:ro
# - ./caddy_data:/data
# - ./caddy_config:/config
# restart: unless-stopped
+1
View File
@@ -531,3 +531,4 @@ src/
- v1.11:新增记账系统——支出/收入录入(金额以分存储)、固定分类枚举、报销跟踪(待报销/已报销与待报销金额汇总)、月度汇总卡片与支出分类分布、月度流水筛选与弹窗编辑;备份格式升级至 v3 并向下兼容
- v1.12:「今日」视图升级为「详情」——支持前后翻页、日期选择器自由切换日期,对任意一天进行查看、打卡、记录与修改
- v1.13:多端同步与安卓应用——自建零依赖同步服务端(Docker 部署、按用户 JSON 隔离、HMAC token);客户端同步引擎(uuid 与 updated_at 补齐、镜像哈希差异、墓碑传播、记录级新者胜);设置页同步配置与自动同步;Capacitor 安卓工程脚手架与移动端 UI 适配(安全区、输入字号)
- v1.13.1:登录会话持久化(localStorage,关闭浏览器后免登录,无需每次使用都登录);部署方案调整为 Docker + Caddy 自动 HTTPS(独立子域名与现有域名路径两种反代方式);移除 30 分钟无操作自动退出(密码库仍保留 5 分钟自动锁定与主密码门槛)