Glassfish 如何从JAX-RS资源确定远程IP地址?

Glassfish 如何从JAX-RS资源确定远程IP地址?,glassfish,jax-rs,grizzly,Glassfish,Jax Rs,Grizzly,我在Grizzly HTTP服务器中运行了以下JAX-RS资源: @Path("/board") public class BoardResource { @POST @Consumes("application/x-www-form-urlencoded") public void login(@FormParam("email") String email, @FormParam("password") String password, @H

我在Grizzly HTTP服务器中运行了以下JAX-RS资源:

@Path("/board")
public class BoardResource {

    @POST
    @Consumes("application/x-www-form-urlencoded")
    public void login(@FormParam("email") String email, @FormParam("password") String password,
            @HeaderParam("user-agent") String userAgent) {
        // how to determine remote IP address here?
    }
}
如何在login()处理程序中确定远程IP地址

谢谢,
Michael

您应该为该类型的方法添加一个额外的参数,并将
@Context
注释放在该参数上。然后,您可以使用该参数的方法来获得您想要的

@Path(“/board”)
公共类董事会资源{
@职位
@使用(“应用程序/x-www-form-urlencoded”)
公共无效登录(@FormParam(“电子邮件”)字符串电子邮件,
@FormParam(“密码”)字符串密码,
@HeaderParam(“用户代理”)字符串userAgent,
@上下文(HttpServletRequest请求){
字符串remoteIP=request.getRemoteAddr();
// ...
}
}

是的,这是一个
字符串
..

因为现在这不是从Grizzly上下文访问远程IP信息,所以我实施了这个肮脏的攻击:

首先,我向我的应用程序添加了新的依赖项注入绑定器,它将java.net.SocketAddress实例绑定到包含请求源IP的实例:

package test;

import java.lang.reflect.Field;
import java.net.InetSocketAddress;
import java.net.SocketAddress;
import javax.inject.Inject;
import javax.inject.Provider;
import org.glassfish.grizzly.http.server.Request;
import org.glassfish.hk2.api.Factory;
import org.glassfish.hk2.utilities.binding.AbstractBinder;
import org.glassfish.jersey.internal.PropertiesDelegate;
import org.glassfish.jersey.process.internal.RequestScoped;
import org.glassfish.jersey.server.ContainerRequest;

public class RemoteAddrBinder extends AbstractBinder {

    private static class RemoteAddrProviderFactory implements Factory<SocketAddress> {
        @Inject
        private Provider<ContainerRequest> request;

        @Override
        public SocketAddress provide() {
            ContainerRequest containerRequest = request.get();
            PropertiesDelegate delegate = containerRequest.getPropertiesDelegate();
            try {
                Field requestField = delegate.getClass().getDeclaredField("request");
                requestField.setAccessible(true);
                Request grizzlyRequest = (Request) requestField.get(delegate);
                return new InetSocketAddress(grizzlyRequest.getRemoteAddr(), grizzlyRequest.getRemotePort());
            } catch (Exception e) {
                e.printStackTrace();
                return null;
            }
        }

        @Override
        public void dispose(SocketAddress instance) {
        }
    }

    @Override
    protected void configure() {        bindFactory(RemoteAddrProviderFactory.class).to(SocketAddress.class).in(RequestScoped.class);
    }
}
现在,SocketAddress可以注入到任何JAX-RS方法中:

@GET
@Path("test")
public Response test(@Context SocketAddress remoteAddr) {
    return Response.ok("Your IP is: " + ((InetSocketAddress) remoteAddr).getAddress().getHostAddress()).build();
}

希望这对某人有所帮助:)

spektom的解决方案不再适用于最新版本。幸运的是,现在有了一个更好的解决方案,将以下内容添加到方法参数中:

@Context org.glassfish.grizzly.http.server.Request req
在你的情况下,会是这样的:

@Path("/board")
public class BoardResource {

    @POST
    @Consumes("application/x-www-form-urlencoded")
    public void login(@Context Request req, @FormParam("email") String email, @FormParam("password") String password,
            @HeaderParam("user-agent") String userAgent) {
        // remote IP address
        System.out.println(req.getRemoteAddr());
    }
}

根据开发人员的解释,Grizzly不完全符合JAX-RS2.0,因此没有正式的上下文注入/包装。看见 适用于Jersey+Grizzly 2.7版+

幸运的是,有一种方法可以注入Grizzly请求/响应对象。有点棘手,但有效 Jersey的一个单元测试中提供的代码示例。看

因此,代码片段将是:

import javax.inject.Inject;
import javax.inject.Provider;

public someclass {
    @Inject
    private Provider<Request> grizzlyRequestProvider;

    public void method() {
         if (grizzlyRequestProvider != null) {
            Request httpRequest = grizzlyRequestProvider.get();

            // Extract what you need
            String remoteAddress = httpRequest.getRemoteAddr();
         }
    }
}
import javax.inject.inject;
导入javax.inject.Provider;
公共课{
@注入
私人提供商grizzlyRequestProvider;
公开作废法(){
if(grizzlyRequestProvider!=null){
请求httpRequest=grizzlyRequestProvider.get();
//提取你需要的东西
字符串remoteAddress=httpRequest.getRemoteAddr();
}
}
}

对于过滤器和服务方法都可以正常工作

,但我的类路径中没有HttpServletRequest类。也许这是因为我使用了Grizzly HTTP服务器?真的吗?for Grizzly表示类与servlet类完全相关,因此必须在运行时可用(否则Grizzly将无法工作)。我猜您的构建时类路径是不完整的…我尝试将servlet API添加到构建时类路径中,但该变量未在运行时注入-我得到null。效果很好(2.22.2),但您需要确保javax.ws.rs.ext.Provider和javax.inject.Provider不会出现导入问题
import javax.inject.Inject;
import javax.inject.Provider;

public someclass {
    @Inject
    private Provider<Request> grizzlyRequestProvider;

    public void method() {
         if (grizzlyRequestProvider != null) {
            Request httpRequest = grizzlyRequestProvider.get();

            // Extract what you need
            String remoteAddress = httpRequest.getRemoteAddr();
         }
    }
}