1
votes

Angular application, (executed in webpack development server),

It makes REST calls to a Spring application deployed in JETTY (with spring security / BASIC authentication enabled).

When calling http://localhost:8085/myapi/api/login through angular, response is: 401 Unauthorized (Request method is OPTIONS, although is specified as POST)

Have tried most solutions posted related to this (enabling/sending CORS headers from Angular, Spring Security and web.xml(jetty) side.

What is needed?

Error in Chrome: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource

Angular:

let headers =  new Headers();
headers.append("Authorization", "Basic " + btoa("test_user:test_user"));
headers.append("X-Requested-With", "XMLHttpRequest");
headers.append("withCredentials", "true");
//headers.append("Access-Control-Allow-Methods", "GET, HEAD, OPTIONS, POST, PUT, DELETE");
//headers.append("Access-Control-Allow-Origen", "*");

let options = new RequestOptions({headers: headers});
this.http.post("http://localhost:8085/myapi/api/services/login", 
               JSON.stringify({}), options);

Spring security

<sec:http auto-config="true" use-expressions="true" 
entry-point-ref="authenticationEntryPoint">
    <sec:form-login />
    <sec:http-basic />
    <sec:logout />
    <sec:intercept-url pattern="/**" access="permitAll" />
    <!-- corsHandler: filter (OncePerRequestFilter) that adds Access-Control-Allow-Origin header -->
    <sec:custom-filter ref="corsHandler" position="PRE_AUTH_FILTER"/>
    <sec:cors /> 
</sec:http>

web.xml

<filter>
    <filter-name>cross-origin</filter-name>
    <filter-class>org.eclipse.jetty.servlets.CrossOriginFilter</filter-class>
    <init-param>
        <param-name>allowedOrigins</param-name>
        <param-value>*</param-value>
    </init-param>
   <init-param>
       <param-name>allowedMethods</param-name>
       <param-value>GET,POST,OPTIONS,DELETE,PUT,HEAD</param-value>
   </init-param>
  <init-param>
       <param-name>allowedHeaders</param-name>
       <param-value>Origin,Content-Type,Accept,authorization,X-Requested-With</param-value>
   </init-param>
</filter>
<filter-mapping>
    <filter-name>cross-origin</filter-name>
    <url-pattern>*</url-pattern>
</filter-mapping>

webpack server:

  devServer: {
    historyApiFallback: true,
    stats: 'minimal',
        headers: {
            'Access-Control-Allow-Origin': '*'
        } 
  }

There are filters (servlet filters) and Spring interceptors setup to add the Access-Control-Allow-Origen header, but none is executed.

1

1 Answers

0
votes

Final solution was to create a proxy in the webpack development server

The proxy avoid CORS problems (proxy: {...}). The URL to the rest api has been updated to the same machine were the angular application is running: this.http.post("http://localhost:8081/myapi/api/services/login", ...):

webpack proxy:

devServer: {
    historyApiFallback: true,
    stats: 'minimal',
    headers: {
        'Access-Control-Allow-Origin': '*'
    },
    proxy: {
       '/myapi/api/**': {
            target: 'http://localhost:8085',
            secure: false              
        }
    }
}

From Angular, an HTTP call with authentication header is needed against a rest mapped method.

@PostMapping("/login")
public ResponseEntity login() {
    return new ResponseEntity<>(HttpStatus.OK);
}

Calling this rest method (through the proxy) seems to work fine once CORS problems don´t exist.

Don´t understand why CORS configuration was not working in this case: Most of the code related to CORS given above in the question is not necessary with this solution