feat(auth): 统一身份 - 增加可选IAM快捷登录并保留原业务权限
This commit is contained in:
@@ -11,14 +11,22 @@
|
||||
<div class="text-center text-3xl font-medium mb-8">{{ config.web_name }}</div>
|
||||
|
||||
<!-- 企业微信自动授权中 -->
|
||||
<div v-if="wxWorkAutoLogin" class="text-center py-10">
|
||||
<div v-if="wxWorkAutoLogin || iamLoading" class="text-center py-10">
|
||||
<el-icon class="is-loading mb-4" :size="40" color="var(--el-color-primary)">
|
||||
<Loading />
|
||||
</el-icon>
|
||||
<div class="text-gray-500">企业微信授权登录中...</div>
|
||||
<div class="text-gray-500">{{ iamLoading ? '统一账号登录中...' : '企业微信授权登录中...' }}</div>
|
||||
</div>
|
||||
|
||||
<template v-else>
|
||||
<el-button
|
||||
v-if="iamEnabled"
|
||||
class="mb-6"
|
||||
size="large"
|
||||
@click="handleIamLogin"
|
||||
>
|
||||
统一账号快捷登录
|
||||
</el-button>
|
||||
<!-- 登录方式切换标签 -->
|
||||
<div v-if="wxWorkEnabled" class="flex justify-center mb-6">
|
||||
<el-radio-group v-model="loginMode" size="large">
|
||||
@@ -99,7 +107,7 @@ import LayoutFooter from '@/layout/components/footer.vue'
|
||||
import useAppStore from '@/stores/modules/app'
|
||||
import useUserStore from '@/stores/modules/user'
|
||||
import cache from '@/utils/cache'
|
||||
import { getWorkWechatConfig } from '@/api/user'
|
||||
import { getIamConfig, getWorkWechatConfig } from '@/api/user'
|
||||
|
||||
const passwordRef = shallowRef<InputInstance>()
|
||||
const formRef = shallowRef<FormInstance>()
|
||||
@@ -118,6 +126,66 @@ const rules = {
|
||||
password: [{ required: true, message: '请输入密码', trigger: ['blur'] }]
|
||||
}
|
||||
|
||||
// 统一账号登录是可选入口,不取代账号密码或企业微信登录。
|
||||
const iamEnabled = ref(false)
|
||||
const iamLoginUrl = ref('')
|
||||
const iamLoading = ref(false)
|
||||
let iamCallbackHandled = false
|
||||
|
||||
const loadIamConfig = async () => {
|
||||
try {
|
||||
const result = await getIamConfig()
|
||||
const url = new URL(result?.loginUrl || '', window.location.origin)
|
||||
if (result?.enabled === true && url.protocol === 'https:') {
|
||||
iamLoginUrl.value = url.href
|
||||
iamEnabled.value = true
|
||||
}
|
||||
} catch {
|
||||
// IAM 不可用时,原有登录入口保持可用。
|
||||
}
|
||||
}
|
||||
|
||||
const handleIamLogin = () => {
|
||||
if (iamEnabled.value && iamLoginUrl.value) {
|
||||
window.location.assign(iamLoginUrl.value)
|
||||
}
|
||||
}
|
||||
|
||||
const handleIamCallback = async (ticket: string | null, error: string | null) => {
|
||||
if (iamCallbackHandled) return
|
||||
iamCallbackHandled = true
|
||||
// 在任何 await 和兑换前移除票据,刷新不会重复兑换;保留其他 query/hash。
|
||||
const cleanUrl = new URL(window.location.href)
|
||||
cleanUrl.searchParams.delete('iam_ticket')
|
||||
cleanUrl.searchParams.delete('iam_error')
|
||||
// 同一回调不得随后被识别为企业微信授权。
|
||||
cleanUrl.searchParams.delete('code')
|
||||
cleanUrl.searchParams.delete('state')
|
||||
window.history.replaceState(window.history.state, '', cleanUrl.pathname + cleanUrl.search + cleanUrl.hash)
|
||||
if (error || !ticket) {
|
||||
ElMessage.error(error || '统一账号登录凭证无效,请重新登录')
|
||||
return
|
||||
}
|
||||
iamLoading.value = true
|
||||
try {
|
||||
const result = await userStore.iamLogin(ticket)
|
||||
if (result.is_paw === 0) {
|
||||
await router.push('/change-password')
|
||||
return
|
||||
}
|
||||
if (result.need_bind_work_wechat) {
|
||||
await router.push('/bind-work-wechat')
|
||||
return
|
||||
}
|
||||
redirectAfterLogin()
|
||||
} catch (error: any) {
|
||||
ElMessage.error(error?.msg || error?.message || '统一账号登录失败,请重新登录或使用账号密码')
|
||||
loginMode.value = 'account'
|
||||
} finally {
|
||||
iamLoading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
// 企业微信相关
|
||||
const loginMode = ref<'account' | 'wxwork'>('account')
|
||||
const wxWorkEnabled = ref(false)
|
||||
@@ -243,7 +311,12 @@ onMounted(async () => {
|
||||
|
||||
// 检查 URL 中是否有企业微信回调 code
|
||||
const urlParams = new URLSearchParams(window.location.search)
|
||||
const wxCode = urlParams.get('code')
|
||||
void loadIamConfig()
|
||||
const hasIamCallback = urlParams.has('iam_ticket') || urlParams.has('iam_error')
|
||||
if (hasIamCallback) {
|
||||
await handleIamCallback(urlParams.get('iam_ticket'), urlParams.get('iam_error'))
|
||||
}
|
||||
const wxCode = hasIamCallback ? null : urlParams.get('code')
|
||||
const wxState = urlParams.get('state')
|
||||
|
||||
if (wxCode && wxState === 'admin_login') {
|
||||
@@ -263,7 +336,7 @@ onMounted(async () => {
|
||||
wxWorkConfig.value = { corp_id: res.corp_id, agent_id: res.agent_id }
|
||||
|
||||
// 在企业微信内:自动跳转 OAuth 授权
|
||||
if (isInWxWork()) {
|
||||
if (isInWxWork() && !hasIamCallback) {
|
||||
const redirectUri = encodeURIComponent(getRedirectUri())
|
||||
const authUrl =
|
||||
`https://open.weixin.qq.com/connect/oauth2/authorize` +
|
||||
|
||||
Reference in New Issue
Block a user