Browse Source

add:实现gitee第三方登陆

master
秋田弘 6 months ago
parent
commit
8a60a6a71c
  1. 11
      frontend/components.d.ts
  2. 2
      frontend/package.json
  3. 31
      frontend/pnpm-lock.yaml
  4. 0
      frontend/public/image/login/sina.png
  5. 0
      frontend/public/image/login/wechat.png
  6. BIN
      frontend/src/assets/login/GitHub.png
  7. BIN
      frontend/src/assets/login/QQ.png
  8. BIN
      frontend/src/assets/login/gitee.png
  9. BIN
      frontend/src/assets/login/sina.png
  10. BIN
      frontend/src/assets/login/wechat.png
  11. 97
      frontend/src/components/desktop/LockDesktop.vue
  12. 20
      frontend/src/components/setting/SetLang.vue
  13. 17
      frontend/src/components/window/IframeFile.vue

11
frontend/components.d.ts

@ -67,18 +67,26 @@ declare module 'vue' {
ElCard: typeof import('element-plus/es')['ElCard'] ElCard: typeof import('element-plus/es')['ElCard']
ElCarousel: typeof import('element-plus/es')['ElCarousel'] ElCarousel: typeof import('element-plus/es')['ElCarousel']
ElCarouselItem: typeof import('element-plus/es')['ElCarouselItem'] ElCarouselItem: typeof import('element-plus/es')['ElCarouselItem']
ElCheckbox: typeof import('element-plus/es')['ElCheckbox']
ElCol: typeof import('element-plus/es')['ElCol'] ElCol: typeof import('element-plus/es')['ElCol']
ElColorPicker: typeof import('element-plus/es')['ElColorPicker'] ElColorPicker: typeof import('element-plus/es')['ElColorPicker']
ElContainer: typeof import('element-plus/es')['ElContainer'] ElContainer: typeof import('element-plus/es')['ElContainer']
ElDialog: typeof import('element-plus/es')['ElDialog'] ElDialog: typeof import('element-plus/es')['ElDialog']
ElDrawer: typeof import('element-plus/es')['ElDrawer'] ElDrawer: typeof import('element-plus/es')['ElDrawer']
ElDropdown: typeof import('element-plus/es')['ElDropdown']
ElDropdownItem: typeof import('element-plus/es')['ElDropdownItem']
ElDropdownMenu: typeof import('element-plus/es')['ElDropdownMenu']
ElEmpty: typeof import('element-plus/es')['ElEmpty'] ElEmpty: typeof import('element-plus/es')['ElEmpty']
ElFooter: typeof import('element-plus/es')['ElFooter']
ElForm: typeof import('element-plus/es')['ElForm'] ElForm: typeof import('element-plus/es')['ElForm']
ElFormItem: typeof import('element-plus/es')['ElFormItem'] ElFormItem: typeof import('element-plus/es')['ElFormItem']
ElHeader: typeof import('element-plus/es')['ElHeader'] ElHeader: typeof import('element-plus/es')['ElHeader']
ElIcon: typeof import('element-plus/es')['ElIcon'] ElIcon: typeof import('element-plus/es')['ElIcon']
ElImage: typeof import('element-plus/es')['ElImage'] ElImage: typeof import('element-plus/es')['ElImage']
ElInput: typeof import('element-plus/es')['ElInput'] ElInput: typeof import('element-plus/es')['ElInput']
ElMain: typeof import('element-plus/es')['ElMain']
ElMenu: typeof import('element-plus/es')['ElMenu']
ElMenuItem: typeof import('element-plus/es')['ElMenuItem']
ElOption: typeof import('element-plus/es')['ElOption'] ElOption: typeof import('element-plus/es')['ElOption']
ElPageHeader: typeof import('element-plus/es')['ElPageHeader'] ElPageHeader: typeof import('element-plus/es')['ElPageHeader']
ElPagination: typeof import('element-plus/es')['ElPagination'] ElPagination: typeof import('element-plus/es')['ElPagination']
@ -97,6 +105,8 @@ declare module 'vue' {
ElTag: typeof import('element-plus/es')['ElTag'] ElTag: typeof import('element-plus/es')['ElTag']
ElText: typeof import('element-plus/es')['ElText'] ElText: typeof import('element-plus/es')['ElText']
ElTooltip: typeof import('element-plus/es')['ElTooltip'] ElTooltip: typeof import('element-plus/es')['ElTooltip']
ElTransfer: typeof import('element-plus/es')['ElTransfer']
ElTree: typeof import('element-plus/es')['ElTree']
Error: typeof import('./src/components/taskbar/Error.vue')['default'] Error: typeof import('./src/components/taskbar/Error.vue')['default']
FileIcon: typeof import('./src/components/builtin/FileIcon.vue')['default'] FileIcon: typeof import('./src/components/builtin/FileIcon.vue')['default']
FileIconImg: typeof import('./src/components/builtin/FileIconImg.vue')['default'] FileIconImg: typeof import('./src/components/builtin/FileIconImg.vue')['default']
@ -106,7 +116,6 @@ declare module 'vue' {
FilePwd: typeof import('./src/components/oa/FilePwd.vue')['default'] FilePwd: typeof import('./src/components/oa/FilePwd.vue')['default']
FileTree: typeof import('./src/components/builtin/FileTree.vue')['default'] FileTree: typeof import('./src/components/builtin/FileTree.vue')['default']
FileViewer: typeof import('./src/components/builtin/FileViewer.vue')['default'] FileViewer: typeof import('./src/components/builtin/FileViewer.vue')['default']
GithubNext: typeof import('./src/components/desktop/GithubNext.vue')['default']
IframeFile: typeof import('./src/components/window/IframeFile.vue')['default'] IframeFile: typeof import('./src/components/window/IframeFile.vue')['default']
ImageViewer: typeof import('./src/components/builtin/ImageViewer.vue')['default'] ImageViewer: typeof import('./src/components/builtin/ImageViewer.vue')['default']
Install: typeof import('./src/components/install/Install.vue')['default'] Install: typeof import('./src/components/install/Install.vue')['default']

2
frontend/package.json

@ -19,6 +19,7 @@
"jszip": "^3.10.1", "jszip": "^3.10.1",
"lunar-typescript": "^1.7.6", "lunar-typescript": "^1.7.6",
"moment": "^2.30.1", "moment": "^2.30.1",
"nanoid": "^5.0.9",
"pinia": "^2.1.7", "pinia": "^2.1.7",
"pinia-plugin-persist": "^1.0.0", "pinia-plugin-persist": "^1.0.0",
"vite-plugin-svg-icons": "^2.0.1", "vite-plugin-svg-icons": "^2.0.1",
@ -31,6 +32,7 @@
}, },
"devDependencies": { "devDependencies": {
"@types/file-saver": "^2.0.7", "@types/file-saver": "^2.0.7",
"@types/nanoid": "^3.0.0",
"@types/node": "^20.14.10", "@types/node": "^20.14.10",
"@vitejs/plugin-vue": "^5.0.5", "@vitejs/plugin-vue": "^5.0.5",
"sass": "^1.77.8", "sass": "^1.77.8",

31
frontend/pnpm-lock.yaml

@ -33,11 +33,14 @@ importers:
specifier: ^3.10.1 specifier: ^3.10.1
version: 3.10.1 version: 3.10.1
lunar-typescript: lunar-typescript:
specifier: ^1.7.5 specifier: ^1.7.6
version: 1.7.5 version: 1.7.6
moment: moment:
specifier: ^2.30.1 specifier: ^2.30.1
version: 2.30.1 version: 2.30.1
nanoid:
specifier: ^5.0.9
version: 5.0.9
pinia: pinia:
specifier: ^2.1.7 specifier: ^2.1.7
version: 2.2.4(typescript@5.6.3)(vue@3.5.12(typescript@5.6.3)) version: 2.2.4(typescript@5.6.3)(vue@3.5.12(typescript@5.6.3))
@ -69,6 +72,9 @@ importers:
'@types/file-saver': '@types/file-saver':
specifier: ^2.0.7 specifier: ^2.0.7
version: 2.0.7 version: 2.0.7
'@types/nanoid':
specifier: ^3.0.0
version: 3.0.0
'@types/node': '@types/node':
specifier: ^20.14.10 specifier: ^20.14.10
version: 20.16.13 version: 20.16.13
@ -534,6 +540,10 @@ packages:
'@types/lodash@4.17.12': '@types/lodash@4.17.12':
resolution: {integrity: sha512-sviUmCE8AYdaF/KIHLDJBQgeYzPBI0vf/17NaYehBJfYD1j6/L95Slh07NlyK2iNyBNaEkb3En2jRt+a8y3xZQ==} resolution: {integrity: sha512-sviUmCE8AYdaF/KIHLDJBQgeYzPBI0vf/17NaYehBJfYD1j6/L95Slh07NlyK2iNyBNaEkb3En2jRt+a8y3xZQ==}
'@types/nanoid@3.0.0':
resolution: {integrity: sha512-UXitWSmXCwhDmAKe7D3hNQtQaHeHt5L8LO1CB8GF8jlYVzOv5cBWDNqiJ+oPEWrWei3i3dkZtHY/bUtd0R/uOQ==}
deprecated: This is a stub types definition. nanoid provides its own type definitions, so you do not need this installed.
'@types/node@20.16.13': '@types/node@20.16.13':
resolution: {integrity: sha512-GjQ7im10B0labo8ZGXDGROUl9k0BNyDgzfGpb4g/cl+4yYDWVKcozANF4FGr4/p0O/rAkQClM6Wiwkije++1Tg==} resolution: {integrity: sha512-GjQ7im10B0labo8ZGXDGROUl9k0BNyDgzfGpb4g/cl+4yYDWVKcozANF4FGr4/p0O/rAkQClM6Wiwkije++1Tg==}
@ -2040,8 +2050,8 @@ packages:
lottie-web@5.12.2: lottie-web@5.12.2:
resolution: {integrity: sha512-uvhvYPC8kGPjXT3MyKMrL3JitEAmDMp30lVkuq/590Mw9ok6pWcFCwXJveo0t5uqYw1UREQHofD+jVpdjBv8wg==} resolution: {integrity: sha512-uvhvYPC8kGPjXT3MyKMrL3JitEAmDMp30lVkuq/590Mw9ok6pWcFCwXJveo0t5uqYw1UREQHofD+jVpdjBv8wg==}
lunar-typescript@1.7.5: lunar-typescript@1.7.6:
resolution: {integrity: sha512-AlOwYrxHRCR9Plba5TlZY0NVv6aFobmR1gxfiAE1KxjDzBXoDtT2KrsBYCVaErGokiL8qLMS1FNwGPiPRX2a4g==} resolution: {integrity: sha512-vrNRgzJ6UgK++P81jaOykV7YBCLemC8l/XDbsXE7MinojXolOKiIHm6sOZg5wdDMbJxCWP1ERAaqcBV9mhw2Bg==}
magic-string@0.30.12: magic-string@0.30.12:
resolution: {integrity: sha512-Ea8I3sQMVXr8JhN4z+H/d8zwo+tYDgHE9+5G4Wnrwhs0gaK9fXTKx0Tw5Xwsd/bCPTTZNRAdpyzvoeORe9LYpw==} resolution: {integrity: sha512-Ea8I3sQMVXr8JhN4z+H/d8zwo+tYDgHE9+5G4Wnrwhs0gaK9fXTKx0Tw5Xwsd/bCPTTZNRAdpyzvoeORe9LYpw==}
@ -2145,6 +2155,11 @@ packages:
engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1}
hasBin: true hasBin: true
nanoid@5.0.9:
resolution: {integrity: sha512-Aooyr6MXU6HpvvWXKoVoXwKMs/KyVakWwg7xQfv5/S/RIgJMy0Ifa45H9qqYy7pTCszrHzP21Uk4PZq2HpEM8Q==}
engines: {node: ^18 || >=20}
hasBin: true
nanomatch@1.2.13: nanomatch@1.2.13:
resolution: {integrity: sha512-fpoe2T0RbHwBTBUOftAfBPaDEi06ufaUai0mE6Yn1kacc3SnTErfb/h+X94VXzI64rKFHYImXSvdwGGCmwOqCA==} resolution: {integrity: sha512-fpoe2T0RbHwBTBUOftAfBPaDEi06ufaUai0mE6Yn1kacc3SnTErfb/h+X94VXzI64rKFHYImXSvdwGGCmwOqCA==}
engines: {node: '>=0.10.0'} engines: {node: '>=0.10.0'}
@ -3356,6 +3371,10 @@ snapshots:
'@types/lodash@4.17.12': {} '@types/lodash@4.17.12': {}
'@types/nanoid@3.0.0':
dependencies:
nanoid: 5.0.9
'@types/node@20.16.13': '@types/node@20.16.13':
dependencies: dependencies:
undici-types: 6.19.8 undici-types: 6.19.8
@ -5330,7 +5349,7 @@ snapshots:
lottie-web@5.12.2: {} lottie-web@5.12.2: {}
lunar-typescript@1.7.5: {} lunar-typescript@1.7.6: {}
magic-string@0.30.12: magic-string@0.30.12:
dependencies: dependencies:
@ -5481,6 +5500,8 @@ snapshots:
nanoid@3.3.7: {} nanoid@3.3.7: {}
nanoid@5.0.9: {}
nanomatch@1.2.13(supports-color@3.2.3): nanomatch@1.2.13(supports-color@3.2.3):
dependencies: dependencies:
arr-diff: 4.0.0 arr-diff: 4.0.0

0
frontend/public/image/login/新浪微博.png → frontend/public/image/login/sina.png

Before

Width:  |  Height:  |  Size: 4.5 KiB

After

Width:  |  Height:  |  Size: 4.5 KiB

0
frontend/public/image/login/微信.png → frontend/public/image/login/wechat.png

Before

Width:  |  Height:  |  Size: 3.6 KiB

After

Width:  |  Height:  |  Size: 3.6 KiB

BIN
frontend/src/assets/login/GitHub.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.9 KiB

BIN
frontend/src/assets/login/QQ.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.7 KiB

BIN
frontend/src/assets/login/gitee.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.2 KiB

BIN
frontend/src/assets/login/sina.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.5 KiB

BIN
frontend/src/assets/login/wechat.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.6 KiB

97
frontend/src/components/desktop/LockDesktop.vue

@ -48,54 +48,17 @@
</div> </div>
<div class="third-party-login"> <div class="third-party-login">
<img <img
v-for="platform in thirdPartyPlatforms"
:key="platform.name"
:src="platform.icon"
:alt="platform.name"
style=" style="
width: 25px; width: 25px;
height: 25px; height: 25px;
cursor: pointer; cursor: pointer;
color: #409eff; color: #409eff;
" "
src="../../../public/image/login/微信.png" @click="onThirdPartyLogin(platform.name)"
@click="onThirdPartyLogin('wechat')"
/>
<img
style="
width: 25px;
height: 25px;
cursor: pointer;
color: #409eff;
"
src="../../../public/image/login/QQ.png"
@click="onThirdPartyLogin('qq')"
/>
<img
style="
width: 25px;
height: 25px;
cursor: pointer;
color: #409eff;
"
src="../../../public/image/login/新浪微博.png"
@click="onThirdPartyLogin('sina')"
/>
<img
style="
width: 25px;
height: 25px;
cursor: pointer;
color: #409eff;
"
src="../../../public/image/login/GitHub.png"
@click="onThirdPartyLogin('github')"
/>
<img
style="
width: 25px;
height: 25px;
cursor: pointer;
color: #409eff;
"
src="../../../public/image/login/gitee.png"
@click="onThirdPartyLogin('gitee')"
/> />
</div> </div>
<div <div
@ -199,6 +162,30 @@
const config = getSystemConfig(); const config = getSystemConfig();
const lockClassName = ref("screen-show"); const lockClassName = ref("screen-show");
const isRegisterMode = ref(false); const isRegisterMode = ref(false);
const thirdPartyPlatforms = [
{
name: "wechat",
icon: new URL("@/assets/login/wechat.png", import.meta.url).href,
},
{
name: "qq",
icon: new URL("@/assets/login/qq.png", import.meta.url).href,
},
{
name: "sina",
icon: new URL("@/assets/login/sina.png", import.meta.url).href,
},
{
name: "github",
icon: new URL("@/assets/login/github.png", import.meta.url).href,
},
{
name: "gitee",
icon: new URL("@/assets/login/gitee.png", import.meta.url).href,
},
];
function loginSuccess() { function loginSuccess() {
lockClassName.value = "screen-hidean"; lockClassName.value = "screen-hidean";
setTimeout(() => { setTimeout(() => {
@ -219,6 +206,7 @@
} }
}); });
// code
watch( watch(
() => router.currentRoute.value.query.code, () => router.currentRoute.value.query.code,
() => { () => {
@ -249,6 +237,8 @@
const returnedState = router.currentRoute.value.query const returnedState = router.currentRoute.value.query
.state as string; .state as string;
console.log(returnedState, "---", store.State);
if (returnedState !== store.State) { if (returnedState !== store.State) {
notifyError("登录失败,请重试"); notifyError("登录失败,请重试");
return; return;
@ -402,7 +392,7 @@
break; break;
case "gitee": case "gitee":
loginFunction = async function () { loginFunction = async function () {
return await authWithGithub(); return await authWithGitee();
}; };
break; break;
default: default:
@ -423,7 +413,6 @@
const authWithGithub = async (): Promise<boolean> => { const authWithGithub = async (): Promise<boolean> => {
// stateCSRF,使 // stateCSRF,使
const state = Date.now() + Math.random().toString(36).substring(2, 15); const state = Date.now() + Math.random().toString(36).substring(2, 15);
//
store.State = state; store.State = state;
const url = config.userInfo.url + "/github/authorize?state=" + state; const url = config.userInfo.url + "/github/authorize?state=" + state;
const res: any = await fetch(url, { const res: any = await fetch(url, {
@ -452,6 +441,26 @@
const authWithSina = (): boolean | PromiseLike<boolean> => { const authWithSina = (): boolean | PromiseLike<boolean> => {
throw new Error("Function not implemented."); throw new Error("Function not implemented.");
}; };
const authWithGitee = async (): Promise<boolean> => {
// stateCSRF,使
const state = Date.now() + Math.random().toString(36).substring(2, 15);
store.State = state;
const url = config.userInfo.url + "/gitee/authorize?state=" + state;
const res: any = await fetch(url, {
method: "POST",
body: JSON.stringify({
state: state,
}),
});
if (!res.ok) {
return false;
}
const data = await res.json();
// Gitee
window.location.href = data.data.url;
return true;
};
</script> </script>
<style scoped lang="scss"> <style scoped lang="scss">

20
frontend/src/components/setting/SetLang.vue

@ -31,23 +31,25 @@
<div class="setting-item"> <div class="setting-item">
<label></label> <label></label>
<el-button @click="submit" type="primary"> <el-button
@click="submit"
type="primary"
>
{{ t("confirm") }} {{ t("confirm") }}
</el-button> </el-button>
</div> </div>
</div> </div>
</div> </div>
</div> </div>
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
import { getLang, setLang, t } from "@/i18n";
import { ElMessageBox } from "element-plus";
import { ref } from "vue"; import { ref } from "vue";
import { ElMessageBox } from 'element-plus' import { useI18n } from "vue-i18n";
import { t, getLang, setLang } from "@/i18n"; const { locale } = useI18n();
import { useI18n } from 'vue-i18n'; // const showDialog = ref(false);
const { locale } = useI18n()
const showDialog = ref(false);
const langList = [ const langList = [
{ {
label: "中文", label: "中文",
@ -72,8 +74,8 @@ async function submit() {
setLang(modelvalue.value); setLang(modelvalue.value);
locale.value = modelvalue.value; locale.value = modelvalue.value;
ElMessageBox.alert(t("save.success"), t("language"), { ElMessageBox.alert(t("save.success"), t("language"), {
confirmButtonText: 'OK', confirmButtonText: "OK",
}) });
//showDialog.value = false //showDialog.value = false
// Dialog.showMessageBox({ // Dialog.showMessageBox({

17
frontend/src/components/window/IframeFile.vue

@ -1,17 +1,22 @@
<template> <template>
<iframe class="setiframe" allow="fullscreen" ref="storeRef" :src="src"></iframe> <iframe
class="setiframe"
allow="fullscreen"
ref="storeRef"
:src="src"
></iframe>
</template> </template>
<script lang="ts" setup name="IframeFile"> <script lang="ts" setup name="IframeFile">
//@ts-ignore //@ts-ignore
import { askAi } from "@/hook/useAi";
import { useChooseStore } from "@/stores/choose";
import { BrowserWindow, Dialog, Notify, System } from "@/system"; import { BrowserWindow, Dialog, Notify, System } from "@/system";
import { getSplit, getSystemConfig, setSystemKey } from "@/system/config"; import { getSplit, getSystemConfig, setSystemKey } from "@/system/config";
import eventBus from "@/system/event/eventBus";
import { base64ToBuffer, isBase64 } from "@/util/file"; import { base64ToBuffer, isBase64 } from "@/util/file";
import { isShareFile } from "@/util/sharePath.ts"; import { isShareFile } from "@/util/sharePath.ts";
import { inject, onMounted, onUnmounted, ref, toRaw } from "vue";
import { askAi } from "@/hook/useAi";
import { useChooseStore } from "@/stores/choose";
import { nanoid } from "nanoid"; import { nanoid } from "nanoid";
import eventBus from "@/system/event/eventBus"; import { inject, onMounted, onUnmounted, ref, toRaw } from "vue";
const SP = getSplit(); const SP = getSplit();
const sys: any = inject<System>("system"); const sys: any = inject<System>("system");
@ -46,7 +51,7 @@ const saveFile = async (e: any) => {
if (data.ext) { if (data.ext) {
ext = data.ext; ext = data.ext;
} }
let path:string let path: string;
e.filePath !== "" e.filePath !== ""
? (path = `${e.filePath}/${e.fileName}.${ext}`) ? (path = `${e.filePath}/${e.fileName}.${ext}`)
: (path = `${SP}C${SP}Users${SP}Desktop${SP}${e.fileName}.${ext}`); : (path = `${SP}C${SP}Users${SP}Desktop${SP}${e.fileName}.${ext}`);

Loading…
Cancel
Save