Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 37 additions & 0 deletions backend/alembic/versions/060_platform_token_ddl.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
"""060_platform_token_ddl

Revision ID: b40e41c67db3
Revises: db1a95567cbb
Create Date: 2026-01-04 15:50:31.550287

"""
from alembic import op
import sqlalchemy as sa
import sqlmodel.sql.sqltypes
from sqlalchemy.dialects import postgresql

# revision identifiers, used by Alembic.
revision = 'b40e41c67db3'
down_revision = 'db1a95567cbb'
branch_labels = None
depends_on = None


def upgrade():
# ### commands auto generated by Alembic - please adjust! ###
op.create_table('sys_platform_token',
sa.Column('id', sa.BigInteger(), nullable=False),
sa.Column('token', sqlmodel.sql.sqltypes.AutoString(length=255), nullable=False),
sa.Column('create_time', sa.BigInteger(), nullable=False),
sa.Column('exp_time', sa.BigInteger(), nullable=False),
sa.PrimaryKeyConstraint('id')
)
op.create_index(op.f('ix_sys_platform_token_id'), 'sys_platform_token', ['id'], unique=False)
# ### end Alembic commands ###


def downgrade():
# ### commands auto generated by Alembic - please adjust! ###
op.drop_index(op.f('ix_sys_platform_token_id'), table_name='sys_platform_token')
op.drop_table('sys_platform_token')
# ### end Alembic commands ###
2 changes: 2 additions & 0 deletions backend/common/utils/whitelist.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,8 @@
"/system/authentication/platform/status",
"/system/authentication/login/*",
"/system/authentication/sso/*",
"/system/platform/sso/*",
"/system/platform/client/*",
"/system/parameter/login"
]

