How do I solve the CORS problem in JavaEE and Angular

1

I have a CORS problem that I have no idea where it comes from, I am creating a REST service in JavaEE (Glassfish) and I have Front an Angular app consuming the aforementioned service, I am testing the token authentication with the JJWT library, so far I have created Token and other token operations and I have not had any problem , the angular app makes requests to the service and it responds, BUT , I'm not sending the token in the header and that's because every time I create an HttpHeaders in angular and what I added to the Http request the server returns a CORS error.

My Angular code is as follows:

getProductoIndividual():Observable<any>
{
     console.log("getProductoIndividual", 'Authorization' + ':'  + 'Bearer ' + localStorage["clave"]);

     const header = new HttpHeaders({
                   'Authorization' : 'Bearer ' + localStorage["clave"]
                   });

     return this.http.get("http://localhost:8080/PruebaCuatro/api/persona/3", { headers : header });
 }

If I delete the second parameter of the GET operation, then the request works perfectly, but if I leave it as they appreciate it there, the server throws me CORS error.

My JavaEE code is as follows:

@GET
@Path("{id}")
@Produces({MediaType.APPLICATION_JSON})
public Response findModificado(@PathParam("id") Long id, @Context             HttpHeaders headers) throws UnsupportedEncodingException
{

    String jwt = "TTOOKKEENN";
    JsonObject json;
    List<String> authorizationHeader = headers.getRequestHeader("Authorization");

    String authString = null;

    if(authorizationHeader == null  || authorizationHeader.isEmpty())
    {
        authString = "NULO";            
    }
    else
    {
        authString = authorizationHeader.get(0);        
    }

    String email = null;
    String sujeto = null;
    Date iat = null;
    Date exp = null;

    try
    {

         Jws<Claims> claims = Jwts.parser().setSigningKey("mi_clave").parseClaimsJws(jwt);

         sujeto = claims.getBody().getSubject();             
         email = claims.getBody().get("email", String.class);
         iat = claims.getBody().getIssuedAt();
         exp = claims.getBody().getExpiration();

         json = Json.createObjectBuilder().add("email", email)
                                            .add("sujeto", sujeto)
                                            .add("iat", iat.toString())
                                            .add("exp", exp.toString())
                                            .add("Authorization", authString)
                                            .build();

    } catch(SignatureException e)
    {
        json = Json.createObjectBuilder().add("LLAVE_ERRONEA", "La firma no correponde").build(); 
    }  
    catch(ExpiredJwtException e)
    {
        json = Json.createObjectBuilder().add("LLAVE_ERRONEA", "La llave expiro").build();            
    }

 return Response.status(Response.Status.CREATED).entity(json)
                    .header("Access-Control-Allow-Origin", "*").build();

 }

CONSIDERATIONS : Evidently the TTOOKKEENN chain is not really in the code, in my code if there is a real token, I clarify it but that is not really part of the problem. I am using the GlassFish server and I am not using any JavaEE framework, ABSOLUTELY NO FRAMEWORK, it is simply JavaEE code and it was generated mostly by Netbeans and I have modified it, it has a JPA connection but that is another story. I'm not using maven either.

Also try to use an interceptor in angular but I got the same result (CORS error).

The Warning that I get from the server is the following:

  

Cross-origin request blocked: The same origin policy does not allow the reading of remote resources in link . (Reason: CORS header 'Access-Control-Allow-Origin' not present)

Where should Access-Control-Allow-Origin go? the question seems silly, but it is that I do not know what else to do and how the wise say that there are no silly questions but fools that do not ask because I also leave that there.

I hope you can help me. In my opinion the problem is in the angular header, I read them.

By the way, when I run the same URL API with the same Authorization parameter set to Bearer TTOOKKEENN in POSTMAN or other API testing software REST then if it works as it should be, that's why my theory that the problem is in Angular.

Obviously I have to solve the problem in order to implement Token authentication in the system.

The libraries I use in JavaEE are:

  • jersey-bundle-1.19.1.jar
  • jackson-all-1.9.0.jar
  • jjwt-0.6.0.jar
asked by Ricardo Gabriel 29.05.2018 в 23:58
source

2 answers

3

It is necessary that you enable the CORS option in your REST API.

@Provider
public class CorsFilter implements ContainerResponseFilter {
    @Override
    public void filter(ContainerRequestContext requestContext, 
      ContainerResponseContext responseContext) throws IOException {
          responseContext.getHeaders().add(
            "Access-Control-Allow-Origin", "*");
          responseContext.getHeaders().add(
            "Access-Control-Allow-Credentials", "true");
          responseContext.getHeaders().add(
           "Access-Control-Allow-Headers",
           "origin, content-type, accept, authorization");
          responseContext.getHeaders().add(
            "Access-Control-Allow-Methods", 
            "GET, POST, PUT, DELETE, OPTIONS, HEAD");
    }
} 

I leave a link that can be useful CORS-JAX-RS

    
answered by 21.06.2018 в 20:52
1

You have two options, implement CORS on your server or use a reverse proxy. The first option is explained by @cjara, so I will not go deep there.

The second option, which is the one I like best (is the one I use both in development and in production) is based on the static content server acting as a gateway for REST calls. I present you on stage so you can understand it easily:

  • You have a web server with your HTML, Javascript and other files of your Angular application. It can be Apache, Nginx or similar. This server uses the standard ports (80 for http and 443 for https).

  • You have a J2EE server (say a Glassfish) listening on port 8080 to serve REST resources.

  • You configure the web server so that any request that starts with / api is forwarded to port 8080 of the same machine.

In the development environment

Simply create a file named package.json with the following content in the root of your Angular project (where the file proxy.conf.json is found)

{   
  "/api": {
    "target": "http://localhost:8080/PruebaCuatro",
    "secure": false
  }
}

And when you raise the server, instead of

ng serve

pon

ng serve --proxy-config proxy.conf.json --host=0.0.0.0

In production (example)

Using Nginx would be something like:

    upstream backend {
        server localhost:8080;
    }

    location /api/ {
        proxy_pass http://backend/PruebaCuatro/api/;
        proxy_http_version 1.1;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP          $remote_addr;
        proxy_set_header X-Forwarded-For    $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto  $scheme;
        proxy_set_header Origin "";
    }

Therefore, if your Angular application is downloaded when a user enters https://midominio.com/index.html , any call to the REST API should be made using a URL such as https://midominio.com/api/mi-recurso , which the proxy server will redirect internally to http://localhost:8080/PruebaCuatro/api/mi-recurso .

With this you get two advantages:

  • For the client everything is transparent and there is only one communication channel, simplifying the configuration of firewalls and routers.
  • Since everything has the same origin (only web domain with a single port), the browser does not require the use of the CORS protocol.
answered by 22.06.2018 в 15:51