Skip to content

Commit

Permalink
feat(desktop): add appToken for providers & fix ssr error (#4566)
Browse files Browse the repository at this point in the history
  • Loading branch information
xudaotutou committed Mar 7, 2024
1 parent b766fb5 commit 8f135d6
Show file tree
Hide file tree
Showing 15 changed files with 73 additions and 141 deletions.
Expand Up @@ -130,8 +130,8 @@ describe('invite member', () => {
role
});
console.log(res);
console.log(ns)
console.log(payload1)
console.log(ns);
console.log(payload1);
expect(res.code).toBe(200);
setAuth(token2);
const res2 = await verifyInviteRequest({ action: reciveAction.Accepte, ns_uid });
Expand Down
4 changes: 3 additions & 1 deletion frontend/desktop/src/api/auth.ts
Expand Up @@ -6,7 +6,9 @@ import { AxiosHeaders, AxiosHeaderValue, type AxiosInstance } from 'axios';
import useSessionStore from '@/stores/session';

export const _getRegionToken = (request: AxiosInstance) => () =>
request.post<any, ApiResp<{ token: string; kubeconfig: string }>>('/api/auth/regionToken');
request.post<any, ApiResp<{ token: string; kubeconfig: string; appToken: string }>>(
'/api/auth/regionToken'
);

export const getRegionToken = _getRegionToken(request);
export const _passwordExistRequest = (request: AxiosInstance) => (data: { user: string }) =>
Expand Down
9 changes: 6 additions & 3 deletions frontend/desktop/src/api/namespace.ts
Expand Up @@ -53,9 +53,12 @@ export const _teamDetailsRequest = (request: AxiosInstance) => (ns_uid: string)
export const _reciveMessageRequest = (request: AxiosInstance) => () =>
request.post<any, ApiResp<{ messages: teamMessageDto[] }>>('/api/auth/namespace/recive');
export const _switchRequest = (request: AxiosInstance) => (ns_uid: string) =>
request.post<any, ApiResp<{ token: string; kubeconfig: string }>>('/api/auth/namespace/switch', {
ns_uid
});
request.post<any, ApiResp<{ token: string; kubeconfig: string; appToken: string }>>(
'/api/auth/namespace/switch',
{
ns_uid
}
);
// 提供给prod/dev环境使用
export const abdicateRequest = _abdicateRequest(request);
export const createRequest = _createRequest(request);
Expand Down
19 changes: 4 additions & 15 deletions frontend/desktop/src/components/account/index.tsx
Expand Up @@ -34,6 +34,7 @@ import { CopyIcon, DownloadIcon, LogoutIcon, RightArrowIcon } from '@sealos/ui';
import { ImageFallBackUrl } from '@/stores/config';
import { jwtDecode } from 'jwt-decode';
import { AccessTokenPayload } from '@/types/token';
import { sessionConfig } from '@/utils/sessionConfig';

const NsMenu = () => {
const { t } = useTranslation();
Expand All @@ -46,21 +47,9 @@ const NsMenu = () => {
mutationFn: switchRequest,
async onSuccess(data) {
if (data.code === 200 && !!data.data) {
setToken(data.data.token);
const payload = jwtDecode<AccessTokenPayload>(data.data.token);
if (session) {
setSession({
...session,
user: {
...session.user,
nsid: payload.workspaceId,
ns_uid: payload.workspaceUid
},
kubeconfig: data.data.kubeconfig
});
} else {
throw Error('session in invalid');
}
await sessionConfig(data.data);
} else {
throw Error('session in invalid');
}
}
});
Expand Down
21 changes: 2 additions & 19 deletions frontend/desktop/src/components/signin/auth/usePassword.tsx
Expand Up @@ -8,6 +8,7 @@ import { useState } from 'react';
import { useForm } from 'react-hook-form';
import { jwtDecode } from 'jwt-decode';
import { AccessTokenPayload } from '@/types/token';
import { sessionConfig } from '@/utils/sessionConfig';

export default function usePassword({
showError
Expand Down Expand Up @@ -53,25 +54,7 @@ export default function usePassword({
inviterId
});
if (!!result?.data) {
const regionUserToken = result.data.token;
setToken(regionUserToken);
const infoData = await UserInfo();
const payload = jwtDecode<AccessTokenPayload>(regionUserToken);
setSession({
token: regionUserToken,
user: {
k8s_username: payload.userCrName,
name: infoData.data?.info.nickname || '',
avatar: infoData.data?.info.avatarUri || '',
nsid: payload.workspaceId,
ns_uid: payload.workspaceUid,
userCrUid: payload.userCrUid,
userUid: payload.userUid,
userId: payload.userId
},
// @ts-ignore
kubeconfig: result.data.kubeconfig
});
await sessionConfig(result.data);
await router.replace('/');
}
return;
Expand Down
20 changes: 2 additions & 18 deletions frontend/desktop/src/components/signin/auth/useSms.tsx
Expand Up @@ -19,6 +19,7 @@ import { getRegionToken, UserInfo } from '@/api/auth';
import { jwtDecode } from 'jwt-decode';
import { uploadConvertData } from '@/api/platform';
import { AccessTokenPayload } from '@/types/token';
import { sessionConfig } from '@/utils/sessionConfig';

export default function useSms({
showError
Expand Down Expand Up @@ -61,24 +62,7 @@ export default function useSms({
setToken(globalToken);
const regionTokenRes = await getRegionToken();
if (regionTokenRes?.data) {
const regionUserToken = regionTokenRes.data.token;
setToken(regionUserToken);
const infoData = await UserInfo();
const payload = jwtDecode<AccessTokenPayload>(regionUserToken);
setSession({
token: regionUserToken,
user: {
k8s_username: payload.userCrName,
name: infoData.data?.info.nickname || '',
avatar: infoData.data?.info.avatarUri || '',
nsid: payload.workspaceId,
ns_uid: payload.workspaceUid,
userCrUid: payload.userCrUid,
userId: payload.userId,
userUid: payload.userUid
},
kubeconfig: regionTokenRes.data.kubeconfig
});
await sessionConfig(regionTokenRes.data);
uploadConvertData([3]).then(
(res) => {
console.log(res);
Expand Down
17 changes: 7 additions & 10 deletions frontend/desktop/src/pages/api/auth/namespace/switch.ts
Expand Up @@ -5,7 +5,7 @@ import { getUserKubeconfig } from '@/services/backend/kubernetes/admin';
import { switchKubeconfigNamespace } from '@/services/backend/kubernetes/user';
import { validate } from 'uuid';
import { JoinStatus } from 'prisma/region/generated/client';
import { generateAccessToken, verifyAccessToken } from '@/services/backend/auth';
import { generateAccessToken, generateAppToken, verifyAccessToken } from '@/services/backend/auth';

export default async function handler(req: NextApiRequest, res: NextApiResponse) {
try {
Expand All @@ -26,30 +26,27 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse)
userCr: true
}
});
const curWorkspaceItem = queryResults.find(
(item) => item.workspace.uid === payload.workspaceUid
);
if (!curWorkspaceItem)
return jsonRes(res, { code: 403, message: 'You are not in this workspace' });
const newWorkspaceItem = queryResults.find((item) => item.workspace.uid === ns_uid);
if (!newWorkspaceItem)
return jsonRes(res, { code: 403, message: 'You are not in this workspace' });
const oldKcRaw = await getUserKubeconfig(payload.userCrUid, payload.userCrName);
if (!oldKcRaw) return jsonRes(res, { code: 404, message: 'The kubeconfig is not found' });
const kubeconfig = switchKubeconfigNamespace(oldKcRaw, newWorkspaceItem.workspace.id);

const token = generateAccessToken({
const jwtPayload = {
workspaceUid: newWorkspaceItem.workspaceUid,
workspaceId: newWorkspaceItem.workspace.id,
regionUid: payload.regionUid,
userCrUid: payload.userCrUid,
userCrName: payload.userCrName,
userId: payload.userId,
userUid: payload.userUid
});
};
const token = generateAccessToken(jwtPayload);
const appToken = generateAppToken(jwtPayload);
const data = {
token,
kubeconfig
kubeconfig,
appToken
};
return jsonRes(res, {
data,
Expand Down
20 changes: 2 additions & 18 deletions frontend/desktop/src/pages/callback.tsx
Expand Up @@ -10,6 +10,7 @@ import { jwtDecode } from 'jwt-decode';
import { isString } from 'lodash';
import { getRegionToken, UserInfo } from '@/api/auth';
import { AccessTokenPayload } from '@/types/token';
import { sessionConfig } from '@/utils/sessionConfig';

const Callback: NextPage = () => {
const router = useRouter();
Expand Down Expand Up @@ -70,24 +71,7 @@ const Callback: NextPage = () => {
setToken(token);
const regionTokenRes = await getRegionToken();
if (regionTokenRes?.data) {
const regionUserToken = regionTokenRes.data.token;
setToken(regionUserToken);
const infoData = await UserInfo();
const payload = jwtDecode<AccessTokenPayload>(regionUserToken);
setSession({
token: regionUserToken,
user: {
k8s_username: payload.userCrName,
name: infoData.data?.info.nickname || '',
avatar: infoData.data?.info.avatarUri || '',
nsid: payload.workspaceId,
ns_uid: payload.workspaceUid,
userCrUid: payload.userCrUid,
userUid: payload.userUid,
userId: payload.userId
},
kubeconfig: regionTokenRes.data.kubeconfig
});
await sessionConfig(regionTokenRes.data);
uploadConvertData([3]).then(
(res) => {
console.log(res);
Expand Down
28 changes: 2 additions & 26 deletions frontend/desktop/src/pages/switchRegion.tsx
Expand Up @@ -8,6 +8,7 @@ import { getRegionToken, UserInfo } from '@/api/auth';
import { isString } from 'lodash';
import { jwtDecode } from 'jwt-decode';
import { AccessTokenPayload } from '@/types/token';
import { sessionConfig } from '@/utils/sessionConfig';

const Callback: NextPage = () => {
const router = useRouter();
Expand All @@ -28,32 +29,7 @@ const Callback: NextPage = () => {
setToken(globalToken);
const regionTokenRes = await getRegionToken();
if (regionTokenRes?.data) {
const regionUserToken = regionTokenRes.data.token;
setToken(regionUserToken);
const infoData = await UserInfo();
const payload = jwtDecode<AccessTokenPayload>(regionUserToken);
setSession({
token: regionUserToken,
user: {
k8s_username: payload.userCrName,
name: infoData.data?.info.nickname || '',
avatar: infoData.data?.info.avatarUri || '',
nsid: payload.workspaceId,
ns_uid: payload.workspaceUid,
userCrUid: payload.userCrUid,
userId: payload.userId,
userUid: payload.userUid
},
kubeconfig: regionTokenRes.data.kubeconfig
});
uploadConvertData([3]).then(
(res) => {
console.log(res);
},
(err) => {
console.log(err);
}
);
await sessionConfig(regionTokenRes.data);
await router.replace('/');
return;
} else {
Expand Down
4 changes: 3 additions & 1 deletion frontend/desktop/src/services/backend/auth.ts
Expand Up @@ -6,6 +6,7 @@ import { getRegionUid } from '@/services/enable';

const jwtSecret = (process.env.JWT_SECRET as string) || '123456789';
const regionJwtSecret = process.env.JWT_SECRET_REGION || '123456789';
const appJwtSecret = process.env.JWT_SECRET_APP || '123456789';
const verifyToken = async <T extends Object>(header: IncomingHttpHeaders) => {
try {
if (!header?.authorization) {
Expand Down Expand Up @@ -60,6 +61,7 @@ export const verifyJWT = <T extends Object = JWTPayload>(token?: string, secret?
});
export const generateAccessToken = (props: AccessTokenPayload) =>
sign(props, jwtSecret, { expiresIn: '7d' });

export const generateAppToken = (props: AccessTokenPayload) =>
sign(props, appJwtSecret, { expiresIn: '7d' });
export const generateAuthenticationToken = (props: AuthenticationTokenPayload) =>
sign(props, regionJwtSecret, { expiresIn: '60000' });
28 changes: 4 additions & 24 deletions frontend/desktop/src/services/backend/regionAuth.ts
Expand Up @@ -6,7 +6,7 @@ import { customAlphabet } from 'nanoid';
import { retrySerially } from '@/utils/tools';
import { AccessTokenPayload } from '@/types/token';
import { JoinStatus, Role } from 'prisma/region/generated/client';
import { generateAccessToken } from '@/services/backend/auth';
import { generateAccessToken, generateAppToken } from '@/services/backend/auth';

const LetterBytes = 'abcdefghijklmnopqrstuvwxyz0123456789';
const HostnameLength = 8;
Expand Down Expand Up @@ -35,6 +35,7 @@ export async function getRegionToken({
}): Promise<{
kubeconfig: string;
token: string;
appToken: string;
}> {
const region = await globalPrisma.region.findUnique({
where: {
Expand Down Expand Up @@ -141,28 +142,7 @@ export async function getRegionToken({

return {
kubeconfig,
token: generateAccessToken(payload)
token: generateAccessToken(payload),
appToken: generateAppToken(payload)
};
}

export function verifyK8sUser({
workspaceUid,
userCrUid
}: {
workspaceUid: string;
userCrUid: string;
}) {
return prisma.userWorkspace
.findUnique({
where: {
workspaceUid_userCrUid: {
userCrUid,
workspaceUid
}
}
})
.then(
(result) => !!result,
() => false
);
}
33 changes: 33 additions & 0 deletions frontend/desktop/src/utils/sessionConfig.ts
@@ -0,0 +1,33 @@
import { UserInfo } from '@/api/auth';
import { jwtDecode } from 'jwt-decode';
import { AccessTokenPayload } from '@/types/token';
import useSessionStore from '@/stores/session';

export const sessionConfig = async ({
token,
kubeconfig,
appToken
}: {
token: string;
kubeconfig: string;
appToken: string;
}) => {
const store = useSessionStore.getState();
store.setToken(token);
const infoData = await UserInfo();
const payload = jwtDecode<AccessTokenPayload>(token);
store.setSession({
token: appToken,
user: {
k8s_username: payload.userCrName,
name: infoData.data?.info.nickname || '',
avatar: infoData.data?.info.avatarUri || '',
nsid: payload.workspaceId,
ns_uid: payload.workspaceUid,
userCrUid: payload.userCrUid,
userId: payload.userId,
userUid: payload.userUid
},
kubeconfig
});
};
1 change: 1 addition & 0 deletions frontend/packages/client-sdk/src/master.ts
Expand Up @@ -60,6 +60,7 @@ class MasterSDK {
avatar: session.user.avatar,
nsid: session.user.nsid
},
token: session.token,
kubeconfig: session.kubeconfig
};
}
Expand Down
4 changes: 1 addition & 3 deletions frontend/packages/client-sdk/src/types/user.d.ts
Expand Up @@ -18,9 +18,7 @@ export type KubeConfig = string;

export type Session = {
token: string; // jwt token
// 提供一些简单的信息
user: UserInfo;
// 帮忙导出用的
kubeconfig: KubeConfig;
};

Expand All @@ -39,7 +37,7 @@ export type UserInfoV1 = Readonly<{
}>;

export type SessionV1 = {
token?: OAuthToken;
token?: string;
user: UserInfoV1;
kubeconfig: KubeConfig;
};
2 changes: 1 addition & 1 deletion frontend/providers/adminer/src/stores/session.ts
@@ -1,9 +1,9 @@
import type { Session } from '@/interfaces/session';
import { sessionKey } from '@/interfaces/session';
import { create } from 'zustand';
import { devtools, persist } from 'zustand/middleware';
import { immer } from 'zustand/middleware/immer';
import * as yaml from 'js-yaml';
import { SessionV1 as Session } from 'sealos-desktop-sdk';

type SessionState = {
session: Session;
Expand Down

0 comments on commit 8f135d6

Please sign in to comment.