Expand Down
2 changes: 1 addition & 1 deletion backend/pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ dependencies = [
"pyyaml (>=6.0.2,<7.0.0)",
"fastapi-mcp (>=0.3.4,<0.4.0)",
"tabulate>=0.9.0",
"sqlbot-xpack>=0.0.4.0,<0.0.5.0",
"sqlbot-xpack>=0.0.5.0,<0.0.6.0",
"fastapi-cache2>=0.2.2",
"sqlparse>=0.5.3",
"redis>=6.2.0",
Expand Down
64 changes: 64 additions & 0 deletions frontend/src/assets/svg/logo_wechat-work.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
79 changes: 79 additions & 0 deletions frontend/src/views/login/xpack/DingtalkQr.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
<template>
<div id="de2-dingtalk-qr" :class="{ 'de2-dingtalk-qr': !isBind }" />
</template>

<script lang="ts" setup>
import { loadScript } from '@/utils/RemoteJs'
import { propTypes } from '@/utils/propTypes'
import { getSQLBotAddr } from '@/utils/utils'
import { ref } from 'vue'
import { queryClientInfo } from './platformUtils'
interface DingtalkQrInfo {
client_id: string
state: string
redirect_uri: string
}

const props = defineProps({
isBind: propTypes.bool.def(false),
})
const origin = ref(7)
const remoteJsUrl = 'https://g.alicdn.com/dingding/h5-dingtalk-login/0.21.0/ddlogin.js'
const jsId = 'de-dingtalk-qr-id'
const init = () => {
loadScript(remoteJsUrl, jsId).then(() => {
queryClientInfo(origin.value).then((res: any) => {
const data = formatQrResult(res)
loadQr(data.client_id, data.state, data.redirect_uri)
})
})
}

const formatQrResult = (data: any): DingtalkQrInfo => {
const result = { client_id: null, state: null, redirect_uri: null } as unknown as DingtalkQrInfo
result.client_id = data.client_id
result.state = 'fit2cloud-dingtalk-qr'
result.redirect_uri = data.redirect_uri || getSQLBotAddr()
if (props.isBind) {
result.state += '_de_bind'
}
return result
}

const loadQr = (client_id: string, STATE: string, REDIRECT_URI: string) => {
// eslint-disable-next-line
// @ts-ignore
window.DTFrameLogin(
{
id: 'de2-dingtalk-qr',
width: 280,
height: 300,
},
{
redirect_uri: encodeURIComponent(REDIRECT_URI),
client_id: client_id,
scope: 'openid',
response_type: 'code',
state: STATE,
prompt: 'consent',
},
(loginResult: any) => {
const { redirectUrl, authCode } = loginResult
// 这里可以直接进行重定向
window.location.href = redirectUrl
// 也可以在不跳转页面的情况下,使用code进行授权
console.log(authCode)
},
(errorMsg: any) => {
// 这里一般需要展示登录失败的具体原因,可以使用toast等轻提示
console.error(`errorMsg of errorCbk: ${errorMsg}`)
}
)
}
init()
</script>
<style lang="less" scoped>
.de2-dingtalk-qr {
margin-top: -36px;
}
</style>
82 changes: 76 additions & 6 deletions frontend/src/views/login/xpack/Handler.vue
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
<template>
<!-- <div v-if="loginCategory.qrcode" :class="{ 'de-qr-hidden': !qrStatus }">
<div v-if="loginCategory.qrcode" :class="{ 'de-qr-hidden': !qrStatus }">
<QrTab
v-if="qrStatus"
:wecom="loginCategory.wecom"
:dingtalk="loginCategory.dingtalk"
:lark="loginCategory.lark"
:larksuite="loginCategory.larksuite"
/>
</div> -->
</div>
<LdapLoginForm v-if="isLdap" />
<el-divider v-if="anyEnable" class="de-other-login-divider">{{
t('login.other_login')
Expand Down Expand Up @@ -54,13 +54,11 @@
import { ref, onMounted, nextTick, computed } from 'vue'
import QrcodeLdap from './QrcodeLdap.vue'
import LdapLoginForm from './LdapLoginForm.vue'
/* import Oidc from './Oidc.vue'
import Oauth2 from './Oauth2.vue'
import Saml2 from './Saml2.vue' */

import Oidc from './Oidc.vue'
import Cas from './Cas.vue'
import Oauth2 from './Oauth2.vue'
// import QrTab from './QrTab.vue'
import QrTab from './QrTab.vue'
import { request } from '@/utils/request'
import { useCache } from '@/utils/useCache'

Expand Down Expand Up @@ -197,6 +195,8 @@ const init = (cb?: () => void) => {
.then((res) => {
if (res) {
const list: any[] = res as any[]
/* list.push({ name: 'qrcode', enable: true })
list.push({ name: 'wecom', enable: true }) */
list.forEach((item: { name: keyof LoginCategory; enable: boolean }) => {
loginCategory.value[item.name] = item.enable
if (item.enable) {
Expand Down Expand Up @@ -416,6 +416,72 @@ const oidcLogin = () => {
}, 1500)
})
}
const wecomLogin = () => {
const urlParams = getUrlParams()
request
.post('/system/platform/sso/6', urlParams)
.then((res: any) => {
const token = res.access_token
// const platform_info = res.platform_info
if (token && isPlatformClient()) {
wsCache.set('de-platform-client', true)
}
userStore.setToken(token)
userStore.setExp(res.exp)
userStore.setTime(Date.now())
userStore.setPlatformInfo({
flag: 'wecom',
// data: platform_info ? JSON.stringify(platform_info) : '',
origin: 6,
})
const queryRedirectPath = getCurLocation()
router.push({ path: queryRedirectPath })
})
.catch((e: any) => {
userStore.setToken('')
setTimeout(() => {
// logoutHandler(true, true)
platformLoginMsg.value = e?.message || e
setTimeout(() => {
window.location.href =
window.location.origin + window.location.pathname + window.location.hash
}, 2000)
}, 1500)
})
}
const dingtalkLogin = () => {
const urlParams = getUrlParams()
request
.post('/system/platform/sso/7', urlParams)
.then((res: any) => {
const token = res.access_token
// const platform_info = res.platform_info
if (token && isPlatformClient()) {
wsCache.set('de-platform-client', true)
}
userStore.setToken(token)
userStore.setExp(res.exp)
userStore.setTime(Date.now())
userStore.setPlatformInfo({
flag: 'dingtalk',
// data: platform_info ? JSON.stringify(platform_info) : '',
origin: 7,
})
const queryRedirectPath = getCurLocation()
router.push({ path: queryRedirectPath })
})
.catch((e: any) => {
userStore.setToken('')
setTimeout(() => {
// logoutHandler(true, true)
platformLoginMsg.value = e?.message || e
setTimeout(() => {
window.location.href =
window.location.origin + window.location.pathname + window.location.hash
}, 2000)
}, 1500)
})
}
/* const platformLogin = (origin: number) => {
const url = '/system/authentication/sso/cas'
request
Expand Down Expand Up @@ -591,6 +657,10 @@ onMounted(() => {
oauth2Login()
} else if (state?.includes('oidc')) {
oidcLogin()
} else if (state?.includes('wecom')) {
wecomLogin()
} else if (state?.includes('dingtalk')) {
dingtalkLogin()
} else {
auto2Platform()
}
Expand Down
Loading
Loading