setCurrIframe(item)}
@@ -227,7 +207,7 @@ const Dashboard: NextPage
= (props) => {
- {urls.map((item) => renderBottomDockIcon(item))}
+ {urls !== undefined && urls.map((item) => renderBottomDockIcon(item))}
diff --git a/desktop/frontend/src/pages/index.tsx b/desktop/frontend/src/pages/index.tsx
index fc4bdc1df..ad259ffeb 100755
--- a/desktop/frontend/src/pages/index.tsx
+++ b/desktop/frontend/src/pages/index.tsx
@@ -37,7 +37,7 @@ const Home: NextPage = () => {
Discover sealos in open source world!
-
+
Login & Register →
Instantly deploy your Next.js site to a public URL with Vercel.
diff --git a/desktop/frontend/src/pages/login/callback.tsx b/desktop/frontend/src/pages/login/callback.tsx
index b9bbb8d54..33d741e15 100644
--- a/desktop/frontend/src/pages/login/callback.tsx
+++ b/desktop/frontend/src/pages/login/callback.tsx
@@ -2,12 +2,14 @@ import type { NextPage } from 'next';
import Link from 'next/link';
import { useRouter } from 'next/router';
import { useEffect, useState } from 'react';
-import { fetchPost } from '../../lib/api';
-import { OAuthToken, Session, setSession, UserInfo } from '../../store/session';
+import { fetchGet, fetchPost } from '../../lib/client_api';
+import { setSession } from '../../stores/session';
+import { KubeConfig, OAuthToken, Session, UserInfo } from '../../interfaces/session';
const Callback: NextPage = () => {
const [otoken, setOToken] = useState(null);
const [uinfo, setUInfo] = useState(null);
+ const [kconfig, setKConfig] = useState(null);
const [redirect, setRedirect] = useState('');
const router = useRouter();
@@ -16,40 +18,50 @@ const Callback: NextPage = () => {
if (!router.isReady) return;
const { code, state } = router.query;
- if (code !== undefined && code !== '' && state !== undefined && state != '') {
- fetchPost('api/token', { code: code, state: state })
- .then((token) => {
- console.log(token);
- setOToken(JSON.stringify(token));
+ if (code === undefined || code === '' || state === undefined || state === '') return;
- const oauth_token = token as OAuthToken;
- if (oauth_token.access_token !== '') {
- fetchPost(
- 'api/userinfo',
- { code: code, state: state },
- { authorization: 'Bearer ' + oauth_token.access_token }
- )
- .then((userinfo) => {
- console.log(userinfo);
- setUInfo(JSON.stringify(userinfo));
+ fetchPost('auth/token', { code: code, state: state })
+ .then((token) => {
+ console.log('token', token);
+ const oauth_token = token as OAuthToken;
+ if (oauth_token.access_token === '') return;
- const user_info = userinfo as UserInfo;
- if (user_info.id !== '') {
- const session: Session = { token: oauth_token, user: user_info };
- setSession(session);
-
- setRedirect('/dashboard');
- }
- })
- .catch((err) => {
- console.log(err);
- });
- }
+ fetchGet('auth/userinfo', undefined, {
+ authorization: 'Bearer ' + oauth_token.access_token
})
- .catch((err) => {
- console.log(err);
- });
- }
+ .then((userinfo) => {
+ console.log('userinfo', userinfo);
+
+ const user_info = userinfo as UserInfo;
+ if (user_info.id === '') return;
+
+ fetchGet('auth/kubeconfig', undefined, {
+ authorization: 'Bearer ' + oauth_token.access_token
+ })
+ .then((kubeconfig) => {
+ console.log('kubeconfig', kubeconfig);
+
+ const kube_config = kubeconfig as string;
+ if (kube_config === '') return;
+
+ setOToken(JSON.stringify(oauth_token));
+ setUInfo(JSON.stringify(user_info));
+ setKConfig(kube_config);
+
+ const session: Session = {
+ token: oauth_token,
+ user: user_info,
+ kubeconfig: kube_config
+ };
+ setSession(session);
+
+ setRedirect('/dashboard');
+ })
+ .catch((err) => console.log(err));
+ })
+ .catch((err) => console.log(err));
+ })
+ .catch((err) => console.log(err));
}, [router.isReady]);
useEffect(() => {
@@ -57,7 +69,7 @@ const Callback: NextPage = () => {
const timer = setTimeout(() => {
router.replace('/dashboard');
- }, 5000);
+ }, 3000);
return () => clearTimeout(timer);
}, [redirect]);
diff --git a/desktop/frontend/src/pages/login/index.tsx b/desktop/frontend/src/pages/login/index.tsx
index 15a332f0f..598745715 100644
--- a/desktop/frontend/src/pages/login/index.tsx
+++ b/desktop/frontend/src/pages/login/index.tsx
@@ -1,9 +1,9 @@
import type { GetServerSideProps, NextPage } from 'next';
-import { isUserLogin } from '../../store/session';
+import { isUserLogin } from '../../stores/session';
export const getServerSideProps: GetServerSideProps = async (context) => {
const is_login = isUserLogin();
- let destination = '/api/login';
+ let destination = process.env.NEXT_PUBLIC_API_HOST + 'auth/login';
if (is_login) {
destination = '/dashboard';
}
diff --git a/desktop/frontend/src/store/session.ts b/desktop/frontend/src/stores/session.ts
similarity index 64%
rename from desktop/frontend/src/store/session.ts
rename to desktop/frontend/src/stores/session.ts
index b2035bdf5..a4d839269 100644
--- a/desktop/frontend/src/store/session.ts
+++ b/desktop/frontend/src/stores/session.ts
@@ -1,20 +1,4 @@
-export type OAuthToken = {
- readonly access_token: string;
- readonly token_type: string;
- readonly refresh_token: string;
- readonly expiry: string;
-};
-
-export type UserInfo = {
- readonly id: string;
- readonly name: string;
- readonly avatar: string;
-};
-
-export type Session = {
- readonly token: OAuthToken;
- readonly user: UserInfo;
-};
+import { Session, OAuthToken, UserInfo } from '../interfaces/session';
let session: Session | undefined;
diff --git a/desktop/frontend/tsconfig.json b/desktop/frontend/tsconfig.json
index 99710e857..c1e94dd70 100755
--- a/desktop/frontend/tsconfig.json
+++ b/desktop/frontend/tsconfig.json
@@ -1,7 +1,11 @@
{
"compilerOptions": {
"target": "es5",
- "lib": ["dom", "dom.iterable", "esnext"],
+ "lib": [
+ "dom",
+ "dom.iterable",
+ "esnext"
+ ],
"allowJs": true,
"skipLibCheck": true,
"strict": true,
@@ -15,6 +19,12 @@
"jsx": "preserve",
"incremental": true
},
- "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx"],
- "exclude": ["node_modules"]
-}
+ "include": [
+ "next-env.d.ts",
+ "**/*.ts",
+ "**/*.tsx"
+ ],
+ "exclude": [
+ "node_modules"
+ ]
+}
\ No newline at end of file
diff --git a/pkg/auth/utils/config.go b/pkg/auth/utils/config.go
index d4f5b68d4..a8a7fc4b4 100644
--- a/pkg/auth/utils/config.go
+++ b/pkg/auth/utils/config.go
@@ -118,7 +118,8 @@ func GenerateKubeConfig(username string) (string, error) {
if err != nil {
return "", err
}
- config := &api.Config{
+
+ config := api.Config{
Clusters: map[string]*api.Cluster{
"kubernetes": {
Server: "https://apiserver.cluster.local:6443",
@@ -139,7 +140,7 @@ func GenerateKubeConfig(username string) (string, error) {
CurrentContext: ctx,
}
- content, err := clientcmd.Write(*config)
+ content, err := clientcmd.Write(config)
if err != nil {
return "", fmt.Errorf("write kubeconfig failed %s", err)
}
diff --git a/pkg/utils/httpserver/cors.go b/pkg/utils/httpserver/cors.go
index 104f3022d..0d1b65429 100644
--- a/pkg/utils/httpserver/cors.go
+++ b/pkg/utils/httpserver/cors.go
@@ -21,7 +21,7 @@ func Cors(wsContainer *restful.Container) {
// Add container filter to enable CORS
cors := restful.CrossOriginResourceSharing{
// ExposeHeaders: []string{"X-My-Header"},
- AllowedHeaders: []string{"Content-Type", "Accept"},
+ AllowedHeaders: []string{"Content-Type", "Accept", "Authorization"},
AllowedMethods: []string{"GET", "POST", "PUT", "DELETE"},
CookiesAllowed: true,
Container: wsContainer}
diff --git a/pkg/utils/httpserver/response.go b/pkg/utils/httpserver/response.go
new file mode 100644
index 000000000..0bb65ae5d
--- /dev/null
+++ b/pkg/utils/httpserver/response.go
@@ -0,0 +1,64 @@
+// Copyright © 2022 sealos.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package httpserver
+
+import (
+ "net/http"
+
+ restful "github.com/emicklei/go-restful/v3"
+)
+
+type Response struct {
+ Code int `json:"code"`
+ Message string `json:"message"`
+ Data interface{} `json:"data,omitempty"`
+}
+
+// RespError write error to response
+func RespError(resp *restful.Response, err error) error {
+ // Set response status code
+ code := http.StatusInternalServerError
+
+ // String error
+ message := err.Error()
+
+ if message == "not found" || len(message) > 7 && message[:7] == "Unknown" {
+ code = http.StatusNotFound
+ } else if message == "unauthorized" || len(message) > 14 && message[:14] == "not authorized" {
+ code = http.StatusUnauthorized
+ }
+
+ // Write error response
+ return resp.WriteHeaderAndEntity(code, &Response{
+ Code: code,
+ Message: message,
+ })
+}
+
+// RespRedirect redirect url
+func RespRedirect(resp *restful.Response, redirectURL string) {
+ resp.Header().Set("Location", redirectURL)
+ resp.WriteHeader(http.StatusTemporaryRedirect)
+}
+
+// RespData write error to response
+func RespData(resp *restful.Response, data any) error {
+ // Write error response
+ return resp.WriteHeaderAndEntity(http.StatusOK, &Response{
+ Code: http.StatusOK,
+ Message: "",
+ Data: data,
+ })
+}
diff --git a/service/auth/api/api.go b/service/auth/api/api.go
index 5ad2157c8..f90bb88c3 100644
--- a/service/auth/api/api.go
+++ b/service/auth/api/api.go
@@ -15,10 +15,12 @@
package api
import (
+ "errors"
+
restful "github.com/emicklei/go-restful/v3"
"github.com/labring/sealos/pkg/auth"
- "github.com/labring/sealos/pkg/utils/httpserver"
+ hs "github.com/labring/sealos/pkg/utils/httpserver"
)
// RegisterRouter Register auth Router
@@ -31,61 +33,66 @@ func RegisterRouter(webService *restful.WebService) {
// SSO callback, get token
webService.Route(webService.POST("/token").To(handlerToken))
// return user info
- webService.Route(webService.POST("/userinfo").To(handlerUserInfo))
+ webService.Route(webService.GET("/userinfo").To(handlerUserInfo))
// generate kubeconfig according to user info
- webService.Route(webService.POST("/kubeconfig").To(handlerKubeConfig))
+ webService.Route(webService.GET("/kubeconfig").To(handlerKubeConfig))
}
func handlerLogin(_ *restful.Request, response *restful.Response) {
redirectURL, err := auth.GetLoginRedirect()
if err != nil {
- _ = response.WriteError(500, err)
+ _ = hs.RespError(response, err)
return
}
- response.Header().Set("Location", redirectURL)
- response.WriteHeader(302)
+ hs.RespRedirect(response, redirectURL)
}
func handlerToken(request *restful.Request, response *restful.Response) {
cs := &codeState{}
if err := request.ReadEntity(&cs); err != nil {
- _ = response.WriteError(500, err)
+ _ = hs.RespError(response, err)
return
}
if cs.State == "" || cs.Code == "" {
- _ = response.WriteError(500, nil)
+ _ = hs.RespError(response, errors.New("state or code is empty"))
return
}
oauthToken, err := auth.GetOAuthToken(cs.State, cs.Code)
if err != nil {
- _ = response.WriteError(500, err)
+ _ = hs.RespError(response, err)
return
}
- _ = response.WriteEntity(oauthToken)
+ _ = hs.RespData(response, oauthToken)
}
func handlerUserInfo(request *restful.Request, response *restful.Response) {
- accessToken := httpserver.GetAccessToken(request)
+ accessToken := hs.GetAccessToken(request)
+ if accessToken == "" {
+ _ = hs.RespError(response, errors.New("access token is empty"))
+ return
+ }
userInfo, err := auth.GetUserInfo(accessToken)
if err != nil {
- _ = response.WriteError(500, err)
+ _ = hs.RespError(response, err)
return
}
- _ = response.WriteEntity(userInfo)
+ _ = hs.RespData(response, userInfo)
}
func handlerKubeConfig(request *restful.Request, response *restful.Response) {
- accessToken := httpserver.GetAccessToken(request)
+ accessToken := hs.GetAccessToken(request)
+ if accessToken == "" {
+ _ = hs.RespError(response, errors.New("access token is empty"))
+ return
+ }
kubeConfig, err := auth.GetKubeConfig(accessToken)
if err != nil {
- _ = response.WriteError(500, err)
+ _ = hs.RespError(response, err)
return
}
- _ = response.WriteEntity(map[string]string{
- "config": kubeConfig,
- })
+ _ = hs.RespData(response, kubeConfig)
}