How to Configure CORS correctly in Spring Boot?

Asked

Viewed 5,591 times

4

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 Angular, the request of the java API is the port 8080 and Angular is port 4200, as each one makes different requests I decided to use the CORS, but I had no positive result 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 Recapitulating!

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

but there is a mechanism known as CORS that allows the service providers to configure the access control cross Domain, ie with the protocol, with domain or ports different from the origin, the back-end I’m using already has the implementation of cross Domain.

To give permission to my packaged project, I executed 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 didn’t work. He denied me permission as you can see.

So I made another attempt, look at my CORS settings 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 estancio for this other java class that does everything:

@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 class Algamoneyapiproperty is with port 8000 and my Frond-End Angular is configuring for port 8080, which is why I executed command requesting permission through the MSDOS, then no longer depend on requests from MSDOS I decided to change the request port of my Java API to 8080 and my Frond-End to 8080.

Only by default, my API will run on the 8080 localhost running on the 8080 request and my Angular Frond-End will run on the 4200 localhost requesting the 8080 request from the java API as you can see below

API Java

Class Algamoneyapiproperty

Private string originPermitida = "http://localhost:8080";

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 at the beginning of this post.

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

Someone might claim that maybe door 8080 might 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 just took!

inserir a descrição da imagem aqui

So the problem is not at the door, the problem may be in the CORS configuration.

Anyone may ask! Why don’t you keep using the API to accept any source?

I don’t 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.

3 answers

3


As I answered your other question, API at port 8000 and Angular at port 4200, how to solve?, for development the ideal is you configure a Proxy on the server @angular/cli.

As I left the link of my post where I explain what is CORS and how to configure the Proxy, https://medium.com/@gigioSouza/solving-the-Cors-problem-with-angular-2-e-o-angular-cli-7f7cb7aab3c2, you have to configure it as needed by your project.

If you remove the configuration of CORS and use the Proxy configuration that is in the link post, you will already be able to follow the development.

The ideal is you prepare your CORS for the production environment. How to do this? A: Google, search, test... after all only you know the needs of your project.


As you passed your Ref to take a look: https://github.com/wladyband/erro1/tree/master/wladimi-ui

Right away I checked that your configuration file is called proxy.config.js and in your package.json your start script is: ng serve --proxy-config proxy.conf.js.

Change your start script to ng serve --proxy-config proxy.config.js

And you should stop making requests for http://localhost:8080, to access this service for example http://localhost:8080/lancamentos request for this endpoint /api/lancamentos.

Now come on, from what I saw you’re using Angular 5, so change the old HttpModule for the new HttpClientModule.

Create an Interceptor to complete the request url by placing the base url of the request, which in dev is /api. So when you go into production and don’t use proxy, you just need to change the base url within that Interceptor to and you’re done, all your endpoints are pointing to production.

Ai is just setting the base url according to the build profile. Exploring the files environment.

Documentation of HttpClient https://angular.io/guide/http

  • thanks for your attempt to help me, but your answer doesn’t help much, because in the same way that the Java API works in a development environment is to work also in a production environment without any gambit, that is, your approach it is functional, but it is not good programming practice. Please do not be offended by what I have said, if you happen to know someone from your contacts who can see my post and can help me, I know very grateful.

  • 1

    Dude, using proxy is not a gambiarra. It is a resource used for development and also used for production. If you want a better help start by writing your question better and be more objective.

  • I’m sorry but my question is well elaborated, if you have questions would look more elegant to ask questions about what you didn’t understand from my post, I don’t know if in fact proxy approach can be made in production environment.

  • If it can be done I invite you to test on any model found on github, again it was not my intention to be awkward with you, but of the projects I found using CORS most do not use good development practices and why I made this post. And of the projects I found on Github I couldn’t find any similar approach to what you did to be applied in a production environment. That’s why I’ve been so sure to tell you who’s not a good practice.

  • But if you still do not accept and were offended even if it was not my intention I invite you to withdraw your answer because for me it will not serve.

  • 2

    If your application architecture is done using Docker containers, communication between these containers is done via proxy. If you have a scalable micro-service architecture where you have no idea how many services are standing to serve you or which address of them, you hit the loadbalancers which in addition to managing the requests for the services intelligently, it acts as a proxy.

  • Again I’m sorry the way I wrote, I try at most to be very receptive in my comments because here are a lot of nervous people in the stackoverflow forum and who is in need of help is me. I’m gonna do it the way it’s on your blog.

  • I made the changes, but it didn’t work gave the same error message, could you take a look at the Frond-End code to see if I did something wrong? please https://github.com/wladyband/erro1/tree/master/wladimi-ui

Show 3 more comments

0

I manage to solve my problem with the solution below, but it also works with the @Giovane solution and so much that I preferred to validate the @Giovane answer because it is valid.

A first thing would be the command. The property "algamoney.origin-allowed" needs to be passed with "--" or "-D". So:

--algamoney.origin-permitted=ORIGIN

... or

-Dalgamoney.origin-permitted=ORIGIN

In the API, only port 8080 always to not have configuration problems or any related confusion. And in the Angular part it’s always good to review the code to make sure everything is using port 8080.

After I did that it worked perfectly my project.

-1

Hello, I have the same problem as you. Besides all that, I could only get the result, because I commented the methods Preauthorize, because even passing Basic, he was checking the Preauthorize. You managed to resolve all domains without authorization?

Browser other questions tagged

You are not signed in. Login or sign up in order to post.