2009-05-26 19 views
41

¿Existe alguna manera de obtener administración de sesión o seguridad de forma programática en Jersey, p. ¿gestión de sesión de aplicaciones web? ¿O todas las transacciones, sesiones y seguridad son manejadas por el contenedor en el que se implementa la aplicación Jersey?jersey security and session management

+0

Acabo de comenzar a investigar esto también. Voy a responder de nuevo si encuentro algo –

Respuesta

68

La gestión de sesiones es el ámbito del contenedor en el que se implementa Jersey. En la mayoría de los casos de producción, se desplegará dentro de un contenedor que realiza la administración de la sesión.

El siguiente código es un ejemplo simple de un recurso de jersey que obtiene el objeto de sesión y almacena los valores en la sesión y los recupera en llamadas posteriores.

@Path("/helloworld") 
public class HelloWorld { 

    @GET 
    @Produces("text/plain") 
    public String hello(@Context HttpServletRequest req) { 

     HttpSession session= req.getSession(true); 
     Object foo = session.getAttribute("foo"); 
     if (foo!=null) { 
      System.out.println(foo.toString()); 
     } else { 
      foo = "bar"; 
      session.setAttribute("foo", "bar"); 
     } 
     return foo.toString(); 


    } 
} 
+0

Gracias Jack, lo necesitaba porque tenemos que implementar algún tipo de control de acceso en los servicios web JAX-RS ... cualquier ayuda en eso también será muy apreciada. Gracias de antemano , Adhir – Adhir

+0

@Jack Cox: He publicado una pregunta relacionada aquí: http://stackoverflow.com/questions/9676588/how-can-you-authenticate-using-the-jersey-client-against-a-jaas- enabled-web-serv ¿Quizás sabría cómo hacer esto en el lado del cliente (con jersey-client) también? – carlspring

+0

@Jack Cox, si tengo una aplicación con 1000 usuarios conectados en ella al mismo tiempo y cada conjunto 'session.setAttribute (" username ", username)'. ¿Comprende Java que hay 1000 sesiones diferentes cada una con una variable llamada 'username' con un valor diferente de los demás? – kasavbere

6

La respuesta de Jack sobre las sesiones es la correcta. Son específicos del contenedor en el que se ejecuta, aunque la especificación de Servlet al menos le ofrece portabilidad entre contenedores JavaEE.

En cuanto a la seguridad, al menos tiene la oportunidad de separarlo de su código específico JAX-RS mediante el empleo de JaaS (Servicio de Autenticación y Autorización de Java) y un servlet filter. El filtro se puede usar para hacer cumplir la autenticación HTTP y, en la autenticación exitosa, configurar el Asunto JaaS con los Principals apropiados. Sus recursos JAX-RS pueden verificar los Principios apropiados sobre el tema. Como controlas toda la pila, deberías poder confiar en un usuario autenticado en tus recursos (¡pero prueba esto!) Y puedes aplicar la autorización en función de la operación actual en el código de recursos.

+1

+1 Parece una buena idea. ¿Cómo podría hacerlo funcionar en Grizzly? Abrí una nueva pregunta. http://stackoverflow.com/questions/1682061/using-jaas-with-jersey-on-grizzly – User1

23

pensé que las sesiones es algo que debería Nunca uso en aplicaciones RESTful ...

Yegor es correcto. No deberíamos nunca mantener el estado en el lado del servidor a la aplicación web convencional. Si desea construir una aplicación desacoplada orientada a SOA, no necesita utilizar ninguna API/framework para los servicios web REST. Si necesita o desea mantener el estado global de cliente-servidor del lado del servidor, está construyendo implícitamente lo que podríamos describir como una aplicación web [orientada a SOA], pero utilizando Jersey como un tipo de estructura de desarrollo [web]. Inadvertidamente está torciendo la naturaleza de un servicio web (REST o de otro tipo). Usted puede hacerlo de la forma en que se sugirió en la primera respuesta, pero no debe. El resultado final no es un servicio web, solo una aplicación normal construida con herramientas de servicios web.

-_o

+2

Eso no siempre es verdad. Si la sesión se utiliza como un medio de respuestas de almacenamiento en caché, entonces se podría argumentar que se usa para mejorar el rendimiento. Aún puede escribir una aplicación sin estado, solo con una sesión como mecanismo de almacenamiento en caché. – Vladimir

+0

sitios web como facebook usan sesiones en la parte superior de los servicios web para ejecutar webapps. No es intrínsecamente incorrecto. También es posible que desee que un usuario se autentique para usar un servicio web, en cuyo caso no le gustaría pasar credenciales en todo momento. – DiamondDrake

4

que resolvieron este problema haciendo que los clientes añadir la cabecera de Autorización y probarlo en el méthode RESTO así:

