How to properly configure CORS in Spring Boot?

2

First I'll tell you what happens!

I developed a simple Spring Boot project to show on screen a GRID having as Frond-End the Angle, the java API request is port 8080 and the Angular port is 4200, as each one makes different requests I have decided to use the CORS , but I did not get positive results and gave this error message;

Failed to load resource: the server responded with a status of 401 ()
localhost/:1 Failed to load http://localhost:8080/lancamentos?resumo: Response to preflight request doesn't pass access control check: The 'Access-Control-Allow-Origin' header has a value 'http://localhost:8000' that is not equal to the supplied origin. Origin 'http://localhost:4200' is therefore not allowed access.
core.js:1350 ERROR Error: Uncaught (in promise): Response with status: 0  for URL: null
    at resolvePromise (zone.js:824)
    at resolvePromise (zone.js:795)
    at eval (zone.js:873)
    at ZoneDelegate.invokeTask (zone.js:425)
    at Object.onInvokeTask (core.js:4621)
    at ZoneDelegate.invokeTask (zone.js:424)
    at Zone.runTask (zone.js:192)
    at drainMicroTaskQueue (zone.js:602)
    at ZoneTask.invokeTask [as invoke] (zone.js:503)
    at invokeTask (zone.js:1540)

Then recap!

My system is placing a request on port 8000 from the localhost 4200 of the Frond-End. When a request is made by a protocol a domain on ports other than the origin, which is my case, the application is Angular port 4200 the Java API is on port 8080 in this case for security browsers restrict access, does not allow the request is made, the browser itself already has this layer of security that restricts access.

But there is a mechanism known as CORS that allows the servers to configure cross domain access control, that is, with the protocol, with different domain or ports of the source, the backend I'm using already has the implementation of cross domain.

To give permission to my project that is bundled, I ran this command:

java -jar algamoney-api-1.0.0-SNAPSHOT.jar  --
 spring.datasource.username=root 
--spring.datasource.password=1234 
 algamoney.origin-permitida=http://localhost:4200

But it did not work. He denied me permission as you can see.

Then I made another attempt, look at my settings from my CORS in my Spring Boot project:

package com.example.algamoney.api.config.property;

import org.springframework.boot.context.properties.ConfigurationProperties;

@ConfigurationProperties("algamoney")
public class AlgamoneyApiProperty {

    private String originPermitida = "http://localhost:8000";

    private final Seguranca seguranca = new Seguranca();

    public Seguranca getSeguranca() {
        return seguranca;
    }

    public String getOriginPermitida() {
        return originPermitida;
    }

    public void setOriginPermitida(String originPermitida) {
        this.originPermitida = originPermitida;
    }

    public static class Seguranca {

        private boolean enableHttps;

        public boolean isEnableHttps() {
            return enableHttps;
        }

        public void setEnableHttps(boolean enableHttps) {
            this.enableHttps = enableHttps;
        }

    }

}

And stick to this other java class that does it all:

@Component
@Order(Ordered.HIGHEST_PRECEDENCE)
public class CorsFilter implements Filter {

    @Autowired
    private AlgamoneyApiProperty algamoneyApiProperty;

    @Override
    public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain)
            throws IOException, ServletException {

        HttpServletRequest request = (HttpServletRequest) req;
        HttpServletResponse response = (HttpServletResponse) resp;

        response.setHeader("Access-Control-Allow-Origin", algamoneyApiProperty.getOriginPermitida());
        response.setHeader("Access-Control-Allow-Credentials", "true");

        if ("OPTIONS".equals(request.getMethod()) && algamoneyApiProperty.getOriginPermitida().equals(request.getHeader("Origin"))) {
            response.setHeader("Access-Control-Allow-Methods", "POST, GET, DELETE, PUT, OPTIONS");
            response.setHeader("Access-Control-Allow-Headers", "Authorization, Content-Type, Accept");
            response.setHeader("Access-Control-Max-Age", "3600");

            response.setStatus(HttpServletResponse.SC_OK);
        } else {
            chain.doFilter(req, resp);
        }

    }

    @Override
    public void destroy() {
    }

    @Override
    public void init(FilterConfig arg0) throws ServletException {
    }

}

You may have noticed that the AlgamoneyApiProperty class has port 8000 and my Frond-End Angle is setting up for port 8080, which is why I ran command requesting permission through MSDOS , so no longer depend on MSDOS requests I decided to change the request port of my java API to 8080 and my Frond-End to 8080.

Just recapping, my API will run on localhost 8080 running on request 8080 and my Frond-End Angle will run on localhost 4200 requesting from the java API the 8080 request as you can see below

Java API

Class AlgamoneyApiProperty

Private String originPermitida=" link ";

Frond-End Angular

import { Http, Headers } from '@angular/http';
import { Injectable } from '@angular/core';

import 'rxjs/add/operator/toPromise';

@Injectable()
export class LancamentoService {

  lancamentosUrl = 'http://localhost:8080/lancamentos';

  constructor(private http: Http) { }

  pesquisar(): Promise<any> {
    const headers = new Headers();
    headers.append('Authorization', 'Basic YWRtaW5AYWxnYW1vbmV5LmNvbTphZG1pbg==');

    return this.http.get('${this.lancamentosUrl}?resumo', { headers })
      .toPromise()
      .then(response => response.json().content)
  }

}

The result was the same, and generated the same error as was commented on at the beginning of this post.

My next attempt was to try with other ports, I tried with 9000 , 7654 and 8000 .

Can anyone claim that maybe port 8080 may be in trouble! So I set up my CORS in my Java API to accept any source, as you can see below;

@Component
@Order(Ordered.HIGHEST_PRECEDENCE)
public class CorsFilter implements Filter {

//  @Autowired
//  private AlgamoneyApiProperty algamoneyApiProperty;

    @Override
    public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain)
            throws IOException, ServletException {

        HttpServletRequest request = (HttpServletRequest) req;
        HttpServletResponse response = (HttpServletResponse) resp;

        response.setHeader("Access-Control-Allow-Origin", request.getHeader("Origin"));

        response.setHeader("Access-Control-Allow-Credentials", "true");

        response.setHeader("Access-Control-Allow-Origin", request.getHeader("Origin"));


        if ("OPTIONS".equals(request.getMethod())) {
        response.setHeader("Access-Control-Allow-Methods", "POST, GET, DELETE, PUT, OPTIONS");
            response.setHeader("Access-Control-Allow-Headers", "Authorization, Content-Type, Accept");
            response.setHeader("Access-Control-Max-Age", "3600");
            response.setStatus(HttpServletResponse.SC_OK);
        } else {
            chain.doFilter(req, resp);
        }

    }

    @Override
    public void destroy() {
    }

    @Override
    public void init(FilterConfig arg0) throws ServletException {
    }

}

And it just caught!

So the problem is not in the port, the problem might be in the CORS configuration.

Someone may ask! Why do not you stay using the API to accept any source?

I do not want to do this because I can lower the security level.

I really need to know where my CORS configuration error is to accept a specific source.

    
asked by anonymous 14.12.2017 / 10:05