AngularJS / Alfresco / CORS filter issue: No '

2019-04-16 00:54发布

I have some problem with Alfresco (5.0.d), my AngularJS (1.4.3) client and the CORS settings (typical cross-domain / No'Access-Control-Allow-Origin' header is present on the requested resource problem).

I am calling the Alfresco REST API from an AngularJS application running on localhost:3000, to an Alfresco instance running on localhost:8080 (Tomcat, no reverse-proxy in front).

This XHR call works fine:

http://localhost:8080/alfresco/service/slingshot/live-search-docs?t=Project&u=admin&pw=admin&alf_ticket=TICKET_9d9780c83b8b9525c7acb9d3d8da66c5c902fb76

This one

http://localhost:8080/alfresco/service/api/login?u=admin&pw=admin

only works fine in Internet Explorer 11, but in Chrome and Firefox, I am getting status code 200 returned with 0 bytes and the error in the JS console:

XMLHttpRequest cannot load http://localhost:8080/alfresco/service/api/login?u=admin&pw=admin. No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost:3000' is therefore not allowed access.

In the Alfresco web.xml, I have enabled the CORS filter as follows:

   <!-- CORS Filter Mappings Begin -->
   <filter-mapping>
      <filter-name>CORS</filter-name>
      <url-pattern>/api/*</url-pattern>
      <url-pattern>/service/*</url-pattern>
      <url-pattern>/s/*</url-pattern>
      <url-pattern>/cmisbrowser/*</url-pattern>
   </filter-mapping>
   <!-- CORS Filter Mappings End -->

   <!-- CORS Filter Begin -->
   <filter>
      <filter-name>CORS</filter-name>
      <filter-class>com.thetransactioncompany.cors.CORSFilter</filter-class>
      <init-param>
         <param-name>cors.allowGenericHttpRequests</param-name>
         <param-value>true</param-value>
      </init-param>
      <init-param>
         <param-name>cors.allowOrigin</param-name>
         <!-- <param-value>http://localhost:3000 http://localhost:8081 http://localhost:8080 https://localhost</param-value> -->
         <param-value>*</param-value>
      </init-param>
      <init-param>
         <param-name>cors.allowSubdomains</param-name>
         <param-value>true</param-value>
      </init-param>
      <init-param>
         <param-name>cors.supportedMethods</param-name>
         <param-value>GET, HEAD, POST, PUT, DELETE, OPTIONS</param-value>
      </init-param>
      <init-param>
         <param-name>cors.supportedHeaders</param-name>
         <param-value>origin, authorization, x-file-size, x-file-name, content-type, accept, x-file-type</param-value>
      </init-param>
      <init-param>
         <param-name>cors.supportsCredentials</param-name>
         <param-value>true</param-value>
      </init-param>
      <init-param>
         <param-name>cors.maxAge</param-name>
         <param-value>3600</param-value>
      </init-param>
   </filter>-->
   <!-- CORS Filter End -->

The calls from within Angular:

The one that works fine:

$http.get('http://localhost:8080/alfresco/service/slingshot/live-search-docs?t=Project&alf_ticket=TICKET_9d9780c83b8b9525c7acb9d3d8da66c5c902fb76').then(function(response) {
    console.log('DATA LOADED: ' + response.items);
    $scope.contents = response.items;
});

Response headers:

HTTP/1.1 200 OK
Server: Apache-Coyote/1.1
Cache-Control: no-cache
Expires: Thu, 01 Jan 1970 00:00:00 GMT
Pragma: no-cache
Content-Type: application/json;charset=UTF-8
Content-Length: 85
Date: Thu, 13 Aug 2015 06:37:24 GMT

The one that fails:

$http.get('http://localhost:8080/alfresco/service/api/login?u=' + $scope.user.email + '&pw=' + $scope.user.password).
      then(function(response) {
        console.log('ALF_TICKET: ' + response.data.ticket);
        $scope.alfTicket = response.data.ticket;
        $state.go('admin-panel.default.introduction');
      }, function(response) {
        console.log('LOGIN FAILED');
      });

Response headers:

HTTP/1.1 200 OK
Server: Apache-Coyote/1.1
Access-Control-Allow-Credentials: true
Access-Control-Allow-Origin: http://localhost:3000
Vary: Origin
Cache-Control: no-cache
Expires: Thu, 01 Jan 1970 00:00:00 GMT
Pragma: no-cache
Content-Type: application/json;charset=UTF-8
Transfer-Encoding: chunked
Date: Thu, 13 Aug 2015 06:38:36 GMT

I have the $httpProvider configured in my AngularJS app, just to be sure:

.config(['$httpProvider', function($httpProvider) {
        $httpProvider.defaults.useXDomain = true;
        delete $httpProvider.defaults.headers.common['X-Requested-With'];
    }

A CURL request simulated from a different host works fine, interestingly though, I do not get a Access-Control-Allow-Origin header back in the response despite the CORS filter enabled in Alfresco:

curl -H "Origin: http://www.microsoft.com" --verbose "http://alfresco.mycompany.ch:8080/alfresco/service/api/login?u=admin&pw=12@echo"

* Hostname was NOT found in DNS cache
*   Trying 10.10.0.183...
* Connected to alfresco.mycompany.ch (10.10.0.183) port 8080 (#0)
> GET /alfresco/service/api/login?u=admin&pw=12@echo HTTP/1.1
> User-Agent: curl/7.37.1
> Host: alfresco.mycompany.ch:8080
> Accept: */*
> Origin: http://www.microsoft.com
> 
< HTTP/1.1 200 OK
* Server Apache-Coyote/1.1 is not blacklisted
< Server: Apache-Coyote/1.1
< Cache-Control: no-cache
< Expires: Thu, 01 Jan 1970 00:00:00 GMT
< Pragma: no-cache
< Content-Type: application/json;charset=UTF-8
< Content-Length: 85
< Date: Thu, 13 Aug 2015 08:11:15 GMT
< 
{
   "data":
   {
"ticket":"TICKET_7d07634afbb25a7e823c0348d907e0790eeff97e"
   }
}
* Connection #0 to host alfresco.mycompany.ch left intact

