Переглянути джерело

feat: 增加单点登录校验

wanghongkai 6 роки тому
батько
коміт
fcb70aff31

+ 3 - 1
package.json

@@ -1,6 +1,6 @@
 {
   "name": "seec-frontend",
-  "version": "0.1.0",
+  "version": "0.2.0",
   "private": true,
   "scripts": {
     "serve": "vue-cli-service serve",
@@ -12,11 +12,13 @@
   },
   "dependencies": {
     "@gitgraph/js": "^1.3.3",
+    "base64url": "^3.0.1",
     "buefy": "^0.7.1",
     "chart.js": "^2.7.3",
     "dayjs": "^1.7.8",
     "file-saver": "^2.0.1",
     "highlight.js": "^9.15.6",
+    "js-cookie": "^2.2.1",
     "marked": "^0.6.2",
     "register-service-worker": "^1.5.2",
     "vue": "^2.5.17",

+ 16 - 2
src/util/profileStorage.js

@@ -1,3 +1,6 @@
+import Cookies from "js-cookie";
+import base64url from "base64url";
+
 const USER_PROFILE = "user_profile";
 
 /**
@@ -17,8 +20,17 @@ export const getUserProfile = () => {
   let profile = {};
   try {
     profile = JSON.parse(profileText);
+    if (profile == null) {
+      profile = JSON.parse(base64url.decode(Cookies.get("user")));
+      saveProfile(profile);
+    }
   } catch (e) {
-    return null;
+    try {
+      profile = JSON.parse(base64url.decode(Cookies.get("user")));
+      saveProfile(profile);
+    } catch (e) {
+      return null;
+    }
   }
   return profile;
 };
@@ -26,5 +38,7 @@ export const getUserProfile = () => {
 /**
  * 删除profile
  */
-export const destroyProfile = () =>
+export const destroyProfile = () => {
+  Cookies.remove("user");
   window.localStorage.removeItem(USER_PROFILE);
+};

+ 16 - 5
src/util/request.js

@@ -1,8 +1,10 @@
 // ant-design-pro request.js file with MIT license
 import "whatwg-fetch";
-import router from "@/router";
-import { LOGIN } from "@/router/name";
-import { getToken } from "@/util/tokenStorage";
+// import router from "@/router";
+// import { LOGIN } from "@/router/name";
+import Vue from "vue";
+import { getToken, destroyToken } from "@/util/tokenStorage";
+import { destroyProfile } from "@/util/profileStorage";
 
 /**
  * @description error
@@ -46,7 +48,7 @@ const checkStatus = async response => {
  */
 export default async function request(url, options) {
   const defaultOptions = {
-    credentials: "include"
+    // credentials: "include"
   };
   const newOptions = { ...defaultOptions, ...options };
   if (
@@ -81,7 +83,16 @@ export default async function request(url, options) {
     await checkStatus(response);
   } catch (e) {
     if (e.name === 401) {
-      router.push({ name: LOGIN });
+      destroyToken();
+      destroyProfile();
+      if (e.body && e.body.redirect) {
+        Vue.prototype.$toast.open({
+          message: e.body.msg || "服务器未知错误",
+          type: "is-danger"
+        });
+        window.location = e.body.redirect;
+      }
+      // router.push({ name: LOGIN });
     } else {
       throw e;
     }

+ 15 - 4
src/util/tokenStorage.js

@@ -1,3 +1,5 @@
+import Cookies from "js-cookie";
+
 const ID_TOKEN_KEY = "id_token";
 
 /**
@@ -5,9 +7,15 @@ const ID_TOKEN_KEY = "id_token";
  * @return {string|null} token
  */
 export const getToken = () => {
-  const token = window.localStorage.getItem(ID_TOKEN_KEY);
-  if (token === "undefined") {
-    return null;
+  let token = window.localStorage.getItem(ID_TOKEN_KEY);
+  if (token == null) {
+    token = Cookies.get("token");
+    if (token == null) {
+      return null;
+    } else {
+      saveToken(token);
+      return token;
+    }
   } else {
     return token;
   }
@@ -16,4 +24,7 @@ export const getToken = () => {
 export const saveToken = token =>
   token && window.localStorage.setItem(ID_TOKEN_KEY, token);
 
-export const destroyToken = () => window.localStorage.removeItem(ID_TOKEN_KEY);
+export const destroyToken = () => {
+  Cookies.remove("token");
+  window.localStorage.removeItem(ID_TOKEN_KEY);
+};

+ 30 - 26
src/views/login/Login.vue

@@ -1,7 +1,7 @@
 <template>
   <div>
     <div class="intro">登录</div>
-    <b-notification type="is-danger" :active.sync="isServerError">
+    <!-- <b-notification type="is-danger" :active.sync="isServerError">
       {{ errorMassage }}
     </b-notification>
     <b-field
@@ -28,7 +28,7 @@
         password-reveal
       >
       </b-input>
-    </b-field>
+    </b-field> -->
     <!--<p class="control level" style="padding-top: 20px">-->
     <div style="padding-top: 40px;">
       <button
@@ -54,10 +54,11 @@
 
 <script>
 import { required, email } from "vuelidate/lib/validators";
-import { login } from "@/api/auth";
-import { SET_PROFILE } from "@/store/type/mutations.type";
-import { destroyToken, saveToken } from "@/util/tokenStorage";
-import { HOME } from "@/router/name";
+// import { login } from "@/api/auth";
+// import { SET_PROFILE } from "@/store/type/mutations.type";
+// import { destroyToken, saveToken } from "@/util/tokenStorage";
+// import { HOME } from "@/router/name";
+import { destroyToken } from "@/util/tokenStorage";
 
 export default {
   data() {
@@ -83,27 +84,30 @@ export default {
   },
   methods: {
     async loginAction() {
-      if (this.submitting) return;
+      window.location = `http://p.seecoder.cn/api/interaction?scope=openid&client_id=seec-seec&redirect_uri=${encodeURI(
+        "http://seec.seecoder.cn/api/auth/receive"
+      )}`;
+      // if (this.submitting) return;
 
-      this.isServerError = false;
-      this.$v.$touch();
-      if (!this.$v.$invalid) {
-        const { username = "", password = "" } = this;
-        try {
-          this.submitting = true;
-          const {
-            data,
-            _header: { Authorization }
-          } = await login({ username, password });
-          saveToken(Authorization);
-          this.$store.commit(SET_PROFILE, data);
-          this.$router.push({ name: HOME });
-        } catch (e) {
-          this.errorMassage = e.message || "登录失败";
-          this.isServerError = true;
-          this.submitting = false;
-        }
-      }
+      // this.isServerError = false;
+      // this.$v.$touch();
+      // if (!this.$v.$invalid) {
+      //   const { username = "", password = "" } = this;
+      //   try {
+      //     this.submitting = true;
+      //     const {
+      //       data,
+      //       _header: { Authorization }
+      //     } = await login({ username, password });
+      //     saveToken(Authorization);
+      //     this.$store.commit(SET_PROFILE, data);
+      //     this.$router.push({ name: HOME });
+      //   } catch (e) {
+      //     this.errorMassage = e.message || "登录失败";
+      //     this.isServerError = true;
+      //     this.submitting = false;
+      //   }
+      // }
     }
   }
 };

+ 26 - 25
src/views/login/Register.vue

@@ -1,7 +1,7 @@
 <template>
   <div>
     <div class="intro">注册</div>
-    <b-notification type="is-danger" :active.sync="isServerError">
+    <!-- <b-notification type="is-danger" :active.sync="isServerError">
       {{ errorMassage }}
     </b-notification>
     <b-field
@@ -66,7 +66,7 @@
         password-reveal
       >
       </b-input>
-    </b-field>
+    </b-field> -->
     <div style="padding-top: 20px;">
       <button
         :class="{ 'is-loading': submitting }"
@@ -96,8 +96,8 @@ import {
   email,
   sameAs
 } from "vuelidate/lib/validators";
-import { register } from "@/api/auth";
-import { LOGIN } from "@/router/name";
+// import { register } from "@/api/auth";
+// import { LOGIN } from "@/router/name";
 
 export default {
   data() {
@@ -133,28 +133,29 @@ export default {
   },
   methods: {
     async registerAction() {
-      if (this.submitting) return;
+      window.location = "http://p.seecoder.cn/register";
+      // if (this.submitting) return;
 
-      this.isServerError = false;
-      this.$v.$touch();
-      if (!this.$v.$invalid) {
-        this.submitting = true;
-        const { username = "", password = "", nickname = null } = this;
-        try {
-          await register({ username, password, nickname });
-          this.$toast.open({
-            message: `用户「${
-              nickname === null ? username : nickname
-            }」注册成功`,
-            type: "is-success"
-          });
-          this.$router.push({ name: LOGIN });
-        } catch (e) {
-          this.errorMassage = e.message;
-          this.isServerError = true;
-          this.submitting = false;
-        }
-      }
+      // this.isServerError = false;
+      // this.$v.$touch();
+      // if (!this.$v.$invalid) {
+      //   this.submitting = true;
+      //   const { username = "", password = "", nickname = null } = this;
+      //   try {
+      //     await register({ username, password, nickname });
+      //     this.$toast.open({
+      //       message: `用户「${
+      //         nickname === null ? username : nickname
+      //       }」注册成功`,
+      //       type: "is-success"
+      //     });
+      //     this.$router.push({ name: LOGIN });
+      //   } catch (e) {
+      //     this.errorMassage = e.message;
+      //     this.isServerError = true;
+      //     this.submitting = false;
+      //   }
+      // }
     }
   }
 };

+ 4 - 3
vue.config.js

@@ -6,12 +6,13 @@ module.exports = {
         // target: "http://10.1.1.198:8080/",
         // target: "http://192.168.0.100:8080",
         // target: "http://seec.yangshan.tech",
-        target: "http://seec.seecoder.cn",
-
+        // target: "http://seec.seecoder.cn",
+        target: "http://localhost:8080",
         ws: true,
         changeOrigin: true
       }
-    }
+    },
+    disableHostCheck: true
   },
   configureWebpack: {
     devtool: "source-map"