feat(project): init
This commit is contained in:
102
components/login/feishu/auto-login.tsx
Normal file
102
components/login/feishu/auto-login.tsx
Normal file
@@ -0,0 +1,102 @@
|
||||
import { APP, PLATFORM, TENANT } from "@/components/login/libs/common"
|
||||
import { useLoginStore } from "@/components/login/store"
|
||||
import { useRouter } from "next/navigation"
|
||||
import { useCallback, useEffect } from "react"
|
||||
import { fetchFeishuLogin } from "../api"
|
||||
import { DigitalIcon } from "../resource/icons/digital"
|
||||
import { APP_ID, APP_SECRECT } from "./util"
|
||||
|
||||
const HeaderIcon = DigitalIcon
|
||||
|
||||
const FeishuAutoLogin = ({ useUserStore }: { useUserStore: any }) => {
|
||||
const fingerprint = useLoginStore.getState().fingerprint
|
||||
|
||||
const list = window.location.href.split("/")
|
||||
const http_header =
|
||||
window.location.protocol.toLowerCase() === "https:" ? "https" : "http"
|
||||
|
||||
const redirect_url =
|
||||
http_header + "://" + list[2] + `${process.env.NEXT_PUBLIC_BASE_PATH}/login`
|
||||
|
||||
const { setUserInfo, refreshToken } = useUserStore()
|
||||
const router = useRouter()
|
||||
|
||||
const autoLogin = useCallback(
|
||||
(
|
||||
fingerprint: any,
|
||||
redirect_url: any,
|
||||
router: any,
|
||||
setUserInfo: (arg0: any, arg1: any, arg2: any) => void
|
||||
) => {
|
||||
if (!window.h5sdk || !window.tt) {
|
||||
console.error("Feishu H5 SDK is not available")
|
||||
setTimeout(() => {
|
||||
autoLogin(fingerprint, redirect_url, router, setUserInfo)
|
||||
}, 500)
|
||||
return
|
||||
}
|
||||
|
||||
// 确保每次进到这个页面是未登录,然后触发自动登录逻辑
|
||||
window.h5sdk.ready(async () => {
|
||||
console.log("Feishu H5 SDK is ready, requesting auth code")
|
||||
window.tt.requestAuthCode({
|
||||
appId: APP_ID,
|
||||
success: async (res: any) => {
|
||||
try {
|
||||
const params = {
|
||||
code: res.code,
|
||||
redirect_uri: redirect_url,
|
||||
tenant: TENANT,
|
||||
platform: PLATFORM,
|
||||
app: APP,
|
||||
fingerprint,
|
||||
app_id: APP_ID,
|
||||
app_secret: APP_SECRECT,
|
||||
}
|
||||
const response = await fetchFeishuLogin(params)
|
||||
const info = response.message
|
||||
setUserInfo(info.tenant, info.user_info, info.rbac)
|
||||
refreshToken({
|
||||
access_token: info.access_token || "",
|
||||
refresh_token: info.refresh_token || "",
|
||||
})
|
||||
window.location.href = `${process.env.NEXT_PUBLIC_BASE_PATH}/`
|
||||
} catch (err) {
|
||||
console.log(err)
|
||||
}
|
||||
},
|
||||
fail: (err: any) => {
|
||||
console.error("Failed to get auth code from Feishu:", err)
|
||||
alert(JSON.stringify(err))
|
||||
},
|
||||
})
|
||||
})
|
||||
},
|
||||
[refreshToken]
|
||||
)
|
||||
|
||||
const isFeishu = useCallback(() => !!(window.h5sdk && window.tt), [])
|
||||
|
||||
useEffect(() => {
|
||||
console.log("Feishu auto login effect triggered")
|
||||
autoLogin(fingerprint, redirect_url, router, setUserInfo)
|
||||
}, [fingerprint, redirect_url, router, setUserInfo, autoLogin, isFeishu])
|
||||
|
||||
return (
|
||||
<div
|
||||
style={{
|
||||
width: "100%",
|
||||
height: "100%",
|
||||
display: "flex",
|
||||
justifyContent: "center",
|
||||
alignItems: "center",
|
||||
flexDirection: "column",
|
||||
gap: 20,
|
||||
}}>
|
||||
<HeaderIcon />
|
||||
<span>自动登录中,请稍后...</span>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default FeishuAutoLogin
|
||||
93
components/login/feishu/qr-login.tsx
Normal file
93
components/login/feishu/qr-login.tsx
Normal file
@@ -0,0 +1,93 @@
|
||||
import {
|
||||
APP,
|
||||
PLATFORM,
|
||||
TENANT,
|
||||
getQueryVariable,
|
||||
} from "@/components/login/libs/common"
|
||||
import { useLoginStore } from "@/components/login/store"
|
||||
import { Flex } from "@mantine/core"
|
||||
import { useSearchParams } from "next/navigation"
|
||||
import { useCallback, useEffect, useState } from "react"
|
||||
import { fetchFeishuLogin } from "../api"
|
||||
import { APP_ID, APP_SECRECT, qr_load, qr_login } from "./util"
|
||||
|
||||
const QrLogin = ({ useUserStore }: { useUserStore: any }) => {
|
||||
const fingerprint = useLoginStore.getState().fingerprint
|
||||
|
||||
const list = window.location.href.split("/")
|
||||
const http_header =
|
||||
window.location.protocol.toLowerCase() === "https:" ? "https" : "http"
|
||||
const redirect_url =
|
||||
http_header + "://" + list[2] + `${process.env.NEXT_PUBLIC_BASE_PATH}/login`
|
||||
|
||||
const searchParams = useSearchParams()
|
||||
const renderCode = useCallback(async () => {
|
||||
await qr_load()
|
||||
qr_login(
|
||||
APP_ID,
|
||||
redirect_url,
|
||||
getQueryVariable("app_id") || searchParams.get("app_id") || ""
|
||||
)
|
||||
}, [redirect_url, searchParams])
|
||||
|
||||
const [times, setTimes] = useState(0)
|
||||
|
||||
const callbackUrl = useCallback(() => {
|
||||
times !== 2 && setTimes(times + 1)
|
||||
}, [times])
|
||||
|
||||
const { setUserInfo, refreshToken } = useUserStore()
|
||||
|
||||
const feishuLogin = useCallback(async () => {
|
||||
try {
|
||||
const params = {
|
||||
code: getQueryVariable("code") || "",
|
||||
redirect_uri: redirect_url,
|
||||
tenant: TENANT,
|
||||
platform: PLATFORM,
|
||||
app: APP,
|
||||
fingerprint,
|
||||
app_id: APP_ID,
|
||||
app_secret: APP_SECRECT,
|
||||
}
|
||||
const res = await fetchFeishuLogin(params)
|
||||
const info = res.message
|
||||
setUserInfo(info.tenant, info.user_info, info.rbac)
|
||||
refreshToken({
|
||||
access_token: info.access_token || "",
|
||||
refresh_token: info.refresh_token || "",
|
||||
})
|
||||
window.location.href = `${process.env.NEXT_PUBLIC_BASE_PATH}/`
|
||||
} catch (err) {
|
||||
console.log(err)
|
||||
}
|
||||
}, [fingerprint, redirect_url, refreshToken, setUserInfo])
|
||||
|
||||
useEffect(() => {
|
||||
if (times === 1) {
|
||||
renderCode()
|
||||
if (getQueryVariable("code")) {
|
||||
fingerprint && feishuLogin()
|
||||
}
|
||||
}
|
||||
}, [feishuLogin, fingerprint, renderCode, times])
|
||||
|
||||
useEffect(() => {
|
||||
callbackUrl()
|
||||
}, [callbackUrl])
|
||||
|
||||
return (
|
||||
<Flex align="center" justify="center" w={"100%"} h={"100%"}>
|
||||
<div
|
||||
id={"login_container"}
|
||||
style={{
|
||||
width: "200px",
|
||||
height: "210px",
|
||||
display: "flex",
|
||||
justifyContent: "center",
|
||||
scale: 0.7,
|
||||
}}></div>
|
||||
</Flex>
|
||||
)
|
||||
}
|
||||
export default QrLogin
|
||||
8
components/login/feishu/type.d.ts
vendored
Normal file
8
components/login/feishu/type.d.ts
vendored
Normal file
@@ -0,0 +1,8 @@
|
||||
interface Window {
|
||||
tt: any
|
||||
h5sdk: any
|
||||
}
|
||||
|
||||
interface window {
|
||||
[key: string]: any
|
||||
}
|
||||
51
components/login/feishu/util.ts
Normal file
51
components/login/feishu/util.ts
Normal file
@@ -0,0 +1,51 @@
|
||||
// 飞书脚本
|
||||
export function qr_load() {
|
||||
return new Promise<void>((resolve, reject) => {
|
||||
const script = document.createElement("script")
|
||||
script.type = "text/javascript"
|
||||
script.src =
|
||||
"https://sf3-cn.feishucdn.com/obj/feishu-static/lark/passport/qrcode/LarkSSOSDKWebQRCode-1.0.2.js"
|
||||
script.onerror = reject
|
||||
script.onload = () => {
|
||||
resolve()
|
||||
}
|
||||
document.head.appendChild(script)
|
||||
})
|
||||
}
|
||||
|
||||
export async function qr_login(
|
||||
appId: string,
|
||||
redirect_url: string,
|
||||
state: string
|
||||
) {
|
||||
const gotoUrl = `https://passport.feishu.cn/suite/passport/oauth/authorize?client_id=${appId}&redirect_uri=${encodeURIComponent(
|
||||
redirect_url
|
||||
)}&response_type=code&state=${encodeURIComponent(state)}`
|
||||
const QRLogin = (<any>window).QRLogin
|
||||
const QRLoginObj = QRLogin({
|
||||
id: "login_container",
|
||||
goto: gotoUrl,
|
||||
style: `width: 270px;height: 270px;border: 0;border-radius:12px;background-color: #E4F2FF;
|
||||
background-image:
|
||||
radial-gradient(at 47% 33%, hsl(212.37, 72%, 59%) 0, transparent 59%),
|
||||
radial-gradient(at 82% 65%, hsl(198.00, 100%, 50%) 0, transparent 55%);`,
|
||||
})
|
||||
const handleMessage = function (event: any) {
|
||||
const origin = event.origin
|
||||
if (
|
||||
QRLoginObj.matchOrigin(origin) &&
|
||||
window.location.href.indexOf("login") > -1
|
||||
) {
|
||||
const loginTmpCode = event.data
|
||||
window.location.href = `${gotoUrl}&tmp_code=${loginTmpCode}`
|
||||
}
|
||||
}
|
||||
if (typeof window.addEventListener !== "undefined") {
|
||||
window.addEventListener("message", handleMessage, false)
|
||||
} else if (typeof (<any>window).attachEvent !== "undefined") {
|
||||
;(<any>window).attachEvent("onmessage", handleMessage)
|
||||
}
|
||||
}
|
||||
|
||||
export const APP_ID = "cli_a56577acb2f3d00c"
|
||||
export const APP_SECRECT = "168xtvkFLnVbZd1Ih5T5agKue3JxJ87V"
|
||||
Reference in New Issue
Block a user