diff --git a/src/backend/commons/common-i18n/src/main/java/com/tencent/bk/job/common/i18n/locale/LocaleUtils.java b/src/backend/commons/common-i18n/src/main/java/com/tencent/bk/job/common/i18n/locale/LocaleUtils.java index 1de0bc1294..9ea4b7ff19 100644 --- a/src/backend/commons/common-i18n/src/main/java/com/tencent/bk/job/common/i18n/locale/LocaleUtils.java +++ b/src/backend/commons/common-i18n/src/main/java/com/tencent/bk/job/common/i18n/locale/LocaleUtils.java @@ -38,6 +38,10 @@ public class LocaleUtils { public static final String LANG_ZH = "zh"; public static final String LANG_EN = "en"; public static final String LANG_EN_US = "en_US"; + /** + * 蓝鲸通用的LANG HEADER + */ + public static final String BLUEKING_LANG_HEADER = "blueking_language"; /** * 定义项目通用的LANG HEADER */ diff --git a/src/backend/commons/common-i18n/src/main/resources/i18n/exception/message.properties b/src/backend/commons/common-i18n/src/main/resources/i18n/exception/message.properties index cdda51fd51..fc398b3245 100644 --- a/src/backend/commons/common-i18n/src/main/resources/i18n/exception/message.properties +++ b/src/backend/commons/common-i18n/src/main/resources/i18n/exception/message.properties @@ -216,6 +216,7 @@ ##业务错误-用户服务、登录服务 1247001=用户不存在或者未登录 +1247403=无该应用访问权限 diff --git a/src/backend/commons/common-i18n/src/main/resources/i18n/exception/message_en.properties b/src/backend/commons/common-i18n/src/main/resources/i18n/exception/message_en.properties index a63ebdb2e7..28f4474466 100644 --- a/src/backend/commons/common-i18n/src/main/resources/i18n/exception/message_en.properties +++ b/src/backend/commons/common-i18n/src/main/resources/i18n/exception/message_en.properties @@ -216,6 +216,7 @@ ## Business error - User/Login 1247001=User does not exist or is not logged in +1247403=No access permission for this application ## Business error - Backup 1249001=Fail to get node info from artifactory diff --git a/src/backend/commons/common-i18n/src/main/resources/i18n/exception/message_en_US.properties b/src/backend/commons/common-i18n/src/main/resources/i18n/exception/message_en_US.properties index a63ebdb2e7..28f4474466 100644 --- a/src/backend/commons/common-i18n/src/main/resources/i18n/exception/message_en_US.properties +++ b/src/backend/commons/common-i18n/src/main/resources/i18n/exception/message_en_US.properties @@ -216,6 +216,7 @@ ## Business error - User/Login 1247001=User does not exist or is not logged in +1247403=No access permission for this application ## Business error - Backup 1249001=Fail to get node info from artifactory diff --git a/src/backend/commons/common-i18n/src/main/resources/i18n/exception/message_zh.properties b/src/backend/commons/common-i18n/src/main/resources/i18n/exception/message_zh.properties index cdda51fd51..fc398b3245 100644 --- a/src/backend/commons/common-i18n/src/main/resources/i18n/exception/message_zh.properties +++ b/src/backend/commons/common-i18n/src/main/resources/i18n/exception/message_zh.properties @@ -216,6 +216,7 @@ ##业务错误-用户服务、登录服务 1247001=用户不存在或者未登录 +1247403=无该应用访问权限 diff --git a/src/backend/commons/common-i18n/src/main/resources/i18n/exception/message_zh_CN.properties b/src/backend/commons/common-i18n/src/main/resources/i18n/exception/message_zh_CN.properties index cdda51fd51..fc398b3245 100644 --- a/src/backend/commons/common-i18n/src/main/resources/i18n/exception/message_zh_CN.properties +++ b/src/backend/commons/common-i18n/src/main/resources/i18n/exception/message_zh_CN.properties @@ -216,6 +216,7 @@ ##业务错误-用户服务、登录服务 1247001=用户不存在或者未登录 +1247403=无该应用访问权限 diff --git a/src/backend/commons/common/src/main/java/com/tencent/bk/job/common/constant/ErrorCode.java b/src/backend/commons/common/src/main/java/com/tencent/bk/job/common/constant/ErrorCode.java index 0f24a926b6..309a397bc4 100644 --- a/src/backend/commons/common/src/main/java/com/tencent/bk/job/common/constant/ErrorCode.java +++ b/src/backend/commons/common/src/main/java/com/tencent/bk/job/common/constant/ErrorCode.java @@ -273,6 +273,8 @@ public class ErrorCode { // 用户服务 start // 用户不存在或者未登录 public static final int USER_NOT_EXIST_OR_NOT_LOGIN_IN = 1247001; + // 用户认证成功,但用户无应用访问权限 + public static final int USER_ACCESS_APP_FORBIDDEN = 1247403; // 用户服务 end // 业务网关 start diff --git a/src/backend/commons/common/src/main/java/com/tencent/bk/job/common/model/Response.java b/src/backend/commons/common/src/main/java/com/tencent/bk/job/common/model/Response.java index fae8eed059..e41359abd2 100644 --- a/src/backend/commons/common/src/main/java/com/tencent/bk/job/common/model/Response.java +++ b/src/backend/commons/common/src/main/java/com/tencent/bk/job/common/model/Response.java @@ -58,7 +58,7 @@ public class Response { @ApiModelProperty("错误信息") private String errorMsg; - @ApiModelProperty("请求成功返回的数据") + @ApiModelProperty("请求成功/失败返回的数据") private T data; @ApiModelProperty("请求 ID") diff --git a/src/backend/commons/esb-sdk/src/main/java/com/tencent/bk/job/common/esb/sdk/AbstractEsbSdkClient.java b/src/backend/commons/esb-sdk/src/main/java/com/tencent/bk/job/common/esb/sdk/AbstractEsbSdkClient.java index cf1c6c6a00..d960721b41 100644 --- a/src/backend/commons/esb-sdk/src/main/java/com/tencent/bk/job/common/esb/sdk/AbstractEsbSdkClient.java +++ b/src/backend/commons/esb-sdk/src/main/java/com/tencent/bk/job/common/esb/sdk/AbstractEsbSdkClient.java @@ -48,6 +48,10 @@ * ESB API 调用基础实现 */ public abstract class AbstractEsbSdkClient { + + // 请求成功 + protected static final Integer ESB_CODE_OK = 0; + private final Logger log = LoggerFactory.getLogger(this.getClass()); private static final JsonMapper JSON_MAPPER = JsonMapper.nonDefaultMapper(); @@ -150,6 +154,10 @@ private void requestEsbApi(BkApiContext apiContext, } esbResp = JSON_MAPPER.fromJson(respStr, typeReference); + if (esbResp == null) { + log.warn("[AbstractEsbSdkClient] warn:esbResp is null after JSON parse, respStr={}", respStr); + throw new InternalException("Esb api resp unexpected, fail to parse json data", ErrorCode.API_ERROR); + } apiContext.setResp(esbResp); if (!esbResp.getResult()) { log.warn( diff --git a/src/backend/commons/paas-sdk/src/main/java/com/tencent/bk/job/common/paas/exception/AppPermissionDeniedException.java b/src/backend/commons/paas-sdk/src/main/java/com/tencent/bk/job/common/paas/exception/AppPermissionDeniedException.java new file mode 100644 index 0000000000..ba74d68d28 --- /dev/null +++ b/src/backend/commons/paas-sdk/src/main/java/com/tencent/bk/job/common/paas/exception/AppPermissionDeniedException.java @@ -0,0 +1,51 @@ +/* + * Tencent is pleased to support the open source community by making BK-JOB蓝鲸智云作业平台 available. + * + * Copyright (C) 2021 THL A29 Limited, a Tencent company. All rights reserved. + * + * BK-JOB蓝鲸智云作业平台 is licensed under the MIT License. + * + * License for BK-JOB蓝鲸智云作业平台: + * -------------------------------------------------------------------- + * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated + * documentation files (the "Software"), to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and + * to permit persons to whom the Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all copies or substantial portions of + * the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO + * THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +package com.tencent.bk.job.common.paas.exception; + +import com.tencent.bk.job.common.constant.ErrorCode; +import com.tencent.bk.job.common.exception.ServiceException; +import com.tencent.bk.job.common.model.error.ErrorType; +import lombok.Getter; +import lombok.ToString; + +/** + * 应用权限不足异常 + */ +@Getter +@ToString +public class AppPermissionDeniedException extends ServiceException { + + // 源于用户管理接口:进一步的操作提示 + private final String message; + + public AppPermissionDeniedException(String message) { + super(ErrorType.PERMISSION_DENIED, ErrorCode.USER_ACCESS_APP_FORBIDDEN); + this.message = message; + } + + public String getMessage() { + return message; + } +} diff --git a/src/backend/commons/paas-sdk/src/main/java/com/tencent/bk/job/common/paas/login/EELoginClient.java b/src/backend/commons/paas-sdk/src/main/java/com/tencent/bk/job/common/paas/login/EELoginClient.java index 4c55d2f528..f7e6979fd3 100644 --- a/src/backend/commons/paas-sdk/src/main/java/com/tencent/bk/job/common/paas/login/EELoginClient.java +++ b/src/backend/commons/paas-sdk/src/main/java/com/tencent/bk/job/common/paas/login/EELoginClient.java @@ -32,6 +32,7 @@ import com.tencent.bk.job.common.exception.InternalUserManageException; import com.tencent.bk.job.common.metrics.CommonMetricNames; import com.tencent.bk.job.common.model.dto.BkUserDTO; +import com.tencent.bk.job.common.paas.exception.AppPermissionDeniedException; import com.tencent.bk.job.common.paas.model.EsbUserDto; import com.tencent.bk.job.common.util.http.HttpMetricUtil; import io.micrometer.core.instrument.Tag; @@ -40,6 +41,14 @@ @Slf4j public class EELoginClient extends AbstractEsbSdkClient implements ILoginClient { + + // 用户认证失败,即用户登录态无效 + private static final Integer ESB_CODE_USER_NOT_LOGIN = 1302100; + // 用户不存在 + private static final Integer ESB_CODE_USER_NOT_EXIST = 1302103; + // 用户认证成功,但用户无应用访问权限 + private static final Integer ESB_CODE_USER_NO_APP_PERMISSION = 1302403; + private static final String API_GET_USER_INFO = "/api/c/compapi/v2/bk_login/get_user/"; public EELoginClient(String esbHostUrl, String appCode, String appSecret, String lang, boolean useEsbTestEnv) { @@ -81,7 +90,13 @@ private BkUserDTO getUserInfo(EsbReq esbReq) { new TypeReference>() { } ); - return convertToBkUserDTO(esbResp.getData()); + Integer code = esbResp.getCode(); + if (ESB_CODE_OK.equals(code)) { + return convertToBkUserDTO(esbResp.getData()); + } else { + handleNotOkResp(esbResp); + return null; + } } catch (Exception e) { String errorMsg = "Get " + API_GET_USER_INFO + " error"; log.error(errorMsg, e); @@ -91,6 +106,17 @@ private BkUserDTO getUserInfo(EsbReq esbReq) { } } + private void handleNotOkResp(EsbResp esbResp) { + Integer code = esbResp.getCode(); + if (ESB_CODE_USER_NO_APP_PERMISSION.equals(code)) { + throw new AppPermissionDeniedException(esbResp.getMessage()); + } else if (ESB_CODE_USER_NOT_LOGIN.equals(code)) { + log.info("User not login, esbResp.code={}, esbResp.message={}", esbResp.getCode(), esbResp.getMessage()); + } else if (ESB_CODE_USER_NOT_EXIST.equals(code)) { + log.info("User not exist, esbResp.code={}, esbResp.message={}", esbResp.getCode(), esbResp.getMessage()); + } + } + private BkUserDTO convertToBkUserDTO(EsbUserDto esbUserDto) { BkUserDTO bkUserDTO = new BkUserDTO(); bkUserDTO.setUsername(esbUserDto.getUsername()); diff --git a/src/backend/job-gateway/src/main/java/com/tencent/bk/job/gateway/config/RouteConfig.java b/src/backend/job-gateway/src/main/java/com/tencent/bk/job/gateway/config/RouteConfig.java index 88a8d0ee7f..27a6815fe3 100644 --- a/src/backend/job-gateway/src/main/java/com/tencent/bk/job/gateway/config/RouteConfig.java +++ b/src/backend/job-gateway/src/main/java/com/tencent/bk/job/gateway/config/RouteConfig.java @@ -46,6 +46,7 @@ import java.util.List; +import static com.tencent.bk.job.common.i18n.locale.LocaleUtils.BLUEKING_LANG_HEADER; import static org.springframework.web.reactive.function.server.RequestPredicates.GET; @Slf4j @@ -95,6 +96,7 @@ Mono getUserByBkToken(ServerRequest request) { String tokenCookieName = loginService.getCookieNameForToken(); List cookieList = request.headers().header("cookie"); + String lang = request.headers().firstHeader(BLUEKING_LANG_HEADER); List bkTokenList = RequestUtil.getCookieValuesFromCookies(cookieList, tokenCookieName); if (CollectionUtils.isEmpty(bkTokenList)) { @@ -107,7 +109,7 @@ Mono getUserByBkToken(ServerRequest request) { BkUserDTO user = null; // 遍历所有传入token找出当前环境的 for (String bkToken : bkTokenList) { - user = loginService.getUser(bkToken); + user = loginService.getUser(bkToken, lang); if (user != null) { break; } diff --git a/src/backend/job-gateway/src/main/java/com/tencent/bk/job/gateway/config/SdkClientConfig.java b/src/backend/job-gateway/src/main/java/com/tencent/bk/job/gateway/config/SdkClientConfig.java index 9533ecc21d..7ddd6b0065 100644 --- a/src/backend/job-gateway/src/main/java/com/tencent/bk/job/gateway/config/SdkClientConfig.java +++ b/src/backend/job-gateway/src/main/java/com/tencent/bk/job/gateway/config/SdkClientConfig.java @@ -24,6 +24,7 @@ package com.tencent.bk.job.gateway.config; +import com.tencent.bk.job.common.i18n.locale.LocaleUtils; import com.tencent.bk.job.common.paas.login.CustomLoginClient; import com.tencent.bk.job.common.paas.login.EELoginClient; import com.tencent.bk.job.common.paas.login.ILoginClient; @@ -44,12 +45,31 @@ public ILoginClient innerLoginClient(@Autowired BkConfig bkConfig) { return new CustomLoginClient(bkConfig.getCustomLoginApiUrl()); } - @Bean + @Bean(name = "enLoginClient") + @ConditionalOnProperty(value = "paas.login.custom.enabled", havingValue = "false", matchIfMissing = true) + @Primary + public ILoginClient enLoginClient(@Autowired BkConfig bkConfig) { + log.info("Init standard en login client"); + return new EELoginClient( + bkConfig.getEsbUrl(), + bkConfig.getAppCode(), + bkConfig.getAppSecret(), + LocaleUtils.LANG_EN, + bkConfig.isUseEsbTestEnv() + ); + } + + @Bean(name = "cnLoginClient") @ConditionalOnProperty(value = "paas.login.custom.enabled", havingValue = "false", matchIfMissing = true) @Primary - public ILoginClient standardLoginClient(@Autowired BkConfig bkConfig) { - log.info("Init standard login client"); - return new EELoginClient(bkConfig.getEsbUrl(), bkConfig.getAppCode(), bkConfig.getAppSecret(), - bkConfig.isUseEsbTestEnv()); + public ILoginClient cnLoginClient(@Autowired BkConfig bkConfig) { + log.info("Init standard cn login client"); + return new EELoginClient( + bkConfig.getEsbUrl(), + bkConfig.getAppCode(), + bkConfig.getAppSecret(), + LocaleUtils.LANG_ZH_CN, + bkConfig.isUseEsbTestEnv() + ); } } diff --git a/src/backend/job-gateway/src/main/java/com/tencent/bk/job/gateway/filter/web/AddWebLangHeaderGatewayFilterFactory.java b/src/backend/job-gateway/src/main/java/com/tencent/bk/job/gateway/filter/web/AddWebLangHeaderGatewayFilterFactory.java index 72b117b61d..4750122a3a 100644 --- a/src/backend/job-gateway/src/main/java/com/tencent/bk/job/gateway/filter/web/AddWebLangHeaderGatewayFilterFactory.java +++ b/src/backend/job-gateway/src/main/java/com/tencent/bk/job/gateway/filter/web/AddWebLangHeaderGatewayFilterFactory.java @@ -35,6 +35,7 @@ import org.springframework.http.server.reactive.ServerHttpRequest; import org.springframework.stereotype.Component; +import static com.tencent.bk.job.common.i18n.locale.LocaleUtils.BLUEKING_LANG_HEADER; import static com.tencent.bk.job.common.i18n.locale.LocaleUtils.COMMON_LANG_HEADER; /** @@ -54,7 +55,7 @@ public AddWebLangHeaderGatewayFilterFactory() { public GatewayFilter apply(Config config) { return (exchange, chain) -> { ServerHttpRequest request = exchange.getRequest(); - String webLangCookieValue = RequestUtil.getCookieValue(request, "blueking_language"); + String webLangCookieValue = RequestUtil.getCookieValue(request, BLUEKING_LANG_HEADER); String commonLang = LocaleUtils.LANG_ZH_CN; if (!StringUtils.isEmpty(webLangCookieValue)) { if (webLangCookieValue.equalsIgnoreCase(WebLangCookie.EN)) { diff --git a/src/backend/job-gateway/src/main/java/com/tencent/bk/job/gateway/filter/web/AuthorizeGatewayFilterFactory.java b/src/backend/job-gateway/src/main/java/com/tencent/bk/job/gateway/filter/web/AuthorizeGatewayFilterFactory.java index faf7edff43..e69c48106b 100644 --- a/src/backend/job-gateway/src/main/java/com/tencent/bk/job/gateway/filter/web/AuthorizeGatewayFilterFactory.java +++ b/src/backend/job-gateway/src/main/java/com/tencent/bk/job/gateway/filter/web/AuthorizeGatewayFilterFactory.java @@ -24,8 +24,13 @@ package com.tencent.bk.job.gateway.filter.web; +import com.tencent.bk.job.common.constant.ErrorCode; +import com.tencent.bk.job.common.i18n.locale.LocaleUtils; +import com.tencent.bk.job.common.model.Response; import com.tencent.bk.job.common.model.dto.BkUserDTO; +import com.tencent.bk.job.common.paas.exception.AppPermissionDeniedException; import com.tencent.bk.job.common.util.RequestUtil; +import com.tencent.bk.job.common.util.json.JsonUtils; import com.tencent.bk.job.gateway.config.LoginExemptionConfig; import com.tencent.bk.job.gateway.web.service.LoginService; import lombok.extern.slf4j.Slf4j; @@ -33,14 +38,21 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.cloud.gateway.filter.GatewayFilter; import org.springframework.cloud.gateway.filter.factory.AbstractGatewayFilterFactory; +import org.springframework.context.i18n.LocaleContextHolder; +import org.springframework.core.io.buffer.DataBuffer; import org.springframework.http.HttpStatus; +import org.springframework.http.MediaType; import org.springframework.http.server.reactive.ServerHttpRequest; import org.springframework.http.server.reactive.ServerHttpResponse; import org.springframework.stereotype.Component; import org.springframework.util.CollectionUtils; +import reactor.core.publisher.Mono; +import java.nio.charset.StandardCharsets; import java.util.List; +import static com.tencent.bk.job.common.i18n.locale.LocaleUtils.BLUEKING_LANG_HEADER; + /** * 用户token校验 */ @@ -74,6 +86,12 @@ private GatewayFilter getLoginFilter() { ServerHttpResponse response = exchange.getResponse(); String tokenCookieName = loginService.getCookieNameForToken(); List bkTokenList = RequestUtil.getCookieValuesFromHeader(request, tokenCookieName); + String lang = RequestUtil.getCookieValue(request, BLUEKING_LANG_HEADER); + if (StringUtils.isBlank(lang)) { + lang = LocaleUtils.LANG_EN; + log.warn("Cannot find blueking_language in cookie, use en"); + } + LocaleContextHolder.setLocale(LocaleUtils.getLocale(lang), true); if (CollectionUtils.isEmpty(bkTokenList)) { log.warn("Fail to parse token from headers, please check"); String bkToken = RequestUtil.getCookieValue(request, tokenCookieName); @@ -87,13 +105,11 @@ private GatewayFilter getLoginFilter() { response.getHeaders().add("x-login-url", loginService.getLoginRedirectUrl()); return response.setComplete(); } - BkUserDTO user = null; - // 遍历所有传入token找出当前环境的 - for (String bkToken : bkTokenList) { - user = loginService.getUser(bkToken); - if (user != null) { - break; - } + BkUserDTO user; + try { + user = getUserByTokenList(bkTokenList, lang); + } catch (AppPermissionDeniedException e) { + return getUserAccessAppForbiddenResp(response, e.getMessage()); } if (user == null) { log.warn("Invalid user token"); @@ -108,6 +124,29 @@ private GatewayFilter getLoginFilter() { }; } + private Mono getUserAccessAppForbiddenResp(ServerHttpResponse response, String data) { + Response resp = new Response<>(ErrorCode.USER_ACCESS_APP_FORBIDDEN, data); + response.setStatusCode(HttpStatus.FORBIDDEN); + String body = JsonUtils.toJson(resp); + byte[] bodyBytes = body.getBytes(StandardCharsets.UTF_8); + DataBuffer dataBuffer = response.bufferFactory().wrap(bodyBytes); + response.getHeaders().setContentLength(bodyBytes.length); + response.getHeaders().setContentType(MediaType.APPLICATION_JSON); + response.writeWith(Mono.just(dataBuffer)).subscribe(); + return response.setComplete(); + } + + private BkUserDTO getUserByTokenList(List bkTokenList, String lang) { + // 遍历所有传入token找出当前环境的 + for (String bkToken : bkTokenList) { + BkUserDTO user = loginService.getUser(bkToken, lang); + if (user != null) { + return user; + } + } + return null; + } + @Override public GatewayFilter apply(Config config) { if (loginExemptionConfig.isEnableLoginExemption()) { diff --git a/src/backend/job-gateway/src/main/java/com/tencent/bk/job/gateway/web/service/LoginService.java b/src/backend/job-gateway/src/main/java/com/tencent/bk/job/gateway/web/service/LoginService.java index 5931d66f90..650c6a9d21 100644 --- a/src/backend/job-gateway/src/main/java/com/tencent/bk/job/gateway/web/service/LoginService.java +++ b/src/backend/job-gateway/src/main/java/com/tencent/bk/job/gateway/web/service/LoginService.java @@ -41,9 +41,10 @@ public interface LoginService { * 根据token获取用户信息 * * @param bkToken 用户token + * @param lang 语言 * @return 用户信息 */ - BkUserDTO getUser(String bkToken); + BkUserDTO getUser(String bkToken, String lang); /** * 获取登录跳转url diff --git a/src/backend/job-gateway/src/main/java/com/tencent/bk/job/gateway/web/service/impl/LoginServiceImpl.java b/src/backend/job-gateway/src/main/java/com/tencent/bk/job/gateway/web/service/impl/LoginServiceImpl.java index 9b8bd8ac35..8181fffd49 100644 --- a/src/backend/job-gateway/src/main/java/com/tencent/bk/job/gateway/web/service/impl/LoginServiceImpl.java +++ b/src/backend/job-gateway/src/main/java/com/tencent/bk/job/gateway/web/service/impl/LoginServiceImpl.java @@ -30,15 +30,19 @@ import com.google.common.util.concurrent.UncheckedExecutionException; import com.tencent.bk.job.common.constant.ErrorCode; import com.tencent.bk.job.common.exception.InternalException; +import com.tencent.bk.job.common.i18n.locale.LocaleUtils; import com.tencent.bk.job.common.model.dto.BkUserDTO; import com.tencent.bk.job.common.paas.login.ILoginClient; import com.tencent.bk.job.gateway.config.BkConfig; import com.tencent.bk.job.gateway.web.service.LoginService; +import lombok.Getter; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.stereotype.Service; +import java.util.Objects; import java.util.Optional; import java.util.concurrent.ExecutionException; import java.util.concurrent.TimeUnit; @@ -49,14 +53,22 @@ public class LoginServiceImpl implements LoginService { private final BkConfig bkConfig; private final String tokenName; private final String loginUrl; - private final ILoginClient loginClient; - private LoadingCache> onlineUserCache = CacheBuilder.newBuilder() + private final ILoginClient enLoginClient; + private final ILoginClient cnLoginClient; + private LoadingCache> onlineUserCache = CacheBuilder.newBuilder() .maximumSize(200).expireAfterWrite(10, TimeUnit.SECONDS).build( - new CacheLoader>() { + new CacheLoader>() { @Override - public Optional load(String bkToken) throws Exception { + public Optional load(BkTokenWithLang bkTokenWithLang) throws Exception { try { - BkUserDTO userDto = loginClient.getUserInfoByToken(bkToken); + String lang = bkTokenWithLang.getLang(); + String bkToken = bkTokenWithLang.getBkToken(); + BkUserDTO userDto; + if (LocaleUtils.LANG_ZH_CN.equals(lang)) { + userDto = cnLoginClient.getUserInfoByToken(bkToken); + } else { + userDto = enLoginClient.getUserInfoByToken(bkToken); + } return Optional.ofNullable(userDto); } catch (Exception e) { return Optional.empty(); @@ -66,13 +78,16 @@ public Optional load(String bkToken) throws Exception { ); @Autowired - public LoginServiceImpl(BkConfig bkConfig, ILoginClient loginClient) { + public LoginServiceImpl(BkConfig bkConfig, + @Qualifier("enLoginClient") ILoginClient enLoginClient, + @Qualifier("cnLoginClient") ILoginClient cnLoginClient) { this.bkConfig = bkConfig; - this.loginClient = loginClient; + this.enLoginClient = enLoginClient; + this.cnLoginClient = cnLoginClient; this.loginUrl = getLoginUrlProp(); this.tokenName = bkConfig.isCustomPaasLoginEnabled() ? bkConfig.getCustomLoginToken() : "bk_token"; log.info("Init login service, customLoginEnabled:{}, loginClient:{}, loginUrl:{}, tokenName:{}", - bkConfig.isCustomPaasLoginEnabled(), loginClient.getClass(), loginUrl, tokenName); + bkConfig.isCustomPaasLoginEnabled(), enLoginClient.getClass(), loginUrl, tokenName); } private String getLoginUrlProp() { @@ -96,14 +111,43 @@ public void deleteUser(String bkToken) { onlineUserCache.invalidate(bkToken); } + @Getter + class BkTokenWithLang { + private String bkToken; + private String lang; + + BkTokenWithLang(String bkToken, String lang) { + this.bkToken = bkToken; + this.lang = lang; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (!(o instanceof BkTokenWithLang)) return false; + BkTokenWithLang that = (BkTokenWithLang) o; + return Objects.equals(bkToken, that.bkToken) && + Objects.equals(lang, that.lang); + } + + @Override + public int hashCode() { + return Objects.hash(bkToken, lang); + } + } @Override - public BkUserDTO getUser(String bkToken) { + public BkUserDTO getUser(String bkToken, String lang) { if (StringUtils.isBlank(bkToken)) { return null; } + if (StringUtils.isBlank(lang)) { + log.warn("getUser: lang is null or blank, use default en"); + lang = LocaleUtils.LANG_EN; + } try { - Optional userDto = onlineUserCache.get(bkToken); + BkTokenWithLang bkTokenWithLang = new BkTokenWithLang(bkToken, lang); + Optional userDto = onlineUserCache.get(bkTokenWithLang); return userDto.orElse(null); } catch (ExecutionException | UncheckedExecutionException e) { log.warn("Error occur when get user from paas!");