Browse Source

feat: 重定向页面参数解析

BaiLuoYan 3 months ago
parent
commit
e0cced5cdd

+ 1 - 1
src/config/request/encryptionInterceptors.ts

@@ -1,7 +1,7 @@
 import isNil from 'ramda/es/isNil';
 
 import globalConfig from '@/config';
-import { bytesBase64decode } from '@/utils/crypto';
+// import { bytesBase64decode } from '@/utils/crypto';
 import {
     CompressMethod,
     decryptResponsePayload,

+ 3 - 3
src/pages/pricing/useService.ts

@@ -26,12 +26,12 @@ export function useService(): UseServiceReturn {
     const { setUserConfig } = userConfigModel.useModel();
 
     const [plans, setPlans] = useState<Plan[]>([]);
-
     useEffect(() => {
         const userinfo = getToken();
         const expired = (userinfo?.accessExpires ?? 0) - currentUnixTimestamp() <= 0;
-        if (expired) return;
-        if (userinfo?.account?.username) return;
+        if (expired) return;  // 如果 accessToken 过期,什么都不做
+        if (userinfo?.account?.username) return; // 否则,如果用户信息存在,也什么都不做
+        // 请求用户信息
         fetchGetUserConfig({})
             .then((res) => {
                 const data = res?.data;

+ 11 - 10
src/pages/redirect/index.tsx

@@ -2,7 +2,7 @@ import React, { useEffect } from 'react';
 
 import { useNavigate, useSearchParams } from 'react-router-dom';
 
-import { setToken } from '@/utils/authUtils';
+import { removeToken, setToken } from '@/utils/authUtils';
 import { decryptUrlParams } from '@/utils/requestCrypto';
 
 /**
@@ -12,8 +12,10 @@ import { decryptUrlParams } from '@/utils/requestCrypto';
  */
 const decryptRedirectParams = async (
     _encryptedData: string
-): Promise<{ userConfig: API.UserInfo; redirectPath: string } | null> => {
-    return decryptUrlParams<{ userConfig: API.UserInfo; redirectPath: string }>(_encryptedData);
+): Promise<{ accessToken: string; expireTime: number; redirectPath: string } | null> => {
+    return decryptUrlParams<{ accessToken: string; expireTime: number; redirectPath: string }>(
+        _encryptedData
+    );
 };
 
 const Redirect: React.FC = () => {
@@ -22,7 +24,7 @@ const Redirect: React.FC = () => {
 
     useEffect(() => {
         const redirectParam = searchParams.get('d');
-        console.log('redirectParam', redirectParam);
+        console.log('🚀 ~ Redirect ~ redirectParam:', redirectParam);
 
         // 如果没有重定向参数,默认跳转到 home 页
         if (!redirectParam) {
@@ -35,20 +37,19 @@ const Redirect: React.FC = () => {
             try {
                 // 解密重定向参数
                 const decryptedData = await decryptRedirectParams(redirectParam);
-
-                console.log('decryptedData', decryptedData);
-
+                console.log('🚀 ~ handleRedirect ~ decryptedData:', decryptedData);
                 if (!decryptedData) {
                     // 解密失败,跳转到 home 页
                     navigate('/home', { replace: true });
                     return;
                 }
 
-                const { userConfig, redirectPath } = decryptedData;
+                const { accessToken, expireTime, redirectPath } = decryptedData;
 
                 // 保存用户信息到 localStorage
-                if (userConfig) {
-                    setToken(userConfig);
+                if (accessToken) {
+                    removeToken(); // 删除旧的 token
+                    setToken({ accessToken, accessExpires: expireTime }); // 设置新的 token
                 }
 
                 // 跳转到指定路由

+ 26 - 0
src/utils/crypto/base64url.ts

@@ -0,0 +1,26 @@
+function padString(input: string): string {
+    const segmentLength = 4;
+    const diff = input.length % segmentLength;
+    if (!diff) return input;
+    const padLength = segmentLength - diff;
+    return input + '='.repeat(padLength);
+}
+
+/**
+ * 将 Base64URL 字符串转换为 Base64 字符串
+ * @param base64url Base64URL 字符串
+ * @returns Base64 字符串
+ */
+export function toBase64(base64url: string): string {
+    base64url = base64url.toString();
+    return padString(base64url).replace(/\-/g, '+').replace(/_/g, '/');
+}
+
+/**
+ * 将 Base64 字符串转换为 Base64URL 字符串
+ * @param base64 Base64 字符串
+ * @returns Base64URL 字符串
+ */
+export function fromBase64(base64: string): string {
+    return base64.replace(/=/g, '').replace(/\+/g, '-').replace(/\//g, '_');
+}

+ 18 - 11
src/utils/crypto/index.ts

@@ -10,6 +10,7 @@ import MD5 from 'crypto-js/md5';
 import Rabbit from 'crypto-js/rabbit';
 import SHA1 from 'crypto-js/sha1';
 import SHA256 from 'crypto-js/sha256';
+import { toBase64, fromBase64 } from './base64url';
 
 import { bigEndianToLittleEndian, littleEndianToBigEndian } from '@/utils/bytesUtils';
 
@@ -107,11 +108,13 @@ export function bytesSha256(bytes: Uint8Array): Uint8Array {
 }
 
 /**
- * 对字符串进行 Base64 编码
+ * 将字符串编码为 Base64 字符串
  */
-export function stringBase64encode(raw: string): string {
+export function stringBase64encode(raw: string, urlSafe = false): string {
     try {
-        return encBase64.stringify(encUtf8.parse(raw));
+        const out = encBase64.stringify(encUtf8.parse(raw));
+        if (urlSafe) return fromBase64(out);
+        return out;
     } catch {
         return '';
     }
@@ -120,31 +123,35 @@ export function stringBase64encode(raw: string): string {
 /**
  * 对二进制数据进行 Base64 编码
  */
-export function bytesBase64encode(bytes: Uint8Array): string {
+export function bytesBase64encode(bytes: Uint8Array, urlSafe = false): string {
     try {
-        return encBase64.stringify(bytesToWordArray(bytes));
+        const out = encBase64.stringify(bytesToWordArray(bytes));
+        if (urlSafe) return fromBase64(out);
+        return out;
     } catch {
         return '';
     }
 }
 
 /**
- * 对字符串进行 Base64 解码
+ * 将 Base64 字符串解码为字符串
  */
-export function stringBase64decode(str: string): string {
+export function stringBase64decode(str: string, urlSafe = false): string {
     try {
-        return encBase64.parse(str).toString(encUtf8);
+        const input = urlSafe ? toBase64(str) : str;
+        return encBase64.parse(input).toString(encUtf8);
     } catch {
         return '';
     }
 }
 
 /**
- *  Base64 字符串解码为二进制数据
+ *  Base64 字符串解码为二进制数据
  */
-export function bytesBase64decode(str: string): Uint8Array {
+export function bytesBase64decode(str: string, urlSafe = false): Uint8Array {
     try {
-        return wordArrayToBytes(encBase64.parse(str));
+        const input = urlSafe ? toBase64(str) : str;
+        return wordArrayToBytes(encBase64.parse(input));
     } catch {
         return new Uint8Array(0);
     }

+ 1 - 1
src/utils/requestCrypto.ts

@@ -96,7 +96,7 @@ export async function decryptResponsePayload(
 export async function decryptUrlParams<T = any>(params: string): Promise<T | null> {
     // const key = bytesBase64decode(globalConfig.security.requestEncryptionKey);
     const key = stringToBytes(globalConfig.security.requestEncryptionKey);
-    const dataBytes = bytesBase64decode(params);
+    const dataBytes = bytesBase64decode(params, true);
     const compressMethod = globalConfig.security.compressMethod;
     try {
         const { data } = await decryptResponsePayload(dataBytes, key, compressMethod);