外部授权
API 网关支持外部授权功能。通过该功能,用户可以在网关将请求转发给 real-server 之前,插入一个自定义的远程接口。网关会先将请求转发给这个自定义接口,该接口继而选择是否允许这个请求正常转发到 real-server。
外部授权服务编写须知
您需要在本地开发一个外部授权接口。当 API 需要验证授权关系时,会调用该外部授权接口进行授权校验。外部授权接口不限制协议类型,但会限制请求体和响应体。请求和响应均为 JSON 字符串,格式如下:
请求体
{ "context":{ "key":"value" } }
字段说明:Request 中只有一个 context 字段,格式为 kv。这些参数来自于 client 的 request,需要在 API 网关控制台平台进行配置。
响应体
{ "success":true/false, "principal":{ "key":"value" }, "failResponseHeader":{ "key":"value" }, "failResponseBody": jsonarray/jsonobject "failResponseStatus": ${httpcode} }
字段说明:
success
:是否允许该请求转发到 real-server。principal
:如果允许转发到 real-server,可以将一些信息传递给 real-server,kv 格式。如果 real-server 是 HTTP 接口,则 principal 会放到 header 中。
如果 real-server 是 SOFARPC 接口,则 principal 会放到 baggage 中。
failResponseHeader
:如果不允许转发到 real-server,可以设置响应头返回给 client。failResponseBody
:如果不允许转发到 real-server,可以设置响应 body 给 client。failResponseStatus
:如果不允许转发到 real-server,可以设置响应 HTTP 状态码。
对应外部授权 API 的定义标准如下:
AuthRequest
publicclassAuthRequest{ private Map<String,String> context; }
AuthResponse
publicclassAuthResponse{ private boolean success; private Map<String,String> principal; private Map<String,String> failResponseHeader; private Object failResponseBody; private int failResponseStatus; }
AuthRequest 和 AuthResponse 需要按照本文提供的数据结构不能改动,类名可以自定义修改。
public class AuthRequest {
private Map<String, String> context;
public Map<String, String> getContext() {
return context;
}
public void setContext(Map<String, String> context) {
this.context = context;
}
}
@Data
public class AuthResponse {
private boolean success;
private Map<String, String> principal;
private Map<String, String> failResponseHeader;
private int failResponseStatus;
private Object failResponseBody;
public void setFailResponse(Object failResponse) {
this.failResponseBody = failResponse;
}
}
@RestController
@RequestMapping("/api")
public class AuthController {
@RequestMapping("/auth")
public AuthResponse auth(@RequestBody AuthRequest request) {
return AuthUtil.buildAuthRes(request);
}
}
public class AuthUtil {
private static final Logger LOGGER = LoggerFactory.getLogger(AuthUtil.class);
public static AuthResponse buildAuthRes(AuthRequest request) {
AuthResponse response = new ObjectAuthResponse();
//---以下都是在外部授权配置页面中配置的参数key才能在这边取得到值----
String headerKey = request.getContext().get("headerKey");
String path = request.getContext().get("x-mosn-path");
String method = request.getContext().get("x-mosn-method");
String bodyKey = request.getContext().get("bodyKey");
String queryKey = request.getContext().get("queryKey");
LOGGER.info("headerKey:" + headerKey + ",bodyKey:" + bodyKey + ",queryKey:" + queryKey + ",path:" + path + ",method:" + method);
//------ end ------
if ("h".equalsIgnoreCase(headerKey)) {
// success
response.setSuccess(true);//外部授权通过
Map<String, String> principal = new HashMap<>();
principal.put("param-to-server", "abc");
principal.put("userName", "user name is tom aaa");
response.setPrincipal(principal);//需要透传到后端服务的参数
return response;
} else {
// error
response.setSuccess(false);//外部授权失败
Map<String, String> failResponseHeader = new HashMap<>();
queryKey = request.getContext().get("queryKey");
if ("q".equalsIgnoreCase(queryKey)) {
failResponseHeader.put("header-to-client", "query");
} else {
failResponseHeader.put("header-to-client", "no-query");
}
response.setFailResponseHeader(failResponseHeader);//失败的响应头
Map<String, String> failResponseBody = new HashMap<>();
String context = JSON.toJSONString(request.getContext());
failResponseBody.put("test", context);
response.setFailResponse(failResponseBody);//失败的错误信息
response.setFailResponseStatus(401);//失败响应码
LOGGER.info("buildAuthRes|response|{}|{}", (response instanceof ByteAuthResponse), JSON.toJSONString(response));
return response;
}
}
}