chore(release): 冻结 v1.1.0 版本
- 同步版本号:VERSION / backend pom / admin-web / miniapp 均升至 1.1.0 - 合并本轮代码审查修复(详见 docs/CODE-REVIEW-2026-09-24.md): - 后端:微信登录真实实现 RealWechatLoginProvider、实名核验真实实现 RealIdentityVerificationProvider(本地强校验 + 可配置第三方 + fail-closed/fail-fast) - 照片直传落库端点 POST /me/photos/confirm(fileKey 归属校验 + 对象存在性校验后 savePhoto) - 刷新 Token Redis TTL 修正(getExpirationMs()*2 的 4h → refreshExpirationMs 的 14 天) - 管理端 token 改为 HttpOnly Cookie + silent-refresh,移除 localStorage 明文存储与 30+ 处手工注入 - 小程序:红娘接单鉴权头错位修复、serviceType 中文映射、生产域名可配置 - 隔离本地产物(.workbuddy/、*.bundle、*.dump、secrets、application-dev.yml 等已被 .gitignore 覆盖) 未验证项(打标签 ≠ 生产发布): - 后端编译 / 单测未在本环境执行(Maven 慢、Docker DNS 受限) - 管理端 登录→刷新→登出 端到端、小程序真机走查待人工验收 - 生产部署需注入 WECHAT_APP_ID / WECHAT_APP_SECRET、VERIFICATION_API_URL / VERIFICATION_API_KEY 与小程序生产域名
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
import { defineStore } from 'pinia'
|
||||
import { ref, computed } from 'vue'
|
||||
import { post } from '@/api/client'
|
||||
import { setAccessToken, clearAccessToken } from '@/utils/token'
|
||||
|
||||
interface OperatorInfo {
|
||||
operatorId: string
|
||||
@@ -23,38 +24,68 @@ export const useAuthStore = defineStore('auth', () => {
|
||||
const previewOperator: OperatorInfo | null = previewRolePermissions[previewRole]
|
||||
? { operatorId: 'ui-preview', name: '界面验收员', username: 'preview', permissions: previewRolePermissions[previewRole], organizationId: null }
|
||||
: null
|
||||
const token = ref<string>(previewOperator ? 'ui-preview-only' : (localStorage.getItem('accessToken') || ''))
|
||||
const operator = ref<OperatorInfo | null>(
|
||||
previewOperator || JSON.parse(localStorage.getItem('operator') || 'null')
|
||||
)
|
||||
|
||||
const isLoggedIn = computed(() => !!token.value)
|
||||
const token = ref<string>(previewOperator ? 'ui-preview-only' : '')
|
||||
const operator = ref<OperatorInfo | null>(previewOperator)
|
||||
let sessionInitialized = false
|
||||
|
||||
const isLoggedIn = computed(() => !!token.value && !!operator.value)
|
||||
const permissions = computed(() => operator.value?.permissions || [])
|
||||
|
||||
function applyAuthData(data: any) {
|
||||
token.value = data.accessToken || ''
|
||||
operator.value = {
|
||||
operatorId: data.operatorId,
|
||||
name: data.name,
|
||||
username: data.username,
|
||||
permissions: data.permissions || [],
|
||||
organizationId: data.organizationId ?? null,
|
||||
}
|
||||
// 同步内存态令牌(供 axios 拦截器注入 Authorization 头;生产同源场景 Cookie 也会自动携带)
|
||||
setAccessToken(token.value)
|
||||
}
|
||||
|
||||
async function login(username: string, password: string) {
|
||||
const res: any = await post('/auth/operator/login', { username, password })
|
||||
if (res.success) {
|
||||
token.value = res.data.accessToken
|
||||
operator.value = {
|
||||
operatorId: res.data.operatorId,
|
||||
name: res.data.name,
|
||||
username: res.data.username,
|
||||
permissions: res.data.permissions || [],
|
||||
organizationId: res.data.organizationId ?? null,
|
||||
}
|
||||
localStorage.setItem('accessToken', res.data.accessToken)
|
||||
localStorage.setItem('operator', JSON.stringify(operator.value))
|
||||
applyAuthData(res.data)
|
||||
return res.data
|
||||
}
|
||||
throw new Error(res.message || '登录失败')
|
||||
}
|
||||
|
||||
function logout() {
|
||||
token.value = ''
|
||||
operator.value = null
|
||||
localStorage.removeItem('accessToken')
|
||||
localStorage.removeItem('operator')
|
||||
/**
|
||||
* 静默恢复会话:页面刷新后内存态清空,凭 HttpOnly refresh Cookie(dy_op_rt)刷新令牌,
|
||||
* 无需用户重新登录。refresh token 不落地、不可被 JS 读取,抗 XSS。
|
||||
* 开发跨端口代理下 Cookie 不共享,刷新将失败并回落到登录页(符合预期)。
|
||||
*/
|
||||
async function initializeSession(): Promise<boolean> {
|
||||
if (sessionInitialized) return isLoggedIn.value
|
||||
sessionInitialized = true
|
||||
if (token.value) return true
|
||||
try {
|
||||
const res: any = await post('/auth/operator/refresh', {})
|
||||
if (res.success) {
|
||||
applyAuthData(res.data)
|
||||
return true
|
||||
}
|
||||
} catch {
|
||||
// 未登录或 refresh 失效,交由路由守卫跳转登录页
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
return { token, operator, isLoggedIn, permissions, login, logout }
|
||||
function logout() {
|
||||
// 尽力通知后端注销并清除 Cookie(best-effort)
|
||||
try {
|
||||
post('/auth/operator/logout', {}).catch(() => {})
|
||||
} catch {
|
||||
// ignore
|
||||
}
|
||||
token.value = ''
|
||||
operator.value = null
|
||||
clearAccessToken()
|
||||
}
|
||||
|
||||
return { token, operator, isLoggedIn, permissions, login, logout, initializeSession }
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user