feat: Oauth update

This commit is contained in:
landaiqing
2024-05-27 00:00:57 +08:00
parent 7f68128b5e
commit e564264c4d
10 changed files with 340 additions and 305 deletions

View File

@@ -1 +1,32 @@
/** @format */
import web from "@/utils/axios/web.ts";
/**
* 获取所有Minio信息
*/
export const getAllMinioInfo = () => {
return web.request({
url: "/oss/minio/getAllMinioInfo",
method: "get",
});
};
/**
* 第三方登录
* @param type
*/
export const oauthLogin = (type: string) => {
return web.request({
url: "/oauth/render/" + type,
method: "get",
});
};
/**
* 获取用户信息
*/
export const geOauthtUserInfo = () => {
return web.request({
url: "/oauth/userInfo/",
method: "get",
});
};

View File

@@ -0,0 +1,50 @@
.splash-body {
align-items: center;
display: flex;
justify-content: center;
height: 100vh;
overflow: hidden;
background-image: url("@/assets/images/background.png");
}
.gegga {
width: 0;
}
.snurra {
filter: url(#gegga);
}
.stopp1 {
stop-color: #f700a8;
}
.stopp2 {
stop-color: #ff8000;
}
.halvan {
animation: Snurra1 10s infinite linear;
stroke-dasharray: 180 800;
fill: none;
stroke: url(#gradient);
stroke-width: 23;
stroke-linecap: round;
}
.strecken {
animation: Snurra1 3s infinite linear;
stroke-dasharray: 26 54;
fill: none;
stroke: url(#gradient);
stroke-width: 23;
stroke-linecap: round;
}
.skugga {
filter: blur(5px);
opacity: 0.3;
position: absolute;
transform: translate(3px, 3px);
}
@keyframes Snurra1 {
0% {
stroke-dashoffset: 0;
}
100% {
stroke-dashoffset: -403px;
}
}

View File

@@ -0,0 +1,73 @@
/** @format */
import React, { useEffect } from "react";
import "./index.less";
import { geOauthtUserInfo } from "@/api/user";
import localforage from "localforage";
const LoadingPage: React.FC = () => {
async function getUserInfo() {
const res: any = await geOauthtUserInfo();
localforage.setItem("token", res.data.token).then();
localforage.setItem("userId", res.data.userId).then();
}
useEffect(() => {
document.body.classList.add("loading-body");
getUserInfo().then(() => {
if (
localforage.getItem("token").then() !== null &&
localforage.getItem("userId").then() !== null
) {
window.location.href = "/main";
}
});
return () => {
document.body.classList.remove("loading-body");
};
}, []);
return (
<>
<svg className="gegga">
<defs>
<filter id="gegga">
<feGaussianBlur
in="SourceGraphic"
stdDeviation="7"
result="blur"></feGaussianBlur>
<feColorMatrix
in="blur"
mode="matrix"
values="1 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 20 -10"
result="inreGegga"></feColorMatrix>
<feComposite
in="SourceGraphic"
in2="inreGegga"
operator="atop"></feComposite>
</filter>
</defs>
</svg>
<svg className="snurra" width="200" height="200" viewBox="0 0 200 200">
<defs>
<linearGradient id="linjärGradient">
<stop className="stopp1" offset="0"></stop>
<stop className="stopp2" offset="1"></stop>
</linearGradient>
<linearGradient
y2="160"
x2="160"
y1="40"
x1="40"
gradientUnits="userSpaceOnUse"
id="gradient"
xlinkHref="#linjärGradient"></linearGradient>
</defs>
<path
className="halvan"
d="m 164,100 c 0,-35.346224 -28.65378,-64 -64,-64 -35.346224,0 -64,28.653776 -64,64 0,35.34622 28.653776,64 64,64 35.34622,0 64,-26.21502 64,-64 0,-37.784981 -26.92058,-64 -64,-64 -37.079421,0 -65.267479,26.922736 -64,64 1.267479,37.07726 26.703171,65.05317 64,64 37.29683,-1.05317 64,-64 64,-64"></path>
<circle className="strecken" cx="100" cy="100" r="64"></circle>
</svg>
</>
);
};
export default React.memo(LoadingPage);

View File

@@ -7,8 +7,8 @@ import Login from "./modules/login/index.ts";
import Register from "./modules/register/index.ts";
import home from "./modules/home/index.ts";
import Main from "./modules/main/index.ts";
import ComponentLoading from "@/components/ComponentLoading";
import Loading from "./modules/loading";
const routes: RouteObject[] = [
{
@@ -23,10 +23,6 @@ const routes: RouteObject[] = [
path: "/register",
Component: (props) => ComponentLoading(Register, props),
},
// {
// path: '/home',
// Component: home,
// },
{
path: "/login",
Component: (props) => ComponentLoading(Login, props),
@@ -35,6 +31,10 @@ const routes: RouteObject[] = [
path: "/main",
Component: (props) => ComponentLoading(Main, props),
},
{
path: "/loading",
Component: (props) => ComponentLoading(Loading, props),
},
];
export default routes;

View File

@@ -0,0 +1,11 @@
/** @format */
import { lazy } from "react";
const loading = lazy(
() =>
new Promise((resolve: any) => {
setTimeout(() => resolve(import("@/components/LoadingPage")), 0);
}),
);
export default loading;

View File

@@ -2,6 +2,7 @@
import axios, { AxiosInstance, AxiosRequestConfig } from "axios";
import { message } from "antd";
import { DecryptData, EncryptData } from "@/utils/encrypt/encrypt.ts";
class Request {
private instance: AxiosInstance | undefined;
@@ -11,6 +12,9 @@ class Request {
// 全局请求拦截
this.instance.interceptors.request.use(
(config) => {
if (config.method == "post") {
config.data = EncryptData(JSON.stringify(config.data));
}
return config;
},
(error) => {
@@ -20,12 +24,16 @@ class Request {
// 全局响应拦截
this.instance.interceptors.response.use(
(res) => {
// if (res.data.code && res.data.code !== 200) {
// message.error(res.data.message).then()
// return Promise.reject(res.data)
// }
return res.data;
(response) => {
// 后端返回字符串表示需要解密操作
if (typeof response.data == "string") {
response.data = DecryptData(response.data);
if (!response.data.code && response.data.code !== 200) {
message.error(response.data.message).then();
return Promise.reject(response.data);
}
}
return response.data;
},
(error) => {
const { response } = error;

View File

@@ -1,173 +1,29 @@
/** @format */
import JSEncrypt from "jsencrypt";
import CryptoJS from "crypto-js";
const key = CryptoJS.enc.Hex.parse("d86d7bab3d6ac01ad9dc6a897652f2d2");
// const iv = CryptoJS.enc.Latin1.parse("d86d7bab3d6ac01ad9dc6a897652f2d2");
// 加密
export function rsaEncrypt(Str: string, afterPublicKey: string) {
const encryptor = new JSEncrypt();
encryptor.setPublicKey(afterPublicKey); // 设置公钥
return encryptor.encrypt(Str); // 对数据进行加密
}
// 解密
export function rsaDecrypt(Str: string, frontPrivateKey: string) {
const encryptor = new JSEncrypt();
encryptor.setPrivateKey(frontPrivateKey); // 设置私钥
return encryptor.decrypt(Str); // 对数据进行解密
}
export function aesEncrypt(aeskey: string, Str: string) {
// 设置一个默认值,如果第二个参数为空采用默认值,不为空则采用新设置的密钥
const key = CryptoJS.enc.Utf8.parse(aeskey);
const srcs = CryptoJS.enc.Utf8.parse(Str);
function EncryptData(data: any) {
const srcs = CryptoJS.enc.Utf8.parse(data);
const encrypted = CryptoJS.AES.encrypt(srcs, key, {
// 切记 需要和后端算法模式一致
mode: CryptoJS.mode.ECB,
padding: CryptoJS.pad.Pkcs7,
});
return encrypted.toString();
}
export function aesDecrypt(aeskey: string, Str: string) {
const key = CryptoJS.enc.Utf8.parse(aeskey);
const decrypt = CryptoJS.AES.decrypt(Str, key, {
// 切记 需要和后端算法模式一致
// 解密
function DecryptData(data: any) {
// const stime = new Date().getTime();
const decrypt = CryptoJS.AES.decrypt(data, key, {
mode: CryptoJS.mode.ECB,
padding: CryptoJS.pad.Pkcs7,
});
return CryptoJS.enc.Utf8.stringify(decrypt).toString();
}
/**
* 获取16位随机码AES
* @returns {string}
*/
export function get16RandomNum() {
const chars = [
"0",
"1",
"2",
"3",
"4",
"5",
"6",
"7",
"8",
"9",
"A",
"B",
"C",
"D",
"E",
"F",
"G",
"H",
"I",
"J",
"K",
"L",
"M",
"N",
"O",
"P",
"Q",
"R",
"S",
"T",
"U",
"V",
"W",
"X",
"Y",
"Z",
"a",
"b",
"c",
"d",
"e",
"f",
"g",
"h",
"i",
"j",
"k",
"l",
"m",
"n",
"o",
"p",
"q",
"r",
"s",
"t",
"u",
"v",
"w",
"x",
"y",
"z",
];
let nums = "";
//这个地方切记要选择16位因为美国对密钥长度有限制选择32位的话加解密会报错需要根据jdk版本去修改相关jar包有点恼火选择16位就不用处理。
for (let i = 0; i < 16; i++) {
const id = parseInt(String(Math.random() * 61));
nums += chars[id];
}
return nums;
}
//获取rsa密钥对
export function getRsaKeys() {
return new Promise((resolve, reject) => {
window.crypto.subtle
.generateKey(
{
name: "RSA-OAEP",
modulusLength: 2048, //can be 1024, 2048, or 4096
publicExponent: new Uint8Array([0x01, 0x00, 0x01]),
hash: { name: "SHA-512" }, //can be "SHA-1", "SHA-256", "SHA-384", or "SHA-512"
},
true, //whether the key is extractable (i.e. can be used in exportKey)
["encrypt", "decrypt"], //must be ["encrypt", "decrypt"] or ["wrapKey", "unwrapKey"]
)
.then(function (key) {
window.crypto.subtle
.exportKey("pkcs8", key.privateKey)
.then(function (keydata1) {
window.crypto.subtle
.exportKey("spki", key.publicKey)
.then(function (keydata2) {
const privateKey = RSA2text(keydata1, 1);
const publicKey = RSA2text(keydata2);
resolve({ privateKey, publicKey });
})
.catch(function (err) {
reject(err);
});
})
.catch(function (err) {
reject(err);
});
})
.catch(function (err) {
reject(err);
});
});
}
function RSA2text(buffer: any, _isPrivate: number = 0) {
let binary = "";
const bytes = new Uint8Array(buffer);
const len = bytes.byteLength;
for (let i = 0; i < len; i++) {
binary += String.fromCharCode(bytes[i]);
}
const base64 = window.btoa(binary);
const text = base64.replace(/[^\x00-\xff]/g, "$&\x01").replace(/.{64}\x01?/g, "$&\n");
return text;
const result = JSON.parse(CryptoJS.enc.Utf8.stringify(decrypt).toString());
// const etime = new Date().getTime();
// console.log("DecryptData Time:" + (etime - stime));
return result;
}
export { EncryptData, DecryptData };

View File

@@ -1,7 +1,7 @@
/** @format */
import { useNavigate } from "react-router-dom";
// import "./index.less";
import "./index.less";
import { useEffect } from "react";
export default () => {
@@ -17,7 +17,6 @@ export default () => {
}, []);
return (
<>
<body translate="no">
<div className="container container-star">
<div className="star-1"></div>
<div className="star-1"></div>
@@ -165,7 +164,6 @@ export default () => {
</button>
</div>
</div>
</body>
</>
);
};

View File

@@ -1,10 +1,8 @@
/** @format */
import { useEffect } from "react";
import MainContainer from "@/components/Home/main-container/MainContainer.tsx";
export default () => {
useEffect(() => {}, []);
return (
<div>
<MainContainer />

View File

@@ -20,6 +20,7 @@ import { observer } from "mobx-react";
import FooterComponent from "@/components/Footer";
import RotateCaptcha, { CaptchaInstance } from "react-rotate-captcha";
import { get, load, verify } from "@/api/captcha/index.ts";
import { oauthLogin } from "@/api/user";
// import useStore from '@/utils/store/useStore.tsx'
type LoginType = "account" | "phone";
@@ -53,6 +54,12 @@ export default observer(() => {
key: "phone",
},
];
async function oAuthLogin(type: string) {
const res: any = await oauthLogin(type);
window.location.href = res.data;
}
const [loginType, setLoginType] = useState<LoginType>("account");
const onSubmit = async (formData: object) => {
@@ -359,6 +366,9 @@ export default observer(() => {
borderRadius: "50%",
}}>
<GitlabOutlined
onClick={() => {
oAuthLogin("GITEE").then();
}}
style={{ ...iconStyles, color: "#FF6A10" }}
/>
</div>