· Vladyslav Baidak · Backend Development · 3 min de leitura
Desenvolvimento Backend: Ativar o CORS (JAX-RS)

Uma das dificuldades comuns que as equipas de desenvolvimento backend podem enfrentar ao criar serviços RESTful é o Cross-origin resource sharing (CORS). Uma vez que o JAX-RS não permite CORS por predefinição, vamos implementar uma solução que o ativa.
Ao alojar os recursos back-end e front-end na mesma máquina (por exemplo, localhost) não haverá problema, mas quando se trata de uma implementação cross-domain (por exemplo, quando os recursos front-end estão alojados numa máquina diferente) é necessária uma solução adequada.
Implementar a funcionalidade CORS
Para ativar o CORS como uma funcionalidade no JAX-RS, precisamos de adicionar a seguinte dependência RestEasy JAX-RS:
<dependency>
<groupId>org.jboss.resteasy</groupId>
<artifactId>resteasy-jaxrs</artifactId>
<version>3.1.0.Final</version>
</dependency>
Esta fornece um CorsFilter conveniente, que podemos adicionar como uma funcionalidade:
import javax.ws.rs.core.FeatureContext;
import org.jboss.resteasy.plugins.interceptors.CorsFilter;
@Provider
public class CorsProvider implements Feature {
@Override
public boolean configure(FeatureContext context) {
CorsFilter corsFilter = new CorsFilter();
corsFilter.getAllowedOrigins().add("*");
context.register(corsFilter);
return true;
}
});
Como pode reparar, estamos a adicionar * às origens permitidas. Isto irá adicionar todos os cabeçalhos CORS apropriados a qualquer pedido de saída.
Implementar o filtro CORS
Se não quiser adicionar dependências adicionais para um caso tão simples, pode implementar o filtro CORS da seguinte forma:
@PreMatching
public class CorsFilter implements ContainerRequestFilter, ContainerResponseFilter {
private static final String HEADER_ORIGIN = "Origin";
private static final String HEADER_ACCESS_CONTROL_ALLOW_ORIGIN = "Access-Control-Allow-Origin";
private static final String HEADER_ACCESS_CONTROL_ALLOW_CREDENTIALS = "Access-Control-Allow-Credentials";
private static final String HEADER_ACCESS_CONTROL_REQUEST_METHOD = "Access-Control-Request-Method";
private static final String HEADER_ACCESS_CONTROL_ALLOW_METHODS = "Access-Control-Allow-Methods";
private static final String HEADER_ACCESS_CONTROL_REQUEST_HEADERS = "Access-Control-Request-Headers";
private static final String HEADER_ACCESS_CONTROL_ALLOW_HEADERS = "Access-Control-Allow-Headers";
private Set<String> allowedOrigins = new HashSet<>();
public Set<String> getAllowedOrigins() {
return allowedOrigins;
}
@Override
public void filter(ContainerRequestContext requestContext) throws IOException {
String origin = requestContext.getHeaderString(HEADER_ORIGIN);
if (origin == null) {
return;
}
if (requestContext.getMethod().equalsIgnoreCase("OPTIONS")) {
preFlight(origin, requestContext);
} else {
checkOrigin(requestContext, origin);
}
}
@Override
public void filter(ContainerRequestContext requestContext, ContainerResponseContext responseContext) throws IOException {
String origin = requestContext.getHeaderString(HEADER_ORIGIN);
if (origin == null
|| requestContext.getMethod().equalsIgnoreCase("OPTIONS")
|| requestContext.getProperty("cors.failure") != null) {
return;
}
responseContext.getHeaders().putSingle(HEADER_ACCESS_CONTROL_ALLOW_ORIGIN, origin);
responseContext.getHeaders().putSingle(HEADER_ACCESS_CONTROL_ALLOW_CREDENTIALS, "true");
}
private void preFlight(String origin, ContainerRequestContext requestContext) throws IOException {
checkOrigin(requestContext, origin);
Response.ResponseBuilder builder = Response.ok();
builder.header(HEADER_ACCESS_CONTROL_ALLOW_ORIGIN, origin);
builder.header(HEADER_ACCESS_CONTROL_ALLOW_CREDENTIALS, "true");
String requestMethods = requestContext.getHeaderString(HEADER_ACCESS_CONTROL_REQUEST_METHOD);
if (requestMethods != null) {
builder.header(HEADER_ACCESS_CONTROL_ALLOW_METHODS, requestMethods);
}
String allowHeaders = requestContext.getHeaderString(HEADER_ACCESS_CONTROL_REQUEST_HEADERS);
if (allowHeaders != null) {
builder.header(HEADER_ACCESS_CONTROL_ALLOW_HEADERS, allowHeaders);
}
requestContext.abortWith(builder.build());
}
private void checkOrigin(ContainerRequestContext requestContext, String origin) {
if (!allowedOrigins.contains("*")
&& !allowedOrigins.contains(origin)) {
requestContext.setProperty("cors.failure", true);
throw new ForbiddenException("Origin not allowed: " + origin);
}
}
}
Esta é quase a mesma implementação que org.jboss.resteasy.plugins.interceptors.CorsFilter, mas sem a necessidade de importar dependências adicionais.
Permitir o método HTTP OPTIONS
A última coisa a ter em conta é permitir que o método HTTP OPTIONS prossiga. O método HTTP OPTIONS é normalmente utilizado pelos browsers antes de enviar o pedido CORS real.
Se tiver restrições de segurança configuradas no ficheiro descritor web.xml, precisa de adicionar o método HTTP OPTIONS utilizando a seguinte declaração de lista de permissões:
<security-constraint>
<web-resource-collection>
<url-pattern>/*</url-pattern>
<http-method>OPTIONS</http-method>
</web-resource-collection>
</security-constraint>
Tenha um bom dia e leia mais artigos sobre desenvolvimento backend aqui!



