2009-05-26 3 views
41

Gibt es eine Möglichkeit, Sitzungsverwaltung oder Sicherheit programmatisch in Jersey, z. Web-Anwendungssitzungsverwaltung? Oder werden Transaktionen, Sitzungen und Sicherheit alle von dem Container behandelt, in dem die Jersey-Anwendung bereitgestellt wird?Jersey Sicherheit und Session-Management

+0

Ich habe gerade angefangen, dies auch zu untersuchen. Ich werde antworten, wenn ich irgendetwas finde –

Antwort

68

Sitzungsverwaltung ist der Bereich des Containers, in dem Jersey bereitgestellt wird. In den meisten Produktionsfällen wird es in einem Container bereitgestellt, der die Sitzungsverwaltung ausführt.

Der folgende Code ist ein einfaches Beispiel für eine Jersey-Ressource, die das Sitzungsobjekt abruft und Werte in der Sitzung speichert und sie bei nachfolgenden Aufrufen abruft.

@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

Danke Jack, ich brauchte das, weil wir irgendeine Art von Zugriffskontrolle auf JAX-RS Web Services implementieren müssen .. jede Hilfe wird auch sehr geschätzt .. Vielen Dank im Voraus , Adhir – Adhir

+0

@Jack Cox: Ich habe eine verwandte Frage hier gepostet: http://StackOverflow.com/Questions/9676588/How-Can-Sie-authenticate-use-the-Jersey-Client-against-a-jaas- enabled-web-serv Vielleicht könnten Sie das auch auf der Client-Seite (mit Jersey-Client) tun? – carlspring

+0

@Jack Cox, wenn ich eine Anwendung mit 1000 Benutzern gleichzeitig angemeldet habe und jedes Set 'session.setAttribute (" Benutzername ", Benutzername)'. Versteht Java, dass es 1000 verschiedene Sitzungen mit jeweils einer Variablen namens "username" gibt, deren Wert sich von den anderen unterscheidet? – kasavbere

6

Jacks Antwort über Sitzungen ist korrekt. Sie sind spezifisch für den Container, den Sie ausführen, obwohl die Servlet-Spezifikation zumindest Portabilität zwischen JavaEE-Containern bietet.

Aus Sicherheitsgründen haben Sie zumindest die Möglichkeit, ihn von Ihrem JAX-RS-spezifischen Code zu trennen, indem Sie JaaS (Java Authentication and Authorization Service) und servlet filter verwenden. Der Filter kann verwendet werden, um die HTTP-Authentifizierung zu erzwingen, und bei erfolgreicher Authentifizierung richten Sie den JaaS-Betreff mit den entsprechenden Principals ein. Ihre JAX-RS-Ressourcen können nach den entsprechenden Principals zum Betreff suchen. Da Sie den gesamten Stack steuern, sollten Sie sich auf einen authentifizierten Benutzer in Ihren Ressourcen verlassen können (aber testen Sie dies!), Und Sie können die Autorisierung basierend auf der aktuellen Operation im Ressourcencode erzwingen.

+1

+1 Klingt nach einer guten Idee. Wie genau konntest du es an Grizzly arbeiten lassen? Ich habe eine neue Frage gestellt. http://stackoverflow.com/questions/1682061/using-jaas-with-jersey-on-grizzly – User1

3

Für Jersey Sicherheit sollten Sie einen Blick auf Jersey OAuth Unterstützung werfen. OAuth passt perfekt, wenn Sie die API für Ihr System externen Benutzern zur Verfügung stellen. Zum Beispiel wie die linkedin api

http://wikis.oracle.com/display/Jersey/OAuth

+0

Bitte korrigieren Sie den Link – bekce

23

Ich dachte, dass Sitzungen etwas ist, wir sollten nie Einsatz in RESTful-Anwendungen ...

Yegor rechts. Wir sollten nie Zustand in der Server-Seite a la konventionellen Web-Anwendung beibehalten. Wenn Sie eine entkoppelte SOA-orientierte Anwendung erstellen möchten, müssen Sie keine API/Framework für REST-Webdienste verwenden. Wenn Sie den globalen Client-Server-Status auf der Serverseite beibehalten möchten oder möchten, erstellen Sie implizit so etwas, was wir als SOA-orientierte [web] -App beschreiben könnten, verwenden Jersey jedoch wie ein [Web] -Entwicklungsframework. Versehentlich verdrehen Sie die Natur eines Web-Service (REST oder anders). Sie können tun es in der Art, wie es in der ersten Antwort vorgeschlagen wurde, aber Sie müssen nicht. Das Endergebnis ist kein Web-Service, sondern eine reguläre App, die mit Tools von Web-Services erstellt wurde.

