fix: 修复单点登录正确获取用户信息

This commit is contained in:
xieyonghong 2023-04-03 19:46:16 +08:00
parent 0cbbd52a1e
commit 6c9524ab9f
4 changed files with 345 additions and 306 deletions

View File

@ -13,7 +13,7 @@ interface AxiosResponseRewrite<T = any[]> extends AxiosResponse<T, any> {
export const SUCCESS_CODE = 200 // 成功代码 export const SUCCESS_CODE = 200 // 成功代码
const filterApiUrl = ['/system/version', '/system/config/front', '/authorize/captcha/config', '/application/sso/_all', '/authorize/captcha/image'] const filterApiUrl = ['/system/version', '/system/config/front', '/authorize/captcha/config', '/application/sso/_all', '/authorize/captcha/image', '/application/sso/bind-code', '/authorize/login']
export const request = axios.create({ export const request = axios.create({
withCredentials: false, withCredentials: false,

View File

@ -1,378 +1,417 @@
<!-- 第三方账户绑定 --> <!-- 第三方账户绑定 -->
<template> <template>
<div class="page-container"> <div class='page-container'>
<div class="content"> <div class='content'>
<div class="title">第三方账户绑定</div> <div class='title'>第三方账户绑定</div>
<!-- 已登录-绑定三方账号 --> <!-- 已登录-绑定三方账号 -->
<template v-if="!!token"> <template v-if='!!token'>
<div class="info"> <div class='info'>
<j-card style="width: 280px"> <j-card style='width: 280px'>
<template #title> <template #title>
<div class="info-head"> <div class='info-head'>
<img :src="getImage('/bind/Rectangle.png')" /> <img :src="getImage('/bind/Rectangle.png')" />
<span>个人信息</span> <span>个人信息</span>
</div> </div>
</template> </template>
<div class="info-body"> <div class='info-body'>
<img <img
:src=" :src="
user?.avatar || user?.avatar ||
getImage('/bind/jetlinksLogo.png') getImage('/bind/jetlinksLogo.png')
" "
/> />
<p>账号{{ user?.username }}</p> <p>账号{{ user?.username }}</p>
<p>用户名{{ user?.name }}</p> <p>用户名{{ user?.name }}</p>
</div> </div>
</j-card> </j-card>
<img :src="getImage('/bind/Vector.png')" /> <img :src="getImage('/bind/Vector.png')" />
<j-card style="width: 280px"> <j-card style='width: 280px'>
<template #title> <template #title>
<div class="info-head"> <div class='info-head'>
<img :src="getImage('/bind/Rectangle.png')" /> <img :src="getImage('/bind/Rectangle.png')" />
<span>三方账户信息</span> <span>三方账户信息</span>
</div> </div>
</template> </template>
<div class="info-body"> <div class='info-body'>
<img <img
:src=" :src="
iconMap.get( iconMap.get(
bindUser?.applicationProvider, bindUser?.applicationProvider,
) || getImage('/apply/provider1.png') ) || getImage('/apply/provider1.png')
" "
/> />
<p>账号{{ bindUser?.result?.username || '-' }}</p> <p>账号{{ bindUser?.result?.userId || '-' }}</p>
<p>用户名{{ bindUser?.result?.name || '-' }}</p> <p>用户名{{ bindUser?.result?.name || '-' }}</p>
</div> </div>
</j-card> </j-card>
</div>
<div class="btn">
<j-button type="primary" @click="handleBind"
>立即绑定</j-button
>
</div>
</template>
<!-- 未登录-绑定三方账号 -->
<template v-else>
<div class="not-login">
<div class="logo">
<img :src="getImage('/bind/jetlinksLogo.png')" />
<img
class="arrow"
:src="getImage('/bind/Vector.png')"
/>
<img
:src="iconMap.get(bindUser?.applicationProvider)"
/>
</div>
<div class="desc">
你已通过
{{
bindUser?.type === 'dingtalk-ent-app'
? '钉钉'
: '微信'
}}
授权,完善以下登录信息即可以完成绑定
</div>
<div class="login-form">
<j-form layout="vertical">
<j-form-item
label="账户"
v-bind="validateInfos.username"
>
<j-input
v-model:value="formData.username"
placeholder="请输入账户"
/>
</j-form-item>
<j-form-item
label="密码"
v-bind="validateInfos.password"
>
<j-input-password
v-model:value="formData.password"
placeholder="请输入密码"
/>
</j-form-item>
<j-form-item
label="验证码"
v-bind="validateInfos.verifyCode"
>
<j-input
v-model:value="formData.verifyCode"
placeholder="请输入验证码"
>
<template #addonAfter>
<img
:src="captcha.base64"
@click="getCode"
style="cursor: pointer"
/>
</template>
</j-input>
</j-form-item>
<j-form-item>
<j-button
type="primary"
@click="handleLoginBind"
style="width: 100%"
>
登录并绑定账户
</j-button>
</j-form-item>
</j-form>
</div>
</div>
</template>
</div> </div>
<div class='btn'>
<j-button type='primary' @click='handleBind'
>立即绑定
</j-button
>
</div>
</template>
<!-- 未登录-绑定三方账号 -->
<template v-else>
<div class='not-login'>
<div class='logo'>
<img :src="getImage('/bind/jetlinksLogo.png')" />
<img
class='arrow'
:src="getImage('/bind/Vector.png')"
/>
<img
:src='iconMap.get(bindUser?.applicationProvider)'
/>
</div>
<div class='desc'>
你已通过
{{ bindUser?.appName }}
授权,完善以下登录信息即可以完成绑定
</div>
<div class='login-form'>
<j-form layout='vertical'>
<j-form-item
label='账户'
v-bind='validateInfos.username'
>
<j-input
v-model:value='formData.username'
placeholder='请输入账户'
/>
</j-form-item>
<j-form-item
label='密码'
v-bind='validateInfos.password'
>
<j-input-password
v-model:value='formData.password'
placeholder='请输入密码'
/>
</j-form-item>
<template v-if='captcha.base64'>
<j-form-item
label='验证码'
v-bind='validateInfos.verifyCode'
:rules="[
{
required: true,
message: '请输入验证码',
},
]"
>
<j-input
v-model:value='formData.verifyCode'
placeholder='请输入验证码'
>
<template #addonAfter>
<img
:src='captcha.base64'
@click='getCode'
style='cursor: pointer'
/>
</template>
</j-input>
</j-form-item>
</template>
<j-form-item>
<j-button
type='primary'
@click='handleLoginBind'
style='width: 100%'
>
登录并绑定账户
</j-button>
</j-form-item>
</j-form>
</div>
</div>
</template>
</div> </div>
</div>
</template> </template>
<script setup lang="ts"> <script setup lang='ts' name='AccountBind'>
import { getImage, LocalStore } from '@/utils/comm'; import { getImage, LocalStore } from '@/utils/comm'
import { TOKEN_KEY } from '@/utils/variable'; import { TOKEN_KEY } from '@/utils/variable'
import { Form } from 'ant-design-vue'; import { Form } from 'ant-design-vue'
import { message } from 'ant-design-vue'; import { message } from 'ant-design-vue'
import { applicationInfo, bindAccount } from '@/api/bind'; import { applicationInfo, bindAccount } from '@/api/bind'
import { code, authLogin, userDetail } from '@/api/login'; import { code, authLogin, userDetail } from '@/api/login'
const useForm = Form.useForm; const useForm = Form.useForm
interface formData { interface formData {
username: string; username: string;
password: string; password: string;
verifyCode: string; verifyCode: string;
} }
const iconMap = new Map(); const iconMap = new Map()
iconMap.set('dingtalk-ent-app', getImage('/notice/dingtalk.png')); iconMap.set('dingtalk-ent-app', getImage('/notice/dingtalk.png'))
iconMap.set('wechat-webapp', getImage('/notice/wechat.png')); iconMap.set('wechat-webapp', getImage('/notice/wechat.png'))
iconMap.set('internal-standalone', getImage('/apply/provider1.png')); iconMap.set('internal-standalone', getImage('/apply/provider1.png'))
iconMap.set('third-party', getImage('/apply/provider5.png')); iconMap.set('third-party', getImage('/apply/provider5.png'))
const token = computed(() => LocalStore.get(TOKEN_KEY)); const token = computed(() => LocalStore.get(TOKEN_KEY))
/** /**
* 用户信息 * 用户信息
*/ */
const user = ref(); const user = ref()
const getDetail = () => { const getDetail = () => {
if (!token.value) return; if (!token.value) return
userDetail().then((res: any) => { userDetail().then((res: any) => {
user.value = res?.result; user.value = res?.result
}); })
}; }
getDetail();
/**
* 三方应用信息
*/
const bindUser = ref();
const getAppInfo = async () => {
const code = getUrlCode();
const { result } = await applicationInfo(code);
bindUser.value = result;
};
getAppInfo();
/** /**
* 获取url参数 * 获取url参数
*/ */
const getUrlCode = () => { const getUrlCode = () => {
const url = new URLSearchParams(window.location.href); const url = new URLSearchParams(window.location.href)
return url.get('code') as string; return url.get('code') as string
}; }
/**
* 三方应用信息
*/
const bindUser = ref<any>({ appName: '' })
const getAppInfo = async () => {
const code = getUrlCode()
const { result } = await applicationInfo(code)
bindUser.value = result
if (result.applicationProvider === 'dingtalk-ent-app') {
bindUser.value.appName = '钉钉'
} else if (result.applicationProvider === 'wechat-webapp') {
bindUser.value.appName = '微信'
} else {
bindUser.value.appName = result.applicationName
}
}
/** /**
* 立即绑定 * 立即绑定
*/ */
const handleBind = async () => { const handleBind = async () => {
const code = getUrlCode(); const code = getUrlCode()
const res = await bindAccount(code); const res = await bindAccount(code)
console.log('bindAccount: ', res); console.log('bindAccount: ', res)
message.success('绑定成功'); message.success('绑定成功')
goRedirect(); goRedirect()
setTimeout(() => window.close(), 1000); setTimeout(() => window.close(), 1000)
}; }
// - // -
const formData = ref<formData>({ const formData = ref<formData>({
username: '', username: '',
password: '', password: '',
verifyCode: '', verifyCode: ''
}); })
const formRules = ref({ const formRules = ref({
username: [ username: [
{ {
required: true, required: true,
message: '请输入账户', message: '请输入账户'
}, }
], ],
password: [ password: [
{ {
required: true, required: true,
message: '请输入密码', message: '请输入密码'
}, }
], ]
verifyCode: [ })
{
required: true,
message: '请输入验证码',
},
],
});
const { resetFields, validate, validateInfos } = useForm( const { resetFields, validate, validateInfos } = useForm(
formData.value, formData.value,
formRules.value, formRules.value
); )
/** /**
* 获取图形验证码 * 获取图形验证码
*/ */
const captcha = ref({ const captcha = ref({
base64: '', base64: '',
key: '', key: ''
}); })
const getCode = async () => { const getCode = async () => {
const res: any = await code(); const res: any = await code()
captcha.value = res.result; captcha.value.base64 = res.result?.base64
}; captcha.value.key = res.result?.key
getCode(); }
/** /**
* 登录并绑定账户 * 登录并绑定账户
*/ */
const handleLoginBind = () => { const handleLoginBind = () => {
validate() validate()
.then(async () => { .then(async () => {
const code = getUrlCode(); const code = getUrlCode()
const params = { const params: any = {
...formData.value, ...formData.value,
verifyKey: captcha.value.key, bindCode: code,
bindCode: code, expires: 3600000
expires: 3600000, }
};
const res = await authLogin(params); if (captcha.value.base64) {
console.log('res: ', res); params.verifyKey = captcha.value.key
message.success('登录成功'); } else {
goRedirect(); delete params.verifyCode
setTimeout(() => window.close(), 1000); }
})
.catch((err) => { const res = await authLogin(params)
getCode(); console.log('res: ', res)
}); if (res.success) {
}; message.success('登录成功')
LocalStore.set(TOKEN_KEY, res.result!.token as string)
goRedirect()
}
})
.catch((err) => {
console.log(err)
getCode()
})
}
/** /**
* 绑定成功跳转至页面url的: redirect * 绑定成功跳转至页面url的: redirect
*/ */
const goRedirect = () => { const goRedirect = () => {
const urlParams = new URLSearchParams(window.location.hash); const urlParams = new URLSearchParams(window.location.hash)
const redirectUrl = const redirectUrl =
urlParams.get('redirect') || urlParams.get('redirect') ||
window.location.href.split('redirect=')?.[1]; window.location.href.split('redirect=')?.[1]
console.log('redirectUrl: ', redirectUrl); console.log('redirectUrl: ', redirectUrl)
// //
if (redirectUrl && redirectUrl.indexOf('account/center/bind') === -1) { if (redirectUrl && redirectUrl.indexOf('account/center/bind') === -1) {
window.location.href = decodeURIComponent(redirectUrl); window.location.href = decodeURIComponent(redirectUrl)
} } else {
}; window.location.href = '/'
setTimeout(() => window.close(), 1000)
}
}
getAppInfo()
getCode()
getDetail()
</script> </script>
<style lang="less" scoped> <style lang='less' scoped>
:deep( :deep(
.ant-form-item-label .ant-form-item-label
> label.ant-form-item-required:not( > label.ant-form-item-required:not(
.ant-form-item-required-mark-optional .ant-form-item-required-mark-optional
)::before )::before
) { ) {
display: none; display: none;
} }
:deep(.ant-form-item-label > label) { :deep(.ant-form-item-label > label) {
font-weight: bold; font-weight: bold;
} }
.page-container { .page-container {
width: 100%; width: 100%;
height: 100vh; height: 100vh;
background: url(/images/bind/bindPage.png) 0% 0% / 100% 100% no-repeat; background: url(/images/bind/bindPage.png) 0% 0% / 100% 100% no-repeat;
display: flex; display: flex;
align-items: center; align-items: center;
justify-content: center; justify-content: center;
.content {
box-sizing: border-box; .content {
width: 850px; box-sizing: border-box;
min-height: 510px; width: 850px;
background: #fff; min-height: 510px;
border: 1px solid #e0e4e8; background: #fff;
border-radius: 2px; border: 1px solid #e0e4e8;
.title { border-radius: 2px;
margin: 30px 0;
color: #0f1222; .title {
font-weight: 400; margin: 30px 0;
font-size: 20px; color: #0f1222;
font-family: 'PingFang SC'; font-weight: 400;
font-style: normal; font-size: 20px;
line-height: 25px; font-family: 'PingFang SC';
text-align: center; font-style: normal;
line-height: 25px;
text-align: center;
}
// -
.info {
display: flex;
align-items: center;
justify-content: center;
gap: 20px;
&-head {
display: flex;
align-items: baseline;
gap: 10px;
}
&-body {
display: flex;
flex-direction: column;
align-items: center;
gap: 10px;
img {
width: 70px;
height: 70px;
} }
// - }
.info { }
display: flex;
align-items: center; .btn {
justify-content: center; display: flex;
gap: 20px; justify-content: center;
&-head { margin-top: 30px;
display: flex; }
align-items: baseline;
gap: 10px; //
} .not-login {
&-body { display: flex;
display: flex; flex-direction: column;
flex-direction: column; align-items: center;
align-items: center;
gap: 10px; .logo {
img { display: flex;
width: 70px; align-items: center;
height: 70px; gap: 20px;
}
} img {
} width: 50px;
.btn { height: 50px;
display: flex;
justify-content: center;
margin-top: 30px;
} }
// .arrow {
.not-login { width: 15px;
display: flex; height: 15px;
flex-direction: column;
align-items: center;
.logo {
display: flex;
align-items: center;
gap: 20px;
img {
width: 50px;
height: 50px;
}
.arrow {
width: 15px;
height: 15px;
}
}
.desc {
margin-top: 30px;
margin-bottom: 30px;
font-size: 14px;
font-family: 'PingFang SC';
font-style: normal;
line-height: 14px;
opacity: 0.75;
mix-blend-mode: normal;
}
} }
}
.desc {
margin-top: 30px;
margin-bottom: 30px;
font-size: 14px;
font-family: 'PingFang SC';
font-style: normal;
line-height: 14px;
opacity: 0.75;
mix-blend-mode: normal;
}
} }
}
} }
</style> </style>

View File

@ -90,9 +90,9 @@ export default defineConfig(({ mode}) => {
proxy: { proxy: {
[env.VITE_APP_BASE_API]: { [env.VITE_APP_BASE_API]: {
// target: 'http://192.168.32.226:8844', target: 'http://192.168.32.226:8844',
// target: 'http://192.168.32.244:8881', // target: 'http://192.168.32.244:8881',
target: 'http://120.77.179.54:8844', // 120测试 // target: 'http://120.77.179.54:8844', // 120测试
// target: 'http://192.168.33.46:8844', // 本地开发环境 // target: 'http://192.168.33.46:8844', // 本地开发环境
ws: 'ws://192.168.33.46:8844', ws: 'ws://192.168.33.46:8844',
changeOrigin: true, changeOrigin: true,

View File

@ -3700,8 +3700,8 @@ jetlinks-store@^0.0.3:
jetlinks-ui-components@^1.0.5: jetlinks-ui-components@^1.0.5:
version "1.0.5" version "1.0.5"
resolved "http://47.108.170.157:9013/jetlinks-ui-components/-/jetlinks-ui-components-1.0.5.tgz#da230869aacc49be00a03da55d6bf268570fee73" resolved "http://47.108.170.157:9013/jetlinks-ui-components/-/jetlinks-ui-components-1.0.5.tgz#bcf2ccab91dd64355bbe6528501d37f85f503161"
integrity sha512-XOHa0sxhFlCrKBJ1tscCXdLlcr1ZZjDhHx1sE4wqurnSKKU6PsjHKsyOWzMC1+4XgRcCLomvo9OGIwHI0IyQrQ== integrity sha512-yUN47hmOjDryn2CBrAL7IRMdyJsuKn7wG+OwLD9Jpii/8obUfIYT2nKoxihUzWjIrBmhP1WmD94C0AwaCN1hxw==
dependencies: dependencies:
"@vueuse/core" "^9.12.0" "@vueuse/core" "^9.12.0"
ant-design-vue "^3.2.15" ant-design-vue "^3.2.15"