segurança Jersey e gerenciamento de sessão
Pergunta
Existe uma maneira de obter o gerenciamento de sessão ou a segurança programaticamente em Jersey, por exemplo, web-aplicativo de gerenciamento de sessão? Ou se são transacções, sessões e segurança todos tratados pelo contêiner em que o pedido Jersey é implantado?
Solução
Gerenciamento de sessão é da competência do recipiente em que Jersey é implantado. Na maioria dos casos de produção, ele será implantado dentro de um recipiente que o gerenciamento de sessão executa.
O código a seguir é um exemplo simples de um recurso camisa que obtém os valores objeto de sessão e armazena na sessão e recupera-los em chamadas subsequentes.
@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();
}
}
Outras dicas
Eu pensei que as sessões é algo que devemos não uso em aplicações RESTful ...
Yegor é certo. Nós não nunca deveria manter o estado no lado do servidor a la aplicação web convencional. Se você quer construir uma aplicação orientada SOA dissociado você não precisa usar qualquer API / estrutura para serviços web REST. Se você precisa, ou deseja, para manter o estado de cliente-servidor global no lado do servidor você está construindo implicitamente o que poderíamos descrever como um aplicativo [web] orientado a SOA, mas usando Jersey como um [web] quadro de desenvolvimento das sortes. Inadvertidamente você está torcendo a natureza de um serviço web REST (ou não). Você pode fazê-lo na forma como tem sido sugerido na primeira resposta, mas você não deve . O resultado final não é um serviço web, apenas um aplicativo normal construído com ferramentas dos serviços web.
-_ o
As informações de segurança de um pedido está disponível através da injeção de um JAX-RS SecurityContext exemplo usando @Context anotação. o injectado exemplo contexto de segurança fornece o equivalente da funcionalidade disponível em HttpServletRequest API. O contexto de segurança injectado depende da implantação real aplicação Jersey. Por exemplo, para uma aplicação Jersey implantado em um recipiente servlet, o Jersey SecurityContext será encapsular informações de um contexto de segurança recuperado do pedido Servlet. No caso de uma aplicação de Jersey implantado em um servidor Grizzly, o SecurityContext voltará informações obtidas a partir da solicitação Grizzly.
Exemplo:
@Path("basket")
public ShoppingBasketResource get(@Context SecurityContext sc) {
if (sc.isUserInRole("PreferredCustomer") {
return new PreferredCustomerShoppingBasketResource();
} else {
return new ShoppingBasketResource();
}
}
ou
@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();
}
}
Ou se você quiser sair da caixa de segurança com anotações verificar estes docs .
Jersey também permite que você personalize o SecurityContext:
O SecurityContext podem ser directamente recuperados a partir de ContainerRequestContext através getSecurityContext () método. Você também pode substituir os SecurityContext padrão em um contexto de solicitação com um costume um método usando o setSecurityContext (SecurityContext). Se você definir um instância costume SecurityContext em sua ContainerRequestFilter, este instância do contexto de segurança será usado para injeção em JAX-RS campos de classe de recursos. Desta forma, você pode implementar um personalizado filtro de autenticação que a instalação pode seus próprios SecurityContext ser usava. Para garantir a execução no início de sua autenticação personalizada solicitação de filtro, definir a prioridade de filtro para a autenticação usando constantes de prioridades. Uma execução antecipada de você autenticação filtro irá garantir que todos os outros filtros, recursos, métodos de recursos e localizadores de sub-recurso será executado com o seu costume SecurityContext exemplo.
sobre como usar filtros de solicitação com Jersey . E verificar o meu exemplo a seguir:
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;
}
});
}
}
Warning! Este foi introduzido em Jersey 2,4 . GlassFish 4.0.0 usos antigos Jersey 2.0, portanto você terá que atualizar Jersey usando essas dicas (não é comprovada para funcionar bem). Ou a melhor maneira é fazer o download o nightly build do Glassfish 4.0.1 . mas não é completamente estável no momento. Espero que a nova versão será lançada em breve.
UPDATE: No momento (2014/02/14) Glassfish 4.0.1 nightly build usa Jersey 2.5.1 e injeção contexto funciona muito bem.
A resposta de Jack sobre sessões está correto. Eles são específicos para o recipiente que é executado em, embora a especificação Servlet, pelo menos, dá-lhe a portabilidade entre recipientes JavaEE.
Quanto à segurança, você pelo menos tem a oportunidade de separá-lo de seus JAX-RS código específico empregando JAAS (Java Authentication and Authorization Service) e um filtro de servlet . O filtro pode ser usado para impor a autenticação HTTP e, por auth bem sucedida, a configuração do JAAS Assunto com os princípios apropriados. Seus recursos JAX-RS pode verificar os diretores apropriadas sobre o assunto. Desde que você controla toda a pilha, você deve ser capaz de confiar em um usuário autenticado em seus recursos (mas fazer teste este!), E você pode impor a autorização com base na operação atual no código fonte.
Eu resolvi esse problema fazendo com que os clientes adicionar o cabeçalho de autorização e testá-lo na methode RESTO assim:
@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
Desta forma, não é a autenticação sem iniciar uma sessão.
Para segurança Jersey você deve dar uma olhada no apoio jersey OAuth. OAuth se encaixa perfeitamente quando você expor API para o seu sistema para usuários externos. Por exemplo, como o api linkedin
Você pode usuário @path para agrupar os serviços sob espaço único nome. exemplo.
@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();
}
}
}
Você pode validar a sua sessão nesta classe de filtro.