This is an automated email from the ASF dual-hosted git repository.

casion pushed a commit to branch dev-1.8.0
in repository https://gitbox.apache.org/repos/asf/linkis.git


The following commit(s) were added to refs/heads/dev-1.8.0 by this push:
     new 7d58d354f6 Add OAuth2 authentication support (#5253)
7d58d354f6 is described below

commit 7d58d354f62bf6edf7418d4354a1a625efd62c89
Author: Kazuto Iris <[email protected]>
AuthorDate: Sun Sep 28 13:39:32 2025 +0800

    Add OAuth2 authentication support (#5253)
    
    * feat(mg-gateway): add OAuth2 authentication support
    
    - Add OAuth2 authentication configuration to GatewayConfiguration
    - Implement OAuth2Authentication
    - Update `SecurityFilter` and `UserRestful` to process OAuth2 request
    
    Signed-off-by: kazutoiris <[email protected]>
    
    * feat(mg-gateway): add OAuth configuration
    
    - Add OAuth-related properties to `linkis-mg-gateway.properties`
    - Include support for GitHub OAuth as an example
    
    Signed-off-by: kazutoiris <[email protected]>
    
    * style: reformat code
    
    Signed-off-by: kazutoiris <[email protected]>
    
    * feat(mg-gateway): add OAuth in frontend
    
    - Add OAuth login option to the login page
    - Implement OAuth callback route and component
    - Add translations for OAuth login text
    
    Signed-off-by: kazutoiris <[email protected]>
    
    * docs: add OAuth authentication documentation
    
    ---------
    
    Signed-off-by: kazutoiris <[email protected]>
---
 docs/configuration/linkis-gateway-core.md          |   8 +
 .../package/conf/linkis-mg-gateway.properties      |   9 +
 .../gateway/config/GatewayConfiguration.scala      |   9 +
 .../linkis/gateway/security/SecurityFilter.scala   |   3 +
 .../linkis/gateway/security/UserRestful.scala      |  15 +
 .../security/oauth/OAuth2Authentication.scala      | 340 +++++++++++++++++++++
 linkis-web/src/common/i18n/en.json                 |   1 +
 linkis-web/src/common/i18n/zh.json                 |   1 +
 linkis-web/src/dss/router.js                       |  10 +
 linkis-web/src/dss/view/login/index.vue            |  21 +-
 linkis-web/src/dss/view/login/oauthCallback.vue    |  55 ++++
 11 files changed, 471 insertions(+), 1 deletion(-)

diff --git a/docs/configuration/linkis-gateway-core.md 
b/docs/configuration/linkis-gateway-core.md
index be933b2a26..5a4f55a3d1 100644
--- a/docs/configuration/linkis-gateway-core.md
+++ b/docs/configuration/linkis-gateway-core.md
@@ -36,3 +36,11 @@
 |linkis-gateway-core|wds.linkis.gateway.this.schema|   | gateway.this.schema|
 |linkis-gateway-core|wds.linkis.web.enable.water.mark|true| 
web.enable.water.mark|
 |linkis-gateway-core|wds.linkis.entrance.name|   |linkis.entrance.name|
+|linkis-gateway-core|wds.linkis.gateway.conf.enable.oauth.auth| false  
|wds.linkis.gateway.conf.enable.oauth.auth|
+|linkis-gateway-core|wds.linkis.gateway.auth.oauth.authentication.url|  
|wds.linkis.gateway.auth.oauth.authentication.url|
+|linkis-gateway-core|wds.linkis.gateway.auth.oauth.exchange.url|  
|wds.linkis.gateway.auth.oauth.exchange.url|
+|linkis-gateway-core|wds.linkis.gateway.auth.oauth.validate.url|  
|wds.linkis.gateway.auth.oauth.validate.url|
+|linkis-gateway-core|wds.linkis.gateway.auth.oauth.validate.field|  
|wds.linkis.gateway.auth.oauth.validate.field|
+|linkis-gateway-core|wds.linkis.gateway.auth.oauth.client.id|  
|wds.linkis.gateway.auth.oauth.client.id|
+|linkis-gateway-core|wds.linkis.gateway.auth.oauth.client.secret|  
|wds.linkis.gateway.auth.oauth.client.secret|
+|linkis-gateway-core|wds.linkis.gateway.auth.oauth.scope|  
|wds.linkis.gateway.auth.oauth.scope|
diff --git a/linkis-dist/package/conf/linkis-mg-gateway.properties 
b/linkis-dist/package/conf/linkis-mg-gateway.properties
index 1f1d2416b4..0e4275677c 100644
--- a/linkis-dist/package/conf/linkis-mg-gateway.properties
+++ b/linkis-dist/package/conf/linkis-mg-gateway.properties
@@ -30,6 +30,15 @@ wds.linkis.ldap.proxy.baseDN=
 wds.linkis.ldap.proxy.userNameFormat=
 wds.linkis.admin.user=hadoop
 #wds.linkis.admin.password=
+##OAuth
+wds.linkis.oauth.enable=false
+wds.linkis.oauth.url=https://github.com/login/oauth/authorize
+wds.linkis.gateway.auth.oauth.exchange.url=https://github.com/login/oauth/access_token
+wds.linkis.gateway.auth.oauth.validate.url=https://api.github.com/user
+wds.linkis.gateway.auth.oauth.validate.field=login
+wds.linkis.gateway.auth.oauth.client.id=YOUR_CLIENT_ID
+wds.linkis.gateway.auth.oauth.client.secret=YOUR_CLIENT_SECRET
+wds.linkis.gateway.auth.oauth.scope=user
 ##Spring
 spring.server.port=9001
 
diff --git 
a/linkis-spring-cloud-services/linkis-service-gateway/linkis-gateway-core/src/main/scala/org/apache/linkis/gateway/config/GatewayConfiguration.scala
 
b/linkis-spring-cloud-services/linkis-service-gateway/linkis-gateway-core/src/main/scala/org/apache/linkis/gateway/config/GatewayConfiguration.scala
index 5fc80d7afc..ccb7325b57 100644
--- 
a/linkis-spring-cloud-services/linkis-service-gateway/linkis-gateway-core/src/main/scala/org/apache/linkis/gateway/config/GatewayConfiguration.scala
+++ 
b/linkis-spring-cloud-services/linkis-service-gateway/linkis-gateway-core/src/main/scala/org/apache/linkis/gateway/config/GatewayConfiguration.scala
@@ -42,6 +42,15 @@ object GatewayConfiguration {
   val TOKEN_AUTHENTICATION_SCAN_INTERVAL =
     CommonVars("wds.linkis.gateway.conf.token.auth.scan.interval", 1000 * 60 * 
10)
 
+  val ENABLE_OAUTH_AUTHENTICATION = 
CommonVars("wds.linkis.gateway.conf.enable.oauth.auth", false)
+  val OAUTH_AUTHENTICATION_URL = 
CommonVars("wds.linkis.gateway.auth.oauth.authentication.url", "")
+  val OAUTH_EXCHANGE_URL = 
CommonVars("wds.linkis.gateway.auth.oauth.exchange.url", "")
+  val OAUTH_VALIDATE_URL = 
CommonVars("wds.linkis.gateway.auth.oauth.validate.url", "")
+  val OAUTH_VALIDATE_FIELD = 
CommonVars("wds.linkis.gateway.auth.oauth.validate.field", "")
+  val OAUTH_CLIENT_ID = CommonVars("wds.linkis.gateway.auth.oauth.client.id", 
"")
+  val OAUTH_CLIENT_SECRET = 
CommonVars("wds.linkis.gateway.auth.oauth.client.secret", "")
+  val OAUTH_SCOPE = CommonVars("wds.linkis.gateway.auth.oauth.scope", "")
+
   val PASS_AUTH_REQUEST_URI =
     CommonVars("wds.linkis.gateway.conf.url.pass.auth", 
"/dws/").getValue.split(",")
 
diff --git 
a/linkis-spring-cloud-services/linkis-service-gateway/linkis-gateway-core/src/main/scala/org/apache/linkis/gateway/security/SecurityFilter.scala
 
b/linkis-spring-cloud-services/linkis-service-gateway/linkis-gateway-core/src/main/scala/org/apache/linkis/gateway/security/SecurityFilter.scala
index 150ae565ef..9f170e9dd2 100644
--- 
a/linkis-spring-cloud-services/linkis-service-gateway/linkis-gateway-core/src/main/scala/org/apache/linkis/gateway/security/SecurityFilter.scala
+++ 
b/linkis-spring-cloud-services/linkis-service-gateway/linkis-gateway-core/src/main/scala/org/apache/linkis/gateway/security/SecurityFilter.scala
@@ -23,6 +23,7 @@ import org.apache.linkis.common.utils.{Logging, Utils}
 import org.apache.linkis.gateway.config.GatewayConfiguration
 import org.apache.linkis.gateway.config.GatewayConfiguration._
 import org.apache.linkis.gateway.http.GatewayContext
+import org.apache.linkis.gateway.security.oauth.OAuth2Authentication
 import org.apache.linkis.gateway.security.sso.SSOInterceptor
 import org.apache.linkis.gateway.security.token.TokenAuthentication
 import org.apache.linkis.server.{validateFailed, Message}
@@ -127,6 +128,8 @@ object SecurityFilter extends Logging {
       logger.info("No login needed for proxy uri: " + 
gatewayContext.getRequest.getRequestURI)
     } else if (TokenAuthentication.isTokenRequest(gatewayContext)) {
       TokenAuthentication.tokenAuth(gatewayContext)
+    } else if (OAuth2Authentication.isOAuth2Request(gatewayContext)) {
+      OAuth2Authentication.OAuth2Entry(gatewayContext)
     } else {
       val userName = 
Utils.tryCatch(GatewaySSOUtils.getLoginUser(gatewayContext)) {
         case n @ (_: NonLoginException | _: LoginExpireException) =>
diff --git 
a/linkis-spring-cloud-services/linkis-service-gateway/linkis-gateway-core/src/main/scala/org/apache/linkis/gateway/security/UserRestful.scala
 
b/linkis-spring-cloud-services/linkis-service-gateway/linkis-gateway-core/src/main/scala/org/apache/linkis/gateway/security/UserRestful.scala
index 38d06b6b17..e79296c564 100644
--- 
a/linkis-spring-cloud-services/linkis-service-gateway/linkis-gateway-core/src/main/scala/org/apache/linkis/gateway/security/UserRestful.scala
+++ 
b/linkis-spring-cloud-services/linkis-service-gateway/linkis-gateway-core/src/main/scala/org/apache/linkis/gateway/security/UserRestful.scala
@@ -20,6 +20,7 @@ package org.apache.linkis.gateway.security
 import org.apache.linkis.common.utils.{Logging, RSAUtils, Utils}
 import org.apache.linkis.gateway.config.GatewayConfiguration
 import org.apache.linkis.gateway.http.GatewayContext
+import org.apache.linkis.gateway.security.oauth.OAuth2Authentication
 import org.apache.linkis.gateway.security.sso.SSOInterceptor
 import org.apache.linkis.gateway.security.token.TokenAuthentication
 import org.apache.linkis.protocol.usercontrol.{
@@ -87,6 +88,20 @@ abstract class AbstractUserRestful extends UserRestful with 
Logging {
           TokenAuthentication.tokenAuth(gatewayContext, true)
           return
         }
+      case "oauth-login" =>
+        Utils.tryCatch {
+          val loginUser = GatewaySSOUtils.getLoginUsername(gatewayContext)
+          Message
+            .ok(loginUser + " already logged in, please log out before signing 
in(已经登录,请先退出再进行登录)!")
+            .data("userName", loginUser)
+        }(_ => {
+          OAuth2Authentication.OAuth2Auth(gatewayContext, true)
+          return
+        })
+      case "oauth-redirect" => {
+        OAuth2Authentication.OAuth2Redirect(gatewayContext)
+        return
+      }
       case "logout" => logout(gatewayContext)
       case "userInfo" => userInfo(gatewayContext)
       case "publicKey" => publicKey(gatewayContext)
diff --git 
a/linkis-spring-cloud-services/linkis-service-gateway/linkis-gateway-core/src/main/scala/org/apache/linkis/gateway/security/oauth/OAuth2Authentication.scala
 
b/linkis-spring-cloud-services/linkis-service-gateway/linkis-gateway-core/src/main/scala/org/apache/linkis/gateway/security/oauth/OAuth2Authentication.scala
new file mode 100644
index 0000000000..c62ab5b3be
--- /dev/null
+++ 
b/linkis-spring-cloud-services/linkis-service-gateway/linkis-gateway-core/src/main/scala/org/apache/linkis/gateway/security/oauth/OAuth2Authentication.scala
@@ -0,0 +1,340 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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 org.apache.linkis.gateway.security.oauth
+
+import org.apache.linkis.common.exception.LinkisCommonErrorException
+import org.apache.linkis.common.utils.{Logging, Utils}
+import org.apache.linkis.gateway.config.GatewayConfiguration
+import org.apache.linkis.gateway.config.GatewayConfiguration._
+import org.apache.linkis.gateway.http.GatewayContext
+import org.apache.linkis.gateway.security.{GatewaySSOUtils, SecurityFilter}
+import org.apache.linkis.server.Message
+import org.apache.linkis.server.conf.ServerConfiguration
+
+import org.apache.commons.io.IOUtils
+import org.apache.commons.lang3.StringUtils
+
+import java.io.IOException
+import java.net.{HttpURLConnection, URL}
+
+import com.fasterxml.jackson.databind.ObjectMapper
+import com.fasterxml.jackson.module.scala.DefaultScalaModule
+
+object OAuth2Authentication extends Logging {
+
+  private val objectMapper = new ObjectMapper()
+  objectMapper.registerModule(DefaultScalaModule)
+
+  def isOAuth2Request(gatewayContext: GatewayContext): Boolean = {
+    val path = getMethod(gatewayContext)
+    path == "oauth_login" || path == "oauth_redirect"
+  }
+
+  def OAuth2Entry(gatewayContext: GatewayContext, login: Boolean = false): 
Boolean = {
+    val path = getMethod(gatewayContext)
+    if (path == "oauth_redirect") {
+      OAuth2Redirect(gatewayContext)
+    } else if (path == "oauth_redirect") {
+      OAuth2Auth(gatewayContext, login)
+    } else {
+      val message =
+        Message.noLogin(s"未知 OAuth 请求") << 
gatewayContext.getRequest.getRequestURI
+      SecurityFilter.filterResponse(gatewayContext, message)
+      false
+    }
+  }
+
+  private def getMethod(gatewayContext: GatewayContext) = {
+    var userURI = ServerConfiguration.BDP_SERVER_USER_URI.getValue
+    if (!userURI.endsWith("/")) userURI += "/"
+    val path = gatewayContext.getRequest.getRequestURI.replace(userURI, "")
+    path
+  }
+
+  def OAuth2Redirect(gatewayContext: GatewayContext): Boolean = {
+    if (!ENABLE_OAUTH_AUTHENTICATION.getValue) {
+      val message =
+        Message.noLogin(
+          s"Gateway 未启用 OAuth 认证,请采用其他认证方式!"
+        ) << gatewayContext.getRequest.getRequestURI
+      SecurityFilter.filterResponse(gatewayContext, message)
+      return false
+    }
+    val message =
+      Message.ok("创建链接成功!").data("redirectUrl", generateAuthenticationUrl())
+    SecurityFilter.filterResponse(gatewayContext, message)
+    true
+  }
+
+  /**
+   * 生成OAuth认证的URL
+   *
+   * @note
+   *   认证完成回调链接需要在认证服务器上进行配置
+   * @return
+   */
+  private def generateAuthenticationUrl(): String = {
+    var oauthServerUrl =
+      
s"${OAUTH_AUTHENTICATION_URL.getValue}?client_id=${OAUTH_CLIENT_ID.getValue}&response_type=code"
+    if (StringUtils.isNotBlank(OAUTH_SCOPE.getValue)) {
+      oauthServerUrl += s"&scope=${OAUTH_SCOPE.getValue}"
+    }
+    oauthServerUrl
+  }
+
+  def OAuth2Auth(gatewayContext: GatewayContext, login: Boolean = false): 
Boolean = {
+    if (!ENABLE_OAUTH_AUTHENTICATION.getValue) {
+      val message =
+        Message.noLogin(
+          s"Gateway 未启用 OAuth 认证,请采用其他认证方式!"
+        ) << gatewayContext.getRequest.getRequestURI
+      SecurityFilter.filterResponse(gatewayContext, message)
+      return false
+    }
+
+    val code = extractCode(gatewayContext)
+    val host = gatewayContext.getRequest.getRequestRealIpAddr()
+
+    if (StringUtils.isBlank(code)) {
+      val message =
+        Message.noLogin(s"请在回调查询参数中返回code,以便完成OAuth认证!") << 
gatewayContext.getRequest.getRequestURI
+      SecurityFilter.filterResponse(gatewayContext, message)
+      return false
+    }
+
+    var authMsg: Message =
+      Message.noLogin(s"无效的访问令牌 $code,无法完成 OAuth 认证!") << 
gatewayContext.getRequest.getRequestURI
+
+    val accessToken = Utils.tryCatch(exchangeAccessToken(code, host))(t => {
+      authMsg = Message.noLogin(
+        s"OAuth exchange failed, code: $code, reason: ${t.getMessage}"
+      ) << gatewayContext.getRequest.getRequestURI
+      null
+    })
+
+    if (StringUtils.isNotBlank(accessToken)) {
+      val username = validateAccessToken(accessToken, host)
+      logger.info(
+        s"OAuth authentication succeed, uri: 
${gatewayContext.getRequest.getRequestURI}, accessToken: $accessToken, 
username: $username."
+      )
+
+      if (login) {
+        GatewaySSOUtils.setLoginUser(gatewayContext, username)
+        val msg =
+          Message
+            .ok("login successful(登录成功)!")
+            .data("userName", username)
+            .data("enableWatermark", 
GatewayConfiguration.ENABLE_WATER_MARK.getValue)
+            .data("isAdmin", false)
+        SecurityFilter.filterResponse(gatewayContext, msg)
+        return true
+      }
+
+      GatewaySSOUtils.setLoginUser(gatewayContext.getRequest, username)
+      true
+    } else {
+      logger.info(
+        s"OAuth exchange fail, uri: 
${gatewayContext.getRequest.getRequestURI}, code: $code, host: $host."
+      )
+      SecurityFilter.filterResponse(gatewayContext, authMsg)
+      false
+    }
+  }
+
+  private def extractCode(gatewayContext: GatewayContext): String = {
+    Utils.tryCatch(gatewayContext.getRequest.getQueryParams.get("code")(0))(_ 
=> null)
+  }
+
+  /**
+   * 验证访问码的有效性并获取访问令牌
+   *
+   * @param code
+   *   访问码
+   * @param host
+   *   客户端主机
+   * @return
+   *   访问令牌
+   */
+  private def exchangeAccessToken(code: String, host: String): String = {
+    val exchangeUrl = OAUTH_EXCHANGE_URL.getValue
+
+    if (StringUtils.isBlank(exchangeUrl)) {
+      logger.warn(s"OAuth exchange url is not set")
+    }
+    if (StringUtils.isBlank(code)) {
+      logger.warn(s"OAuth exchange code is empty")
+    }
+
+    Utils.tryCatch({
+      val response = HttpUtils.post(
+        exchangeUrl,
+        data = objectMapper.writeValueAsString(
+          Map(
+            "client_id" -> OAUTH_CLIENT_ID.getValue,
+            "client_secret" -> OAUTH_CLIENT_SECRET.getValue,
+            "code" -> code,
+            "host" -> host
+          )
+        )
+      )
+      objectMapper.readValue(response, classOf[Map[String, 
String]]).get("access_token").orNull
+    })(t => {
+      logger.warn(s"OAuth exchange failed, url: $exchangeUrl, reason: 
${t.getMessage}")
+      null
+    })
+  }
+
+  /**
+   * 验证访问令牌的有效性并兑换用户名
+   *
+   * @param accessToken
+   *   访问令牌
+   * @param host
+   *   客户端主机
+   * @return
+   *   用户名
+   */
+  private def validateAccessToken(accessToken: String, host: String): String = 
{
+    val url = OAUTH_VALIDATE_URL.getValue
+
+    if (StringUtils.isBlank(url)) {
+      logger.warn(s"OAuth validate url is not set")
+    }
+
+    if (StringUtils.isBlank(accessToken)) {
+      logger.warn(s"OAuth validate accessToken is empty")
+    }
+
+    Utils.tryCatch({
+      val response = HttpUtils.get(url, headers = Map("Authorization" -> 
s"Bearer $accessToken"))
+      objectMapper
+        .readValue(response, classOf[Map[String, String]])
+        .get(OAUTH_VALIDATE_FIELD.getValue)
+        .orNull
+    })(t => {
+      logger.warn(s"OAuth validate failed, url: $url, reason: ${t.getMessage}")
+      null
+    })
+  }
+
+}
+
+object HttpUtils extends Logging {
+
+  def get(
+      url: String,
+      headers: Map[String, String] = Map.empty,
+      params: Map[String, String] = Map.empty
+  ): String = {
+    Utils.tryCatch {
+      val fullUrl = url + (if (params.nonEmpty) {
+                             "?" + params.map { case (key, value) => 
s"$key=$value" }.mkString("&")
+                           } else {
+                             ""
+                           })
+      val connection = new 
URL(fullUrl).openConnection().asInstanceOf[HttpURLConnection]
+      connection.setRequestMethod("GET")
+
+      headers.foreach { case (key, value) =>
+        connection.setRequestProperty(key, value)
+      }
+
+      if (!headers.contains("Accept")) {
+        connection.setRequestProperty("Accept", "application/json")
+      }
+
+      val responseCode = connection.getResponseCode
+      if (!(responseCode >= 200 && responseCode < 300)) {
+        throw new IOException(s"HTTP GET request failed for URL: $url - 
$responseCode")
+      }
+
+      val inputStream = connection.getInputStream
+
+      try {
+        IOUtils.toString(inputStream, "UTF-8")
+      } finally {
+        inputStream.close()
+        connection.disconnect()
+      }
+    } { t =>
+      logger.warn(s"Failed to execute HTTP GET request to $url", t)
+      throw new LinkisCommonErrorException(
+        0,
+        s"HTTP GET request failed for URL: $url, reason: ${t.getMessage}"
+      )
+    }
+  }
+
+  def post(url: String, data: String, headers: Map[String, String] = 
Map.empty): String = {
+    Utils.tryCatch {
+      val connection = new 
URL(url).openConnection().asInstanceOf[HttpURLConnection]
+      try {
+        connection.setRequestMethod("POST")
+        connection.setDoOutput(true)
+        connection.setDoInput(true)
+
+        headers.foreach { case (key, value) =>
+          connection.setRequestProperty(key, value)
+        }
+
+        if (!headers.contains("Content-Type")) {
+          connection.setRequestProperty("Content-Type", "application/json; 
charset=UTF-8")
+        }
+
+        if (!headers.contains("Accept")) {
+          connection.setRequestProperty("Accept", "application/json")
+        }
+
+        if (data != null && data.nonEmpty) {
+          val outputStream = connection.getOutputStream
+          try {
+            IOUtils.write(data, outputStream, "UTF-8")
+          } finally {
+            outputStream.close()
+          }
+        }
+
+        val responseCode = connection.getResponseCode
+        if (!(responseCode >= 200 && responseCode < 300)) {
+          throw new IOException(s"HTTP POST request failed for URL: $url - 
$responseCode")
+        }
+
+        val inputStream = connection.getInputStream
+
+        try {
+          if (inputStream != null) {
+            IOUtils.toString(inputStream, "UTF-8")
+          } else {
+            ""
+          }
+        } finally {
+          if (inputStream != null) inputStream.close()
+        }
+      } finally {
+        connection.disconnect()
+      }
+    } { t =>
+      logger.warn(s"Failed to execute HTTP POST request to $url", t)
+      throw new LinkisCommonErrorException(
+        0,
+        s"HTTP POST request failed for URL: $url, reason: ${t.getMessage}"
+      )
+    }
+  }
+
+}
diff --git a/linkis-web/src/common/i18n/en.json 
b/linkis-web/src/common/i18n/en.json
index aac078b18a..23b21bca44 100644
--- a/linkis-web/src/common/i18n/en.json
+++ b/linkis-web/src/common/i18n/en.json
@@ -265,6 +265,7 @@
         "userName": "Please enter your username",
         "remenber": "Remember me",
         "login": "Login",
+        "oauthLogin": "OAuth Login",
         "passwordHint": "Please enter your password",
         "password": "Please enter password!",
         "loginSuccess": "Login Success",
diff --git a/linkis-web/src/common/i18n/zh.json 
b/linkis-web/src/common/i18n/zh.json
index 688153101e..cc4c24e0c2 100644
--- a/linkis-web/src/common/i18n/zh.json
+++ b/linkis-web/src/common/i18n/zh.json
@@ -266,6 +266,7 @@
         "userName": "请输入用户名",
         "remenber": "记住当前用户",
         "login": "登录",
+        "oauthLogin": "OAuth 登录",
         "passwordHint": "请输入密码!",
         "loginSuccess": "登录成功",
         "haveLogin": "您已经登录,请不要重复登录",
diff --git a/linkis-web/src/dss/router.js b/linkis-web/src/dss/router.js
index 01b5ede649..bac6af2994 100644
--- a/linkis-web/src/dss/router.js
+++ b/linkis-web/src/dss/router.js
@@ -61,6 +61,16 @@ export default [
     component: () =>
       import('./view/login/index.vue'),
   },
+  {
+    path: '/login/oauth/callback',
+    name: 'OAuthCallback',
+    meta: {
+      title: 'OAuthCallback',
+      publicPage: true,
+    },
+    component: () =>
+      import('./view/login/oauthCallback.vue'),
+  },
   // Public pages, not subject to permission control(公用页面,不受权限控制)
   {
     path: '/500',
diff --git a/linkis-web/src/dss/view/login/index.vue 
b/linkis-web/src/dss/view/login/index.vue
index 81c6af0bdb..c3ec243b21 100644
--- a/linkis-web/src/dss/view/login/index.vue
+++ b/linkis-web/src/dss/view/login/index.vue
@@ -20,7 +20,7 @@
     class="login"
     @keyup.enter.stop.prevent="handleSubmit('loginForm')">
     <i class="login-bg"/>
-    <div class="login-main">
+    <div class="login-main" :style="{height: OAuthRedirectUrl ? '500px' : ''}">
       <Form
         ref="loginForm"
         :model="loginForm"
@@ -56,6 +56,14 @@
             size="large"
             
@click="handleSubmit('loginForm')">{{$t('message.common.login.login')}}</Button>
         </FormItem>
+        <FormItem>
+          <Button
+            v-if="OAuthRedirectUrl"
+            type="primary"
+            long
+            size="large"
+            
@click="handleOAuthLogin()">{{$t('message.common.login.oauthLogin')}}</Button>
+        </FormItem>
       </Form>
     </div>
   </div>
@@ -71,6 +79,7 @@ export default {
   data() {
     return {
       loading: false,
+      OAuthRedirectUrl: null,
       loginForm: {
         user: '',
         password: '',
@@ -97,6 +106,7 @@ export default {
       this.loginForm.password = userNameAndPass.split('&')[1];
     }
     this.getPublicKey();
+    this.checkOAuthStatus();
   },
   mounted() {
   },
@@ -179,6 +189,15 @@ export default {
     clearSession() {
       storage.clear();
     },
+    // check OAuth status(检查OAuth状态)
+    checkOAuthStatus() {
+      api.fetch('/user/oauth-redirect', {}, 'get').then((res) => {
+        this.OAuthRedirectUrl = res.redirectUrl;
+      })
+    },
+    handleOAuthLogin() {
+      window.location.href = this.OAuthRedirectUrl;
+    },
   },
 };
 </script>
diff --git a/linkis-web/src/dss/view/login/oauthCallback.vue 
b/linkis-web/src/dss/view/login/oauthCallback.vue
new file mode 100644
index 0000000000..e81bfe7bd8
--- /dev/null
+++ b/linkis-web/src/dss/view/login/oauthCallback.vue
@@ -0,0 +1,55 @@
+<!--
+  ~ Licensed to the Apache Software Foundation (ASF) under one or more
+  ~ contributor license agreements.  See the NOTICE file distributed with
+  ~ this work for additional information regarding copyright ownership.
+  ~ The ASF licenses this file to You 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.
+  -->
+
+<template>
+  <div></div>
+</template>
+<script>
+import api from '@/common/service/api';
+import storage from '@/common/helper/storage';
+export default {
+  data() {
+    return {};
+  },
+  created() {
+    if (this.$route.query.code) {
+      api.fetch('/user/oauth-login', { code: this.$route.query.code }, 
'post').then((res) => {
+        if (res) {
+          this.userName = res.userName;
+          storage.set('userName', res.userName, 'session')
+          storage.set('enableWatermark', res.enableWatermark ? true : false, 
'session')
+          this.$router.push({ path: '/console' });
+          this.$Message.success(this.$t('message.common.login.loginSuccess'));
+        }
+      }).catch((err) => {
+        if (err.message.indexOf('已经登录,请先退出再进行登录') !== -1) {
+          this.getPageHomeUrl().then(() => {
+            this.$router.push({ path: '/' });
+          })
+        } else {
+          this.$Message.error(this.$t('message.common.login.vaildFaild'));
+          this.$router.push({ path: '/login' })
+        }
+      });
+    }
+  },
+  mounted() {
+  },
+  methods: {
+  },
+};
+</script>


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to