mirror of
https://github.com/fawney19/Aether.git
synced 2026-09-02 01:10:23 +08:00
feat(auth): 重构认证系统,引入 session 会话管理
- 新增 user_sessions 数据库表及 Alembic 迁移 - 实现 SessionService 会话生命周期管理(创建/刷新/撤销/清理) - 认证流程改用 refresh token cookie + access token 双令牌模式 - 前端实现自动静默刷新、跨标签页同步及设备指纹 - 用户设置页新增会话管理和密码修改功能 - 管理员用户管理新增强制登出和会话查看 - 密码策略增强,支持强度校验和泄露检测 - OAuth 登录流程适配新会话机制 - 新增完整的单元测试和 API 测试覆盖 Closes #232 Co-authored-by: LewisPen <LewisPen@nyadoo.com>
This commit is contained in:
@@ -6,7 +6,6 @@
|
||||
<input
|
||||
ref="inputRef"
|
||||
:class="inputClass"
|
||||
:style="inputStyle"
|
||||
:value="modelValue"
|
||||
:type="effectiveType"
|
||||
:autocomplete="autocompleteAttr"
|
||||
@@ -42,7 +41,6 @@
|
||||
v-else
|
||||
ref="inputRef"
|
||||
:class="inputClass"
|
||||
:style="inputStyle"
|
||||
:value="modelValue"
|
||||
:type="effectiveType"
|
||||
:autocomplete="autocompleteAttr"
|
||||
@@ -69,24 +67,6 @@ const emit = defineEmits<{
|
||||
'update:modelValue': [value: string]
|
||||
}>()
|
||||
|
||||
// 开发环境警告:type="password" 已被弃用
|
||||
const warnPasswordType = import.meta.env.DEV
|
||||
? (() => {
|
||||
let warned = false
|
||||
return () => {
|
||||
if (!warned) {
|
||||
warned = true
|
||||
// eslint-disable-next-line no-console
|
||||
console.warn(
|
||||
'[Input] type="password" 已被弃用,请使用 masked 属性代替。\n' +
|
||||
'示例:<Input v-model="apiKey" masked />\n' +
|
||||
'masked 属性使用 CSS 遮蔽而非 password 类型,不会触发浏览器密码管理器。'
|
||||
)
|
||||
}
|
||||
}
|
||||
})()
|
||||
: () => {}
|
||||
|
||||
interface Props {
|
||||
modelValue?: string | number
|
||||
class?: string
|
||||
@@ -99,9 +79,8 @@ interface Props {
|
||||
size?: 'default' | 'sm'
|
||||
/**
|
||||
* 遮蔽显示内容(用于 API Key 等敏感信息)
|
||||
* 使用 CSS -webkit-text-security 实现,不会触发浏览器密码管理器
|
||||
* 隐藏态使用真正的 password 输入框,显示态切换为 text
|
||||
* 同时会显示一个小眼睛按钮用于切换显示/隐藏
|
||||
* 注意:Firefox 不支持 -webkit-text-security,会显示明文(但仍可通过按钮切换)
|
||||
*/
|
||||
masked?: boolean
|
||||
/**
|
||||
@@ -134,13 +113,10 @@ const shouldDisableAutofill = computed(() => {
|
||||
return props.disableAutofill ?? false
|
||||
})
|
||||
|
||||
// 始终使用 text 类型,永远不用 password
|
||||
const effectiveType = computed(() => {
|
||||
const attrType = attrs.type as string | undefined
|
||||
// 如果传入 password,强制转为 text(配合 masked 使用)
|
||||
if (attrType === 'password') {
|
||||
warnPasswordType()
|
||||
return 'text'
|
||||
const attrType = (attrs.type as string | undefined) ?? 'text'
|
||||
if (props.masked) {
|
||||
return isVisible.value ? 'text' : 'password'
|
||||
}
|
||||
return attrType
|
||||
})
|
||||
@@ -182,16 +158,6 @@ const inputClass = computed(() =>
|
||||
)
|
||||
)
|
||||
|
||||
// 当 masked 为 true 且未显示时,用 CSS 遮蔽文字
|
||||
const inputStyle = computed(() => {
|
||||
if (props.masked && !isVisible.value) {
|
||||
// 使用 -webkit-text-security(Chrome, Safari, Edge 支持)
|
||||
// Firefox 不支持此属性,会显示明文,但仍可通过小眼睛按钮切换
|
||||
return { '-webkit-text-security': 'disc' }
|
||||
}
|
||||
return undefined
|
||||
})
|
||||
|
||||
function handleInput(event: Event) {
|
||||
const target = event.target as HTMLInputElement
|
||||
emit('update:modelValue', target.value)
|
||||
|
||||
Reference in New Issue
Block a user