sicurezza della maglia e gestione delle sessioni

C’è un modo per ottenere la gestione delle sessioni o la sicurezza in modo programmatico in Jersey, ad esempio la gestione delle sessioni di applicazioni web? Oppure le transazioni, le sessioni e la sicurezza sono tutte gestite dal contenitore in cui viene distribuita l’applicazione Jersey?

La gestione delle sessioni è l’ambito del contenitore in cui viene schierato Jersey. Nella maggior parte dei casi di produzione, verrà implementato all’interno di un contenitore che esegue la gestione delle sessioni.

Il codice seguente è un semplice esempio di una risorsa jersey che ottiene l’object sessione e memorizza i valori nella sessione e li recupera nelle chiamate successive.

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

Pensavo che le sessioni fossero qualcosa che non dovremmo mai usare nelle applicazioni RESTful …

Yegor ha ragione. Non dovremmo mai mantenere lo stato sul lato server di un’applicazione web convenzionale. Se si desidera creare un’applicazione orientata SOA disaccoppiata, non è necessario utilizzare alcuna API / framework per i servizi Web REST. Se hai bisogno, o vuoi, di mantenere lo stato globale client-server sul lato del server stai costruendo implicitamente ciò che potremmo descrivere come un’app [web] orientata alla SOA, ma usando Jersey come un framework di sviluppo [web]. Inavvertitamente si distorce la natura di un servizio Web (REST o altro). Puoi farlo nel modo in cui è stato suggerito nella prima risposta, ma non devi . Il risultato finale non è un servizio web, ma solo una normale app costruita con gli strumenti dei servizi web.

-_o

Si è ansible. La documentazione di Jersey dice:

Le informazioni sulla sicurezza di una richiesta sono disponibili iniettando un’istanza SecurityContext JAX-RS usando l’annotazione @Context. L’istanza del contesto di sicurezza iniettata fornisce l’equivalente della funzionalità disponibile sull’API HttpServletRequest. Il contesto di sicurezza iniettato dipende dall’effettiva distribuzione dell’applicazione Jersey. Ad esempio, per un’applicazione Jersey distribuita in un contenitore Servlet, Jersey SecurityContext incapsulerà le informazioni da un contesto di sicurezza recuperato dalla richiesta Servlet. Nel caso di un’applicazione jersey distribuita su un server Grizzly, SecurityContext restituirà le informazioni recuperate dalla richiesta Grizzly.

Esempio:

 @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 se vuoi che la sicurezza sia pronta con le annotazioni, controlla questi documenti .

Jersey ti consente anche di personalizzare SecurityContext:

SecurityContext può essere recuperato direttamente da ContainerRequestContext tramite il metodo getSecurityContext (). È inoltre ansible sostituire SecurityContext predefinito in un contesto di richiesta con uno personalizzato utilizzando il metodo setSecurityContext (SecurityContext). Se si imposta un’istanza SecurityContext personalizzata in ContainerRequestFilter, questa istanza del contesto di sicurezza verrà utilizzata per l’iniezione nei campi della class di risorsa JAX-RS. In questo modo è ansible implementare un filtro di autenticazione personalizzato che può impostare il proprio SecurityContext da utilizzare. Per garantire l’esecuzione anticipata del filtro delle richieste di autenticazione personalizzate, imposta la priorità del filtro su AUTHENTICATION utilizzando le costanti delle priorità. Un’esecuzione anticipata del filtro di autenticazione garantirà che tutti gli altri filtri, risorse, metodi di risorse e localizzatori di risorse secondarie vengano eseguiti con l’istanza SecurityContext personalizzata.

Vedi esempi su come usare i filtri di richiesta con Jersey . E controlla il mio esempio seguente:

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

Avvertimento! Questo è stato introdotto in Jersey 2.4 . Glassfish 4.0.0 utilizza la vecchia maglia 2.0, pertanto sarà necessario aggiornare Jersey utilizzando questi suggerimenti (non è dimostrato che funzioni bene). O il modo migliore è scaricare la build notturna di Glassfish 4.0.1 . ma al momento non è completamente stabile. Spero che la nuova versione sarà rilasciata presto.

AGGIORNAMENTO: Al momento (2014-02-14) Glassfish 4.0.1 nightly build usa Jersey 2.5.1 e l’iniezione di contesto funziona alla grande.

La risposta di Jack riguardo alle sessioni è corretta. Sono specifici del contenitore in cui esegui, anche se le specifiche Servlet forniscono almeno la portabilità tra i contenitori JavaEE.

Per quanto riguarda la sicurezza, hai almeno l’opportunità di separarlo dal codice specifico JAX-RS utilizzando JaaS (servizio di autenticazione e authorization Java) e un filtro servlet . Il filtro può essere utilizzato per imporre l’autenticazione HTTP e, in caso di authorization riuscita, impostare il sobject JaaS con i Principali appropriati. Le risorse JAX-RS possono controllare i Principali appropriati sull’argomento. Dal momento che controlli l’intero stack, dovresti essere in grado di fare affidamento su un utente autenticato nelle tue risorse (ma provalo!) E puoi imporre l’authorization in base all’operazione corrente nel codice risorsa.

Ho risolto questo problema facendo in modo che i client aggiungessero l’intestazione Authorization e lo testassero nel metodo REST in questo modo:

 @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 

In questo modo c’è l’autenticazione senza avviare una sessione.

Per la sicurezza di Jersey dovresti dare un’occhiata al supporto OAuth della maglia. OAuth si adatta perfettamente quando si espongono le API per il proprio sistema a utenti esterni. Ad esempio come il linkedin api

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

È ansible utilizzare @path per raggruppare i servizi nello spazio per i nomi singoli. esempio .

 @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.  jersey-serlvet com.sun.jersey.spi.container.servlet.ServletContainer  com.sun.jersey.config.property.packages /  1   jersey-serlvet /rest/*   myfilter com.Filterclass   myfilter /rest/admin/*  
 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(); } } } 

È ansible convalidare la sessione in questa class di filtro.