提交
This commit is contained in:
1 parent
66a7fd7068
commit
df640dffad
2 files changed
+324
-10
No files matched your search
+137
-10
@@ -52,16 +52,19 @@
|
||||
</el-button>
|
||||
</el-form-item> -->
|
||||
<el-form-item style="width: 100%">
|
||||
<el-button
|
||||
:loading="loading"
|
||||
size="large"
|
||||
style="width: 100%; background-color: rgb(var(--art-primary)) !important"
|
||||
class="login-button"
|
||||
@click.prevent="handleLogin"
|
||||
>
|
||||
<span v-if="!loading">{{ proxy.$t('login.login') }}</span>
|
||||
<span v-else>{{ proxy.$t('login.logging') }}</span>
|
||||
</el-button>
|
||||
<div class="login-actions">
|
||||
<el-button :loading="loading" size="large" class="login-button primary" @click.prevent="handleLogin">
|
||||
<span v-if="!loading">{{ proxy.$t('login.login') }}</span>
|
||||
<span v-else>{{ proxy.$t('login.logging') }}</span>
|
||||
</el-button>
|
||||
|
||||
<!-- 统一认证登录按钮(已注释,方便恢复)
|
||||
<el-button size="large" class="login-button cas-login" type="primary" @click.prevent="handleUnifiedLogin">
|
||||
统一认证登录
|
||||
</el-button>
|
||||
-->
|
||||
</div>
|
||||
|
||||
<div v-if="register" style="float: right">
|
||||
<router-link class="link-type" :to="'/register'">{{ proxy.$t('login.switchRegisterPage') }}</router-link>
|
||||
</div>
|
||||
@@ -82,6 +85,7 @@ import { LoginData, TenantVO } from '@/api/types';
|
||||
import { to } from 'await-to-js';
|
||||
import { HttpStatus } from '@/enums/RespEnum';
|
||||
import { useI18n } from 'vue-i18n';
|
||||
import { setToken } from '@/utils/auth';
|
||||
|
||||
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
|
||||
|
||||
@@ -233,12 +237,109 @@ const doSocialLogin = (type: string) => {
|
||||
});
|
||||
};
|
||||
|
||||
// ======= 统一认证(CAS)相关 =======
|
||||
// 固定的 CAS 地址与生产前端地址(按需求写死)
|
||||
const CAS_BASE = 'http://172.16.0.82';
|
||||
const CAS_CLIENT_ID = '0i7tcT5tULqvmmbbV8';
|
||||
const CAS_CLIENT_SECRET = '68c4f7641523452aaf5ef6d0432869f7';
|
||||
const FRONTEND_REDIRECT_URI_ENCODED = encodeURIComponent('http://172.16.0.67:8882');
|
||||
|
||||
/**
|
||||
* 点击“统一认证登录”按钮,直接跳转到 CAS 授权页面
|
||||
*/
|
||||
const handleUnifiedLogin = () => {
|
||||
const authorizeUrl = `${CAS_BASE}/cas/oauth2.0/authorize?response_type=code&client_id=${CAS_CLIENT_ID}&redirect_uri=${FRONTEND_REDIRECT_URI_ENCODED}`;
|
||||
window.location.href = authorizeUrl;
|
||||
};
|
||||
|
||||
/**
|
||||
* 从当前路由或 redirect 字段中提取 code 参数
|
||||
*/
|
||||
const extractCodeFromRoute = (route: any): string | null => {
|
||||
// 1) 直接从 query.code 获取
|
||||
if (route && route.query && route.query.code) {
|
||||
return String(route.query.code);
|
||||
}
|
||||
|
||||
// 2) redirect 参数里可能包含 ?code=...,例如 redirect=/index?code=ST-...
|
||||
const redirectParam = route && route.query && route.query.redirect ? String(route.query.redirect) : null;
|
||||
if (redirectParam) {
|
||||
const m = redirectParam.match(/[?&]code=([^&]+)/);
|
||||
if (m && m[1]) return decodeURIComponent(m[1]);
|
||||
}
|
||||
|
||||
// 3) 尝试从 fullPath 中找
|
||||
if (route && route.fullPath) {
|
||||
const m2 = String(route.fullPath).match(/[?&]code=([^&]+)/);
|
||||
if (m2 && m2[1]) return decodeURIComponent(m2[1]);
|
||||
}
|
||||
|
||||
return null;
|
||||
};
|
||||
|
||||
/**
|
||||
* 使用 code 去请求 accessToken,并打印返回信息
|
||||
*/
|
||||
const fetchAccessToken = async (code: string) => {
|
||||
try {
|
||||
// 由于直接请求 CAS 会触发 CORS,改为请求后端接口,由后端向 CAS 请求 accessToken
|
||||
// 后端接口示例:GET ${VITE_APP_BASE_API}/cas/accessToken?code=...
|
||||
const backendUrl = `${import.meta.env.VITE_APP_BASE_API}/cas/accessToken?code=${encodeURIComponent(code)}`;
|
||||
|
||||
const res = await fetch(backendUrl, {
|
||||
method: 'GET'
|
||||
});
|
||||
|
||||
// 读取后端返回(期望后端返回 JSON 或文本)
|
||||
const contentType = res.headers.get('content-type') || '';
|
||||
let body: any;
|
||||
if (contentType.includes('application/json')) {
|
||||
body = await res.json();
|
||||
} else {
|
||||
const txt = await res.text();
|
||||
try {
|
||||
body = JSON.parse(txt);
|
||||
} catch {
|
||||
body = txt;
|
||||
}
|
||||
}
|
||||
console.log('[Backend -> CAS accessToken response]', { status: res.status, ok: res.ok, body });
|
||||
|
||||
// 如果后端返回了登录令牌,前端直接用它完成登录后的行为(存 token & 跳转)
|
||||
// 兼容多种返回结构:{ data: { access_token: '...' } } 或 { access_token: '...' } 或 raw LoginVo
|
||||
const tokenCandidate =
|
||||
(body && body.data && body.data.access_token) ||
|
||||
(body && body.access_token) ||
|
||||
(body && body.data && body.data.accessToken) ||
|
||||
(body && body.accessToken);
|
||||
|
||||
if (tokenCandidate) {
|
||||
const tokenStr = String(tokenCandidate);
|
||||
// 持久化 token,更新 store,并跳转到重定向或首页
|
||||
setToken(tokenStr);
|
||||
userStore.token = tokenStr;
|
||||
const redirectUrl = redirect.value || '/';
|
||||
await router.push(redirectUrl);
|
||||
return;
|
||||
}
|
||||
} catch (err) {
|
||||
console.error('fetchAccessToken error', err);
|
||||
}
|
||||
};
|
||||
|
||||
onMounted(() => {
|
||||
initTenantList();
|
||||
getLoginData();
|
||||
|
||||
// 开始预加载背景图片
|
||||
preloadBackgroundImage();
|
||||
|
||||
// 如果 URL 中携带 CAS 的 code,则使用该 code 请求 accessToken 并打印返回信息
|
||||
const code = extractCodeFromRoute(router.currentRoute.value);
|
||||
if (code) {
|
||||
// 发起请求(异步,不阻塞页面加载)
|
||||
fetchAccessToken(code);
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
@@ -419,4 +520,30 @@ onMounted(() => {
|
||||
.login-button {
|
||||
color: #ffffff;
|
||||
}
|
||||
|
||||
.login-actions {
|
||||
display: flex;
|
||||
gap: 12px;
|
||||
/* 让容器占满可用宽度,保证子按钮能拉伸 */
|
||||
width: 100%;
|
||||
justify-content: stretch;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
/* 单按钮占满整个宽度 */
|
||||
.login-actions .login-button {
|
||||
flex: 1 1 0%;
|
||||
min-width: 0; /* 允许缩小以配合 flex */
|
||||
display: block;
|
||||
width: 100%;
|
||||
background-color: rgb(var(--art-primary)) !important;
|
||||
border-color: transparent !important;
|
||||
color: #ffffff;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.login-button.cas-login {
|
||||
/* 可个性化保留此类;目前与主按钮外观一致 */
|
||||
color: #ffffff !important;
|
||||
}
|
||||
</style>
|
||||
Reference in new issue
Block a user