2012-07-03 1 views
3

У меня есть следующие ресурсы JAX-RS работает сервер HTTP Grizzly:Как определить удаленный IP-адрес с ресурса 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? 
    } 
} 

Как определить удаленный IP-адрес внутри входа (обработчик)?

Спасибо, Майкл

ответ

2

Поскольку сейчас это не possible для доступа к удаленной информации IP от Grizzly контекста, я реализовал это грязный хак:

Во-первых, у меня есть добавлено новое связующее вложение для зависимостей в мое приложение, которое свяжет экземпляр 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); 
    } 
} 

Тогда я зарегистрировал это связующее в заявке:

application.register(new RemoteAddrBinder()); 

Теперь SocketAddress может быть введен в любой метод JAX-RS:

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

Надежда это помогает кому-то :)

1

Вы должны добавить дополнительный аргумент для этого метода типа HttpServletRequest и который вы положили @Context аннотацию. Затем вы можете использовать метод getRemoteAddr() этого аргумента, чтобы получить то, что вы хотите.

@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, 
      @Context HttpServletRequest request) { 
     String remoteIP = request.getRemoteAddr(); 
     // ... 
    } 
} 

Да, это String ...

+0

Но у меня нет HttpServletRequest класса в моем пути к классам. Может быть, это потому, что я использую HTTP-сервер Grizzly? – spektom

+0

Действительно? [Javadoc I find] (http://grizzly.java.net/nonav/docs/2.0/apidocs/index.html) для Grizzly указывает, что классы довольно тщательно связаны с классами сервлета, поэтому он должен быть доступен во время выполнения (или Grizzly _wouldn't_ work).Я предполагаю, что ваш путь к классам сборки не завершен ... –

+0

Я попытался добавить API сервлета в мой путь к классам сборки, но эта переменная не вводится в среду выполнения - я получаю null. – spektom

2

Решение 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()); 
    } 
} 
2

В соответствии с разработчиками объяснениями - гризли не полностью соответствует JAX -RS 2.0, поэтому официальные контекстные инъекции/обертывание не будут. См. Jersey Bug-1960 Применимо для Jersey + Grizzly версии 2.7+

К счастью, есть способ внедрить объекты запроса/ответа Grizzly. Вид сложный, но работает Образец образца, представленный в одном из модульных тестов Джерси. См Jersey container test

Так фрагмент кода будет:

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

отлично работает как для фильтров и методов обслуживания

+0

Отлично работает (2.22.2), но вам нужно убедиться, что вы не получаете проблемы с импортом с помощью javax.ws.rs.ext.Provider и javax.inject.Provider –

Смежные вопросы