有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

java如何访问由Swagger Codegen生成的JAXRS类上的请求头

我有一个带有Swagger API的项目,它的服务器代码是由Swagger-codegen-2.4.24为JAXR语言生成的

生成的代码有一个后缀为“*ApiService”的抽象类,它定义了一系列方法,每个方法对应于API的Swagger规范中定义的每个操作

每个方法都有一个javax。ws。rs.core。SecurityContext接口局部变量

现在,在我扩展“*ApiService”的自定义类上,显然有javax。ws。rs.core。SecurityContext类局部变量,我需要获取请求头“X-Forwarded-For”的值

如果调试自定义类,我会看到SecurityContext接口是org的一个实例。玻璃鱼。运动衫服务器内部的过程SecurityContextejectee,它具有我需要的标题

既然SecurityContextejectee是私有的,我就无法使用它,那么我如何获取这些信息呢

我意识到由swagger codegen生成的if类添加了javax。servlet。http。HttpServletRequest类,除了SecurityContext之外,还可以访问请求参数,但我没有看到任何允许访问的jaxrs参数

期待您的评论


共 (1) 个答案

  1. # 1 楼答案

    在每个规范版本中,您都可以定义一个类似于可能的parameter locationsheader

    因此,一个可能的解决方案是在请求parameters部分中所需的方法中定义头:

    parameters:
        -
            name: X-Forwarded-For
            description: X-Formarwed-For header.
            schema:
                type: string
            in: header
    

    或者,用JSON表示法:

        "parameters": [
            {
                "name": "X-Forwarded-For",
                "description": "X-Formarwed-For header.",
                "schema": {
                    "type": "string"
                },
                "in": "header"
            }
        ]
    

    我知道这可能是一个不太可维护的解决方案,因为您需要在每个请求中包含头,但也许您可以通过在服务实现中使用继承来缓解这一事实

    有一个open Github issue请求您描述的行为,以一般方式处理头处理

    this related SO answer中也建议了一个合适的选项,即修改API代码生成中使用的Mustache templates,并在其中包含所需的头处理。请注意,这会降低代码的可维护性,并且您可能会执行一些更改,从而破坏与官方Swagger Codegen存储库的兼容性。我不确定在Swagger Codegen中,但是在OpenAPI生成器中,有一个选项可以覆盖所使用的模板,而无需修改官方发行版中提供的实际模板。请参见this related SO question

    尽管看起来情况不再如此,至少在Jersey的旧版本中,类是public,但您也可以尝试通过反射访问org.glassfish.jersey.server.internal.process.SecurityContextInjectee中的requestContext内部变量,尽管我认为解决方法使您的应用程序非常依赖于实现。在任何情况下,您都可以定义这样的实用工具方法,以便在服务实现中重用:

    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;
    }
    

    最后,另一种可能是使用一个filter来处理您的头。如果需要,您可以使用线程局部变量将头值传递给底层服务。这个想法是这样的

    首先,定义一个方便的对象来包装ThreadLocal值:

    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();
        }
    }
    

    接下来,创建一个ContainerRequestFilter。此筛选器将从正在处理的HTTP请求中接收的信息中读取标头:

    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
            );
        }
    }
    

    最后,利用服务实现中的价值:

    String xForwardedForHeaderValue = XForwardedForHeaderHolder.getXForwardedForHeader();
    // Clean up
    XForwardedForHeaderHolder.clean();
    

    警告一句:一方面,过滤器注册应该正常工作,但它可能取决于您正在使用的JAXRS版本和招摇过市本身;另一方面,该解决方案假设过滤器将在线程局部变量中为每个对底层服务的请求提供正确的头,换句话说,不存在任何与线程相关的问题。我认为应该是这样,但这是需要检验的