@GET 
@PRODUCES(MediaType.APPLICATION_JSON) 
public String returnClients(@Context HTTPServletRequest request(
    String auth = request.getHeader("Authorization"); 
    Account acc = null; 
    if (auth!=null) { 
     Account acc = Utils.LoginAccount(auth); 
    } 
    if (acc == null) 
    // not logged in, handle it gracefully 

De esta manera no es la autenticación sin iniciar una sesión.

+1

NB: Esto es totalmente inseguro a menos que esté forzando conexiones HTTPS, en cuyo caso también podría usar dropwizard-auth. – Lambart

15

Sí, es posible.Jersey documentation dice:

información de seguridad de una solicitud está disponible mediante la inyección de un JAX-RS ejemplo SecurityContext usando anotación @Context. La instancia de contexto de seguridad inyectada proporciona el equivalente de la funcionalidad disponible en HttpServletRequest API. El contexto de seguridad inyectado depende de la implementación real de la aplicación Jersey. Por ejemplo, para una aplicación de Jersey desplegada en un contenedor Servlet, Jersey SecurityContext encapsulará información de un contexto de seguridad recuperado de la solicitud de servlet. En el caso de una aplicación de Jersey desplegada en un servidor Grizzly, el SecurityContext devolverá la información recuperada de la solicitud de Grizzly.

Ejemplo:

@Path("basket") 
public ShoppingBasketResource get(@Context SecurityContext sc) { 
    if (sc.isUserInRole("PreferredCustomer") { 
     return new PreferredCustomerShoppingBasketResource(); 
    } else { 
     return new ShoppingBasketResource(); 
    } 
} 

o

@Path("resource") 
@Singleton 
public static class MyResource { 
    // Jersey will inject proxy of Security Context 
    @Context 
    SecurityContext securityContext; 

    @GET 
    public String getUserPrincipal() { 
     return securityContext.getUserPrincipal().getName(); 
    } 
} 

O si quieres seguridad fuera de la caja con anotaciones comprobar these docs.

Jersey también le permite personalizar la SecurityContext:

El SecurityContext puede ser recuperada directamente de ContainerRequestContext través getSecurityContext método(). También puede reemplazar el SecurityContext predeterminado en un contexto de solicitud con un personalizado usando el método setSecurityContext (SecurityContext). Si configura una instancia personalizada de SecurityContext en su ContainerRequestFilter, esta instancia de contexto de seguridad se usará para inyección en los campos de clase de recurso JAX-RS . De esta forma puede implementar un filtro de autenticación personalizado que puede configurar su propio SecurityContext para que sea utilizado. Para garantizar la ejecución anticipada de su filtro de solicitud de autenticación personalizada , establezca la prioridad del filtro en AUTENTIFICACIÓN utilizando las constantes de Prioridades. Una ejecución temprana del filtro de autentificación asegurará que todos los demás filtros, recursos, métodos de recursos y localizadores de sub-recursos se ejecutarán con su instancia personalizada de SecurityContext.

Ver examples on how to use request filters with Jersey. Y compruebe mi siguiente ejemplo:

import javax.annotation.Priority; 
import javax.ws.rs.Priorities; 

@Provider 
@Priority(Priorities.AUTHENTICATION) 
public class AuthRequestFilter implements ContainerRequestFilter { 
    @Context 
    HttpServletRequest webRequest; 

    @Override 
    public void filter(ContainerRequestContext requestContext) throws IOException { 
     final HttpSession session = webRequest.getSession(); 

     requestContext.setSecurityContext(new SecurityContext() { 
      @Override 
      public Principal getUserPrincipal() { 
       return new PrincipalImpl((String)session.getAttribute("USER_NAME")); 
      } 

      @Override 
      public boolean isUserInRole(String s) { 
       return false; 
      } 

      @Override 
      public boolean isSecure() { 
       return false; 
      } 

      @Override 
      public String getAuthenticationScheme() { 
       return null; 
      } 
     }); 
    } 
} 

¡Advertencia! This was introduced in Jersey 2.4. Glassfish 4.0.0 usa el antiguo Jersey 2.0, por lo tanto, tendrá que upgrade Jersey using these tips (no está probado que funcione bien). O la mejor manera es descargar the nightly build of Glassfish 4.0.1. pero no es completamente estable en este momento. Espero que la nueva versión sea lanzada pronto.

ACTUALIZACIÓN: En el momento (14/02/2014) Glassfish 4.0.1 nightly build utiliza Jersey 2.5.1 e inyección contexto funciona muy bien.

+1

¡Gran respuesta! Gracias –

2

Puede usar @path para agrupar los servicios en el espacio de nombre único. ejemplo.

@Path("/helloworld") 
public class HelloWorld { 

    @GET 
    @Produces("text/plain") 
    public String hello() { 


     return ""; 


    } 
}
Instead of @Path("/helloworld") use 
@Path("admin/helloworld") to expose you class as rest and bind filter on "admin/" 
in web.xml as below. 

<servlet> 
      <servlet-name>jersey-serlvet</servlet-name> 
      <servlet-class>com.sun.jersey.spi.container.servlet.ServletContainer</servlet-class> 
      <init-param> 
       <param-name>com.sun.jersey.config.property.packages</param-name> 
       <param-value>/</param-value> 
      </init-param> 
      <load-on-startup>1</load-on-startup> 
     </servlet> 
     <servlet-mapping> 
      <servlet-name>jersey-serlvet</servlet-name> 
      <url-pattern>/rest/*</url-pattern> 
     </servlet-mapping> 
     <filter> 
      <filter-name>myfilter</filter-name> 
      <filter-class>com.Filterclass</filter-class> 
     </filter> 
     <filter-mapping> 
      <filter-name>myfilter</filter-name> 
      <url-pattern>/rest/admin/*</url-pattern> 
     </filter-mapping> 

    public class Filterclass implements Filter { 
     public void doFilter(ServletRequest request, ServletResponse response, 
       FilterChain chain) 
       throws IOException, ServletException { 
        try{ 
         chain.doFilter(request, response); 
        }catch(Exception e){ 
        e.printStackTrace(); 
         } 
      } 
    }

Puede que validar la sesión en esta clase de filtro.