Red*_*gle 6 java rest swagger swagger-codegen
我有一个带有 Swagger API 的项目,其服务器代码是由 swagger-codegen-2.4.24 为语言 jaxrs 生成的。
生成的代码有一个后缀为“*ApiService”的抽象类,它定义了一系列方法,每个方法对应于API的Swagger规范上定义的每个操作。
每个方法都有一个 javax.ws.rs.core.SecurityContext 接口局部变量。
现在,在扩展“*ApiService”的自定义类上,它显然具有 javax.ws.rs.core.SecurityContext 类局部变量,我需要获取请求标头“X-Forwarded-For”的值。
如果我调试自定义类,我会看到 SecurityContext 接口是 org.glassfish.jersey.server.internal.process.SecurityContextInjectee 的实例,它具有我需要的标头。
由于 SecurityContextInjectee 是私有的,我无法使用它,因此如何获取该信息?
我意识到,如果 swagger-codegen 生成的类除了 SecurityContext 之外还添加了 javax.servlet.http.HttpServletRequest 类,则可以访问请求参数,但我没有看到任何允许这样做的 jaxrs 参数。
期待您的评论。
在每个规范版本中,您都可以定义类似的可能参数位置header之一。
因此,一种可能的解决方案是在请求parameters部分所需的方法中定义标头:
parameters:
-
name: X-Forwarded-For
description: X-Formarwed-For header.
schema:
type: string
in: header
Run Code Online (Sandbox Code Playgroud)
或者,用 JSON 表示法:
"parameters": [
{
"name": "X-Forwarded-For",
"description": "X-Formarwed-For header.",
"schema": {
"type": "string"
},
"in": "header"
}
]
Run Code Online (Sandbox Code Playgroud)
我知道这可能是一个不太可维护的解决方案,因为您需要在每个请求中包含标头,但也许您可以通过服务实现中的继承来缓解这一事实。
有一个开放的Github 问题要求您描述的行为,以一般方式处理标头。
在此相关 SO 答案中也建议了一个合适的选项,可以修改API 代码生成中使用的Mustache 模板,并在其中包含所需的标头处理。请注意,这会降低您的代码的可维护性,并且您将面临执行某些更改而破坏与官方 Swagger Codegen 存储库的兼容性的风险。我不确定 Swagger Codegen 中的情况,但在 OpenAPI 生成器中,有一个选项可以覆盖使用的模板,而无需修改官方发行版中实际提供的模板。请参阅此相关 SO 问题。
尽管情况似乎不再如此,至少在旧版本的 Jersey 中public,您也可以尝试通过反射访问requestContext内部变量org.glassfish.jersey.server.internal.process.SecurityContextInjectee,尽管我认为这种解决方法使您的应用程序非常依赖于实现。无论如何,也许您可以定义一个像这样的实用程序方法,您可以在服务实现中重用它:
"parameters": [
{
"name": "X-Forwarded-For",
"description": "X-Formarwed-For header.",
"schema": {
"type": "string"
},
"in": "header"
}
]
Run Code Online (Sandbox Code Playgroud)
最后,另一种可能性是使用处理标头的过滤器。如果需要,您可以使用线程局部变量将标头值传递给底层服务。这个想法类似于以下内容。
首先,定义一个方便的对象来包装您的ThreadLocal值:
public static String getXForwardedForHeaderValue(final SecurityContext securityContext) {
SecurityContextInjectee securityContextImpl = (SecurityContextInjectee) securityContext;
Field requestContextField = SecurityContextInjectee.class.getDeclaredField("requestContext");
requestContextField.setAccessible(true);
ContainerRequestContext requestContext = requestContextField.get(securityContextImpl);
String xForwardedForHeaderValue = requestContext.getHeaderString("X-Forwarded-For");
return xForwardedForHeaderValue;
}
Run Code Online (Sandbox Code Playgroud)
接下来,创建一个ContainerRequestFilter. 该过滤器将从正在处理的 HTTP 请求中收到的信息中读取标头:
public class XForwardedForHeaderHolder{
private static final ThreadLocal<String> value = new ThreadLocal<String>();
public static void setXForwardedForHeader(String xForwardedFor) {
value.set(xForwardedFor);
}
public static String getXForwardedForHeader() {
return value.get();
}
public static void clean() {
value.remove();
}
}
Run Code Online (Sandbox Code Playgroud)
最后,消耗服务实现中的价值:
import java.io.IOException;
import javax.ws.rs.container.ContainerRequestContext;
import javax.ws.rs.container.ContainerRequestFilter;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.SecurityContext;
import javax.ws.rs.ext.Provider;
@Provider
public class XForwardedForHeaderRequestFilter implements ContainerRequestFilter {
@Override
public void filter(ContainerRequestContext requestContext)
throws IOException {
String xForwardedForHeaderValue = requestContext.getHeaderString("X-Forwarded-For");
XForwardedForHeaderHolder.setXForwardedForHeader(
xForwardedForHeaderValue
);
}
}
Run Code Online (Sandbox Code Playgroud)
需要注意的是:一方面,过滤器注册应该正常工作,但它可能取决于您正在使用的 JAXRS 版本和 Swagger 本身;另一方面,该解决方案假设过滤器将在线程局部变量中为底层服务的每个请求提供正确的标头,换句话说,不存在任何与线程相关的问题。我觉得应该是这样,但是这是需要检验的事情。
| 归档时间: |
|
| 查看次数: |
937 次 |
| 最近记录: |