From e8179773c051bb6ecf707046e64e96f228ddc24a Mon Sep 17 00:00:00 2001 From: kazutoiris <78157415+kazutoiris@users.noreply.github.com> Date: Thu, 14 Aug 2025 23:16:42 +0800 Subject: [PATCH 1/5] 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 <78157415+kazutoiris@users.noreply.github.com> --- .../gateway/config/GatewayConfiguration.scala | 9 + .../gateway/security/SecurityFilter.scala | 3 + .../linkis/gateway/security/UserRestful.scala | 15 + .../security/oauth/OAuth2Authentication.scala | 333 ++++++++++++++++++ 4 files changed, 360 insertions(+) create mode 100644 linkis-spring-cloud-services/linkis-service-gateway/linkis-gateway-core/src/main/scala/org/apache/linkis/gateway/security/oauth/OAuth2Authentication.scala 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..e452c5c181 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 @@ -31,6 +31,7 @@ import org.apache.linkis.server.exception.{LoginExpireException, NonLoginExcepti import org.apache.commons.lang3.StringUtils import org.apache.commons.lang3.exception.ExceptionUtils +import org.apache.linkis.gateway.security.oauth.OAuth2Authentication import java.io.File import java.text.DateFormat @@ -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..3e2d2413f4 --- /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,333 @@ +/* + * 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.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" + } + + 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 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 + } + } + + 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 + } + + 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("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) + } + + /** + * 生成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 + } + + /** + * 验证访问码的有效性并获取访问令牌 + * + * @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}" + ) + } + } + +} From f44bc18b79d263a5faa6519f5974f76fffafe103 Mon Sep 17 00:00:00 2001 From: kazutoiris <78157415+kazutoiris@users.noreply.github.com> Date: Sun, 17 Aug 2025 11:42:13 +0800 Subject: [PATCH 2/5] 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 <78157415+kazutoiris@users.noreply.github.com> --- linkis-dist/package/conf/linkis-mg-gateway.properties | 9 +++++++++ 1 file changed, 9 insertions(+) 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 From 66ff42fee0d8a4633f51219b7aabe99b1a1e1947 Mon Sep 17 00:00:00 2001 From: kazutoiris <78157415+kazutoiris@users.noreply.github.com> Date: Sun, 17 Aug 2025 14:48:57 +0800 Subject: [PATCH 3/5] style: reformat code Signed-off-by: kazutoiris <78157415+kazutoiris@users.noreply.github.com> --- .../linkis/gateway/security/SecurityFilter.scala | 2 +- .../gateway/security/oauth/OAuth2Authentication.scala | 10 ++++++---- 2 files changed, 7 insertions(+), 5 deletions(-) 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 e452c5c181..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} @@ -31,7 +32,6 @@ import org.apache.linkis.server.exception.{LoginExpireException, NonLoginExcepti import org.apache.commons.lang3.StringUtils import org.apache.commons.lang3.exception.ExceptionUtils -import org.apache.linkis.gateway.security.oauth.OAuth2Authentication import java.io.File import java.text.DateFormat 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 index 3e2d2413f4..8f81d7bada 100644 --- 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 @@ -143,7 +143,7 @@ object OAuth2Authentication extends Logging { * 生成OAuth认证的URL * * @note - * 认证完成回调链接需要在认证服务器上进行配置 + * 认证完成回调链接需要在认证服务器上进行配置 * @return */ private def generateAuthenticationUrl(): String = { @@ -159,11 +159,11 @@ object OAuth2Authentication extends Logging { * 验证访问码的有效性并获取访问令牌 * * @param code - * 访问码 + * 访问码 * @param host - * 客户端主机 + * 客户端主机 * @return - * 访问令牌 + * 访问令牌 */ private def exchangeAccessToken(code: String, host: String): String = { val exchangeUrl = OAUTH_EXCHANGE_URL.getValue @@ -226,9 +226,11 @@ object OAuth2Authentication extends Logging { null }) } + } object HttpUtils extends Logging { + def get( url: String, headers: Map[String, String] = Map.empty, From 873b461a5751a2f8b021c6ba861bd06c5c52ec47 Mon Sep 17 00:00:00 2001 From: kazutoiris <78157415+kazutoiris@users.noreply.github.com> Date: Wed, 20 Aug 2025 23:44:08 +0800 Subject: [PATCH 4/5] 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 <78157415+kazutoiris@users.noreply.github.com> --- .../security/oauth/OAuth2Authentication.scala | 53 ++++++++++-------- 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 ++++++- .../src/dss/view/login/oauthCallback.vue | 55 +++++++++++++++++++ 6 files changed, 116 insertions(+), 25 deletions(-) create mode 100644 linkis-web/src/dss/view/login/oauthCallback.vue 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 index 8f81d7bada..c62ab5b3be 100644 --- 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 @@ -19,6 +19,7 @@ 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} @@ -44,13 +45,6 @@ object OAuth2Authentication extends Logging { path == "oauth_login" || path == "oauth_redirect" } - 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 OAuth2Entry(gatewayContext: GatewayContext, login: Boolean = false): Boolean = { val path = getMethod(gatewayContext) if (path == "oauth_redirect") { @@ -65,6 +59,13 @@ object OAuth2Authentication extends Logging { } } + 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 = @@ -80,6 +81,22 @@ object OAuth2Authentication extends Logging { 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 = @@ -119,7 +136,11 @@ object OAuth2Authentication extends Logging { if (login) { GatewaySSOUtils.setLoginUser(gatewayContext, username) val msg = - Message.ok("login successful(登录成功)!").data("userName", username).data("isAdmin", false) + Message + .ok("login successful(登录成功)!") + .data("userName", username) + .data("enableWatermark", GatewayConfiguration.ENABLE_WATER_MARK.getValue) + .data("isAdmin", false) SecurityFilter.filterResponse(gatewayContext, msg) return true } @@ -139,22 +160,6 @@ object OAuth2Authentication extends Logging { Utils.tryCatch(gatewayContext.getRequest.getQueryParams.get("code")(0))(_ => null) } - /** - * 生成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 - } - /** * 验证访问码的有效性并获取访问令牌 * 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')"> -