therefore I think it's client/AngularJS related.

=== Update 1: ===

I tried to add an interceptor to the $httpProvider as below, but it doesn't help. I don't see the headers I am setting there in any of the responses, although the interceptor gets called.

    $httpProvider.interceptors.push(function() {
      return {
       'request': function(request) {
           return request;
        },
        'response': function(response) {
           console.log('Interceptor called.');
           response.config.headers['MyTestHeader'] = '12345';
           response.config.headers['Access-Control-Allow-Origin'] = '*';
           return response;
        }
      };
    });

=== Update 2: ===

Some more findings, but now a bit weird on the Alfresco side. I am doing two almost similar API calls, to the following two urls:

You can see, they only differ at the end. The one with /whatever returns a Access-Control-Allow-Origin response header, the one with /login does not. It must be related to the Alfresco config / webscript, but I have not yet found the origin of it.

curl -H "Origin: http://www.microsoft.com" --verbose "http://localhost:8080/alfresco/service/api/login"

*   Trying ::1...
* Connected to localhost (::1) port 8080 (#0)
> GET /alfresco/service/api/login HTTP/1.1
> Host: localhost:8080
> User-Agent: curl/7.43.0
> Accept: */*
> Origin: http://www.microsoft.com
>
< HTTP/1.1 400 Bad Request
< Server: Apache-Coyote/1.1
< Cache-Control: no-cache
< Expires: Thu, 01 Jan 1970 00:00:00 GMT
< Pragma: no-cache
< Content-Type: application/json;charset=UTF-8
< Transfer-Encoding: chunked
< Date: Thu, 13 Aug 2015 12:49:46 GMT
< Connection: close
<

But this one:

curl -H "Origin: http://www.microsoft.com" --verbose "http://localhost:8080/alfresco/service/api/whatever"

*   Trying ::1...
* Connected to localhost (::1) port 8080 (#0)
> GET /alfresco/service/api/whatever HTTP/1.1
> Host: localhost:8080
> User-Agent: curl/7.43.0
> Accept: */*
> Origin: http://www.microsoft.com
>
< HTTP/1.1 404 Not Found
< Server: Apache-Coyote/1.1
< Access-Control-Allow-Credentials: true
< Access-Control-Allow-Origin: http://www.microsoft.com
< Vary: Origin
< Cache-Control: no-cache
< Expires: Thu, 01 Jan 1970 00:00:00 GMT
< Pragma: no-cache
< Content-Type: text/html;charset=UTF-8
< Transfer-Encoding: chunked
< Date: Thu, 13 Aug 2015 12:52:15 GMT
<

I also tried the CORS filter of Tomcat instead, same result.

<filter>
  <filter-name>CorsFilter</filter-name>
  <filter-class>org.apache.catalina.filters.CorsFilter</filter-class>
</filter>
<filter-mapping>
  <filter-name>CorsFilter</filter-name>
  <url-pattern>/*</url-pattern>
</filter-mapping>

Questions:

(1) Am I missing something on the client/AngularJS $http side? Should I use a angular-http-interceptor? (Sorry, pretty new to AngularJS). I think that this is most probably the reason here, but not sure what's missing.

(2) I don't see why the CORS filter would not add the 'Access-Control-Allow-Origin' header to both responses but only to the one API call, since both API urls start with /alfresco/service, which should be handled by the CORS filter as per <url-pattern>/service/*</url-pattern>

(And why does it work for one API url, but for the other it does not? Only difference I see is that in one case, I am already authenticated and use an alf_ticket, in the other case I am not. But even if I add an (unnecessary) alf_ticket to the login call, it does not make any difference.)

(3) Why does it work in IE then at all? (by the way: with the Chrome extension https://chrome.google.com/webstore/detail/allow-control-allow-origi/nlfbmbojpeacfghkpbjhddihlkkiljbi it also works in Chrome.)

Related SO question: cross domain call using REST Alfresco

2条回答
神经病院院长
2楼-- · 2019-04-16 01:24

I have the same issue, for some reason the login api "GET" call does not return "Access-Control-Allow-Origin" in the headers. WORKAROUND: The "POST" call works fine!

查看更多
我命由我不由天
3楼-- · 2019-04-16 01:42

I faced similar issue and got it resolved by using "/alfresco/s/" instead of "/alfresco/service/".

In your case, try hitting using

http://localhost:8080/alfresco/s/api/login?u=admin&pw=admin.

Try if this works.

查看更多
登录 后发表回答