-_o

+2

Das ist nicht immer wahr. Wenn die Sitzung als Mittel zum Zwischenspeichern von Antworten verwendet wird, könnte man argumentieren, dass sie dazu verwendet wird, die Leistung zu verbessern. Sie können immer noch eine statusfreie Anwendung schreiben, nur mit einer Sitzung als Caching-Mechanismus. – Vladimir

+0

Websites wie Facebook verwenden Sitzungen über Webservices, um Webapps auszuführen. Es ist nicht von Natur aus falsch. Möglicherweise möchten Sie auch, dass ein Benutzer für die Verwendung eines Webdienstes authentifiziert wird. In diesem Fall sollten Sie die Anmeldeinformationen nicht jedes Mal weitergeben. – DiamondDrake

4

Ich löste dieses Problem, indem die Clients die Authorization-Header hinzufügen zu müssen und es in der REST-Methode wie diese Prüfung:

@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 

diese Weise wird die Authentifizierung ohne eine Sitzung zu starten.

+1

Hinweis: Dies ist völlig unsicher, es sei denn, Sie erzwingen HTTPS-Verbindungen. In diesem Fall können Sie auch dropwizard-auth verwenden. – Lambart

15

Ja, es ist möglich.documentation Jersey sagt:

Sicherheitsinformationen einer Anfrage ein JAX-RS Security Instanz mit @Context Anmerkung durch die Injektion zur Verfügung steht. Die injizierte Sicherheitskontextinstanz bietet das Äquivalent der Funktionalität , die auf der HttpServletRequest-API verfügbar ist. Der injizierte Sicherheitskontext hängt von der tatsächlichen Bereitstellung der Jersey-Anwendung ab. Beispiel: Für eine Jersey-Anwendung, die in einem Servlet-Container bereitgestellt wird, kapselt der Jersey SecurityContext Informationen aus einem Sicherheitskontext ein, der von der Servlet-Anforderung abgerufen wurde. Im Falle einer Jersey-Anwendung , die auf einem Grizzly-Server bereitgestellt wird, gibt der SecurityContext Informationen aus der Grizzly-Anfrage zurück.

Beispiel:

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

oder

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

Oder wenn Sie Sicherheit aus der Box mit Anmerkungen wollen überprüfen these docs.

Jersey können Sie auch die Security anpassen:

Die Security kann direkt aus ContainerRequestContext über getSecurityContext() -Methode abgerufen werden. Sie können auch den Standardsicherheitskontext in einem Anforderungskontext durch einen benutzerdefinierten ersetzen, der die setSecurityContext (SecurityContext) -Methode verwendet. Wenn Sie eine benutzerdefinierte SecurityContext-Instanz in Ihrem ContainerRequestFilter festlegen, wird diese Sicherheitskontextinstanz für die Injektion in JAX-RS Ressourcenklassenfelder verwendet. Auf diese Weise können Sie einen benutzerdefinierten Authentifizierungsfilter implementieren, der möglicherweise Ihren eigenen SecurityContext als verwendet. Um die frühzeitige Ausführung des benutzerdefinierten Authentifizierungsanforderungsfilters sicherzustellen, setzen Sie die Filterpriorität auf AUTHENTICATION unter Verwendung der Konstanten von Priorities. Eine frühzeitige Ausführung Ihrer Authentifizierung Filter wird sicherstellen, dass alle anderen Filter, Ressourcen, Ressourcenmethoden und Unter-Ressource-Locators mit Ihrer benutzerdefinierten SecurityContext-Instanz ausgeführt werden.

Siehe examples on how to use request filters with Jersey. Und überprüfe mein folgendes Beispiel:

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

Warnung! This was introduced in Jersey 2.4. Glassfish 4.0.0 verwendet altes Jersey 2.0, daher müssen Sie upgrade Jersey using these tips haben (es funktioniert nicht gut). Oder der bessere Weg ist, the nightly build of Glassfish 4.0.1 herunterzuladen. aber im Moment ist es nicht vollkommen stabil. Ich hoffe, dass die neue Version bald veröffentlicht wird.

UPDATE: Im Moment (2014.02.14) Glassfish 4.0.1 Nightly Build verwendet Jersey 2.5.1 und Kontext Injektion funktioniert super.

+1

Große Antwort! Vielen Dank –

2

Sie können @path verwenden, um die Dienste unter einem einzigen Namensraum zu gruppieren. Beispiel.

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

Sie können Sie Sitzung in dieser Filterklasse validieren.