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 89b7a91 commit 8ef1788
Show file tree
Hide file tree
Showing 11 changed files with 127 additions and 9 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -216,6 +216,7 @@

##业务错误-用户服务、登录服务
1247001=用户不存在或者未登录
1247403=无该应用访问权限



Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -216,6 +216,7 @@

## Business error - User/Login
1247001=User does not exist or is not logged in
1247403=Do not have access permission for the current application

## Business error - Backup
1249001=Fail to get node info from artifactory
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -216,6 +216,7 @@

## Business error - User/Login
1247001=User does not exist or is not logged in
1247403=Do not have access permission for the current application

## Business error - Backup
1249001=Fail to get node info from artifactory
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -216,6 +216,7 @@

##业务错误-用户服务、登录服务
1247001=用户不存在或者未登录
1247403=无该应用访问权限



Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -216,6 +216,7 @@

##业务错误-用户服务、登录服务
1247001=用户不存在或者未登录
1247403=无该应用访问权限



Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ public class Response<T> {
@ApiModelProperty("错误信息")
private String errorMsg;

@ApiModelProperty("请求成功返回的数据")
@ApiModelProperty("请求成功/失败返回的数据")
private T data;

@ApiModelProperty("请求 ID")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand Down Expand Up @@ -150,6 +154,10 @@ private <R> void requestEsbApi(BkApiContext<? extends EsbReq, R> 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(
Expand Down
Original file line number Diff line number Diff line change
@@ -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;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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) {
Expand Down Expand Up @@ -81,7 +90,13 @@ private BkUserDTO getUserInfo(EsbReq esbReq) {
new TypeReference<EsbResp<EsbUserDto>>() {
}
);
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);
Expand All @@ -91,6 +106,17 @@ private BkUserDTO getUserInfo(EsbReq esbReq) {
}
}

private void handleNotOkResp(EsbResp<EsbUserDto> 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());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,21 +24,28 @@

package com.tencent.bk.job.gateway.filter.web;

import com.tencent.bk.job.common.constant.ErrorCode;
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;
import org.apache.commons.lang3.StringUtils;
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.core.io.buffer.DataBuffer;
import org.springframework.http.HttpStatus;
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;

/**
Expand Down Expand Up @@ -87,13 +94,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);
} catch (AppPermissionDeniedException e) {
return getUserAccessAppForbiddenResp(response, e.getMessage());
}
if (user == null) {
log.warn("Invalid user token");
Expand All @@ -108,6 +113,27 @@ private GatewayFilter getLoginFilter() {
};
}

private Mono<Void> getUserAccessAppForbiddenResp(ServerHttpResponse response, String data) {
Response<?> resp = new Response<>(ErrorCode.USER_ACCESS_APP_FORBIDDEN, data);
response.setStatusCode(HttpStatus.FORBIDDEN);
String body = JsonUtils.toJson(resp);
DataBuffer dataBuffer = response.bufferFactory().wrap(body.getBytes(StandardCharsets.UTF_8));
response.getHeaders().setContentLength(body.length());
response.writeWith(Mono.just(dataBuffer)).subscribe();
return response.setComplete();
}

private BkUserDTO getUserByTokenList(List<String> bkTokenList) {
// 遍历所有传入token找出当前环境的
for (String bkToken : bkTokenList) {
BkUserDTO user = loginService.getUser(bkToken);
if (user != null) {
return user;
}
}
return null;
}

@Override
public GatewayFilter apply(Config config) {
if (loginExemptionConfig.isEnableLoginExemption()) {
Expand Down

0 comments on commit 8ef1788

Please sign in to comment.