Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

CORS Play Framework

I'm developing an Angular 2 application on top of a Play Framework 2.5 (Java) back-end. If I access my endpoints through browser URL, they work fine. However, calling it from the Angular 2 application shows the error:

XMLHttpRequest cannot load localhost:9000/app/myendpoint. No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'localhost:3000' is therefore not allowed access. The response had HTTP status code 500.

I have tryed to follow the documentation and create the filter:

In application.conf:

play.filters {
  cors {
    pathPrefixes = ["/app"]
    allowedOrigins = null
    allowedHttpMethods = null
  }

Filter:

import play.mvc.*;
import play.api.http.DefaultHttpFilters; <- error with this import
import play.filters.cors.CORSFilter;

public class Filters extends DefaultHttpFilters {
    @Inject public Filters(CORSFilter corsFilter) {
        super(corsFilter);
    }
}

In build.sbt:

libraryDependencies ++= Seq(
  ...,
  filters
)

Does anyone knows the true solution? Thank you :)

Working code:

Filters.java (on project's root)

import com.google.inject.Inject;
import com.google.inject.Singleton;    
import play.http.HttpFilters;
import play.mvc.EssentialAction;
import play.mvc.EssentialFilter;
import play.filters.cors.CORSFilter;

@Singleton
public class Filters extends EssentialFilter implements HttpFilters {

    @Inject
    private CORSFilter corsFilter;

    @Override
    public EssentialAction apply(EssentialAction next) {
        return corsFilter.asJava().apply(next);
    }

    @Override
    public EssentialFilter[] filters() {
        EssentialFilter[] result = new EssentialFilter[1];
        result[0] = this;    
        return result;
    }
}

In application.conf:

  #filters += Filters <- yes, it is commented since my Filters is in project's root
libraryDependencies += filters

play.filters {
 cors{
    # allow all paths
    pathPrefixes = ["/"]
    # allow all origins
    allowedOrigins = null
    allowedHttpMethods = ["GET", "POST", "PUT", "DELETE"]
    # allow all headers
    allowedHttpHeaders = null
} ...

In build.sbt:

libraryDependencies ++= Seq(
  ...,
  filters
)

Thank you all! :)

like image 252
Patriicya Avatar asked Aug 16 '16 20:08

Patriicya


1 Answers

The best practice is to serve both static context and webservice from single origin. For example, for single domain, every URI except /api/* is meant to serve static content and /api/* is a reverse proxy to Java app. You may be specifically interested in Grunt. nginx and Apache could also work.

For example in nginx you specify following configuration:

location /api {
    rewrite /api/(.*) /$1  break;
    proxy_pass http://127.0.0.1:9000;
    proxy_redirect off;
    proxy_set_header Host $host;
    proxy_set_header X-Forwarded-For $remote_addr;
}

location / {
    root   /var/www/location;
    index  index.html index.htm;
}

And then you run your Java app listening on localhost, on port 9000. You are able to copy all your static content to location specified after "root" and get it served by nginx. You send all REST request to /api/method/name

Advantage of this solution is solid security and ability to configure SSL easily.

like image 151
mkorman Avatar answered Sep 21 '22 22:09

mkorman