Skip to content

Commit

Permalink
feature: 支持蓝鲸应用级别的权限控制跳转 TencentBlueKing#2238
Browse files Browse the repository at this point in the history
支持国际化
  • Loading branch information
jsonwan committed Jul 19, 2023
1 parent 8ef1788 commit c2643f6
Show file tree
Hide file tree
Showing 6 changed files with 102 additions and 27 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@

import java.util.List;

import static com.tencent.bk.job.common.i18n.locale.LocaleUtils.COMMON_LANG_HEADER;
import static org.springframework.web.reactive.function.server.RequestPredicates.GET;

@Slf4j
Expand Down Expand Up @@ -95,6 +96,7 @@ Mono<ServerResponse> getUserByBkToken(ServerRequest request) {

String tokenCookieName = loginService.getCookieNameForToken();
List<String> cookieList = request.headers().header("cookie");
String lang = request.headers().firstHeader(COMMON_LANG_HEADER);

List<String> bkTokenList = RequestUtil.getCookieValuesFromCookies(cookieList, tokenCookieName);
if (CollectionUtils.isEmpty(bkTokenList)) {
Expand All @@ -107,7 +109,7 @@ Mono<ServerResponse> getUserByBkToken(ServerRequest request) {
BkUserDTO user = null;
// 遍历所有传入token找出当前环境的
for (String bkToken : bkTokenList) {
user = loginService.getUser(bkToken);
user = loginService.getUser(bkToken, lang);
if (user != null) {
break;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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()
);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
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;
Expand All @@ -48,6 +49,8 @@
import java.nio.charset.StandardCharsets;
import java.util.List;

import static com.tencent.bk.job.common.i18n.locale.LocaleUtils.COMMON_LANG_HEADER;

/**
* 用户token校验
*/
Expand Down Expand Up @@ -81,6 +84,11 @@ private GatewayFilter getLoginFilter() {
ServerHttpResponse response = exchange.getResponse();
String tokenCookieName = loginService.getCookieNameForToken();
List<String> bkTokenList = RequestUtil.getCookieValuesFromHeader(request, tokenCookieName);
String lang = RequestUtil.getCookieValue(request, COMMON_LANG_HEADER);
if (StringUtils.isBlank(lang)) {
lang = LocaleUtils.LANG_EN;
log.warn("Cannot find blueking_language in cookie, use en");
}
if (CollectionUtils.isEmpty(bkTokenList)) {
log.warn("Fail to parse token from headers, please check");
String bkToken = RequestUtil.getCookieValue(request, tokenCookieName);
Expand All @@ -96,7 +104,7 @@ private GatewayFilter getLoginFilter() {
}
BkUserDTO user;
try {
user = getUserByTokenList(bkTokenList);
user = getUserByTokenList(bkTokenList, lang);
} catch (AppPermissionDeniedException e) {
return getUserAccessAppForbiddenResp(response, e.getMessage());
}
Expand All @@ -123,10 +131,10 @@ private Mono<Void> getUserAccessAppForbiddenResp(ServerHttpResponse response, St
return response.setComplete();
}

private BkUserDTO getUserByTokenList(List<String> bkTokenList) {
private BkUserDTO getUserByTokenList(List<String> bkTokenList, String lang) {
// 遍历所有传入token找出当前环境的
for (String bkToken : bkTokenList) {
BkUserDTO user = loginService.getUser(bkToken);
BkUserDTO user = loginService.getUser(bkToken, lang);
if (user != null) {
return user;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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<String, Optional<BkUserDTO>> onlineUserCache = CacheBuilder.newBuilder()
private final ILoginClient enLoginClient;
private final ILoginClient cnLoginClient;
private LoadingCache<BkTokenWithLang, Optional<BkUserDTO>> onlineUserCache = CacheBuilder.newBuilder()
.maximumSize(200).expireAfterWrite(10, TimeUnit.SECONDS).build(
new CacheLoader<String, Optional<BkUserDTO>>() {
new CacheLoader<BkTokenWithLang, Optional<BkUserDTO>>() {
@Override
public Optional<BkUserDTO> load(String bkToken) throws Exception {
public Optional<BkUserDTO> 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();
Expand All @@ -66,13 +78,16 @@ public Optional<BkUserDTO> 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() {
Expand All @@ -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<BkUserDTO> userDto = onlineUserCache.get(bkToken);
BkTokenWithLang bkTokenWithLang = new BkTokenWithLang(bkToken, lang);
Optional<BkUserDTO> userDto = onlineUserCache.get(bkTokenWithLang);
return userDto.orElse(null);
} catch (ExecutionException | UncheckedExecutionException e) {
log.warn("Error occur when get user from paas!");
Expand Down
14 changes: 7 additions & 7 deletions src/backend/job-gateway/src/main/resources/application.yml
Original file line number Diff line number Diff line change
Expand Up @@ -26,64 +26,64 @@ spring:
predicates:
- Path= /job-manage/web/**
filters:
- AddWebLangHeader
- Authorize
- CsrfCheck
- StripPrefix=1
- AddWebLangHeader
- id: job-crontab-web
uri: lb://job-crontab
predicates:
- Path= /job-crontab/web/**
filters:
- AddWebLangHeader
- Authorize
- CsrfCheck
- StripPrefix=1
- AddWebLangHeader
- id: job-execute-web
uri: lb://job-execute
predicates:
- Path= /job-execute/web/**
filters:
- AddWebLangHeader
- Authorize
- CsrfCheck
- StripPrefix=1
- AddWebLangHeader
- id: job-backup-web
uri: lb://job-backup
predicates:
- Path= /job-backup/web/**
filters:
- AddWebLangHeader
- Authorize
- CsrfCheck
- StripPrefix=1
- AddWebLangHeader
- id: job-file-gateway-web
uri: lb://job-file-gateway
predicates:
- Path= /job-file-gateway/web/**
filters:
- AddWebLangHeader
- Authorize
- CsrfCheck
- StripPrefix=1
- AddWebLangHeader
- id: job-ticket-web
uri: lb://job-manage
predicates:
- Path= /job-ticket/web/**
filters:
- AddWebLangHeader
- Authorize
- CsrfCheck
- StripPrefix=1
- AddWebLangHeader
- id: job-analysis-web
uri: lb://job-analysis
predicates:
- Path= /job-analysis/web/**
filters:
- AddWebLangHeader
- Authorize
- CsrfCheck
- StripPrefix=1
- AddWebLangHeader

- id: job-file-gateway-remote
uri: lb://job-file-gateway
Expand Down

0 comments on commit c2643f6

Please sign in to comment.