0

I still to find a solution, and search about CORS problem. To solve these, i have setup my configuration like this :

Project on server : Debian 8 / nginx / php-fpm

My Nginx vhost :

server {
    server_name sub.domain.com;
    root /home/projects/sub.domain.com/web;

    location / {
        try_files $uri /app.php$is_args$args;
    }


    # DEV
    location ~ ^/(app_dev|config)\.php(/|$) {
                fastcgi_pass unix:/var/run/php5-fpm-user.sock;
        fastcgi_split_path_info ^(.+\.php)(/.*)$;
        include fastcgi_params;
        fastcgi_param  SCRIPT_FILENAME  $realpath_root$fastcgi_script_name;
        fastcgi_param DOCUMENT_ROOT $realpath_root;
    }

    # PROD
    location ~ ^/app\.php(/|$) {
        fastcgi_pass unix:/var/run/php5-fpm-user.sock;
        fastcgi_split_path_info ^(.+\.php)(/.*)$;
        include fastcgi_params;
        fastcgi_param  SCRIPT_FILENAME  $realpath_root$fastcgi_script_name;
        fastcgi_param DOCUMENT_ROOT $realpath_root;
        internal;
    }

}

Server side : Symfony 3.0 with FosUserBundle/ FOSRestBundle/ NelmioApiDocBundle / NelmioCorsBundle/ LexikJWTAuthenticationBundle / JMSSerializer

My config.yml :

# FosUserBundle Configuration
fos_user:
    db_driver: orm
    firewall_name: main
    user_class: UserBundle\Entity\User
    group:
        group_class: UserBundle\Entity\Group
        form:
            type: UserBundle\Form\Type\GroupFormType
    profile:
        form:
            type: UserBundle\Form\Type\ProfileFormType

# FOSRestBundle Configuration
fos_rest:
    param_fetcher_listener: true
    body_listener: true
    format_listener: true
    view:
        view_response_listener: 'force'
        formats:
            xml: true
            json : true
        templating_formats:
            html: true
        force_redirects:
            html: true
        failed_validation: HTTP_BAD_REQUEST
        default_engine: twig
    routing_loader:
        default_format: json

# LexikJWTAuthenticationBundle Configuration
lexik_jwt_authentication:
    private_key_path: %jwt_private_key_path%
    public_key_path:  %jwt_public_key_path%
    pass_phrase:      %jwt_key_pass_phrase%
    token_ttl:        %jwt_token_ttl%

# JMSSerializer Configuration
jms_serializer:
    metadata:
        auto_detection: true

# NelmioCorsBundle Configuration
nelmio_cors:
    defaults:
        allow_credentials: true
        allow_origin: []
        allow_headers: []
        allow_methods: []
        expose_headers: []
        max_age: 0
        hosts: []
        origin_regex: false
    paths:
        '^/api/':
            allow_origin: ['*']
            allow_headers: ['Origin', 'Content-Type', 'X-Requested-With', 'Accept']
            allow_methods: ['POST', 'PUT', 'GET', 'DELETE', 'OPTIONS']
            max_age: 3600

My security.yml :

api_doc:
    pattern: ^/api/doc
    anonymous: true

api_login:
    pattern:  ^/api/login
    provider: fos_userbundle
    stateless: true
    anonymous: true
    form_login:
        check_path:     /api/login_check
        require_previous_session: false
        username_parameter: username
        password_parameter: password
        success_handler:          lexik_jwt_authentication.handler.authentication_success
        failure_handler:          lexik_jwt_authentication.handler.authentication_failure

api:
    pattern:   ^/api
    stateless: true
    provider: fos_userbundle
    lexik_jwt:
        authorization_header:
            enabled: true
            prefix:  Bearer
        query_parameter:
            enabled: true
            name:    Bearer
        throw_exceptions:        true
        create_entry_point:      true

## Main firewall
main:
    pattern: ^/
    form_login:
        provider: fos_userbundle
        csrf_token_generator: security.csrf.token_manager
        login_path: fos_user_security_login
        check_path: fos_user_security_check
        remember_me: true
        default_target_path: lgb_onepage_home
    logout:
        path:   fos_user_security_logout
        target: lgb_onepage_home
    anonymous: true
    remember_me:
        secret:      %secret%
        lifetime: 604800 # 1 week in seconds
        path:     /
        domain:   ~ # Defaults to the current domain from $_SERVER
        #                secure:   true
        httponly: true

access_control:
    - { path: ^/login$, role: IS_AUTHENTICATED_ANONYMOUSLY }
    - { path: ^/register, role: ROLE_ADMIN }
    - { path: ^/resetting, role: ROLE_ADMIN }
    - { path: ^/intranet/, role: ROLE_USER }
    - { path: ^/api/login, roles: IS_AUTHENTICATED_ANONYMOUSLY }
    - { path: ^/api/doc, roles: IS_AUTHENTICATED_ANONYMOUSLY }
    - { path: ^/api,       roles: [IS_AUTHENTICATED_FULLY, ROLE_ADMIN] }

And for my client, i use Ionic with angular JS on base project (with skeleton tabs for have a valid login form) :

My config :

.config(function ($stateProvider, $urlRouterProvider, localStorageServiceProvider, $httpProvider) {
    $stateProvider...;

    // if none of the above states are matched, use this as the fallback
    $urlRouterProvider.otherwise('/app/playlists');

    localStorageServiceProvider
        .setPrefix('lgb-preorder');

    $httpProvider.defaults.headers.common = {};
    $httpProvider.defaults.headers.post = {};
    $httpProvider.defaults.headers.put = {};
    $httpProvider.defaults.headers.patch = {};
});

and my function (doesn't work):

$scope.doLogin = function () {

            var loginData = {
                username: this.login.username,
                password: this.login.password
            };

            $http({
                url: 'http://sub.domain.com/app_dev.php/api/login_check',
                method: 'POST',
                data: loginData,
                headers: {'Content-Type': 'application/json'}
            })
                .success(function (data) {
                    console.log("Success -- login ok with ", data);
                })
                .error(function (error) {
                    console.log("ERROR -- login fail with ", error);
                });
        };

Error send is :

XMLHttpRequest cannot load http://sub.domain.com/app_dev.php/api/login_check. Response to preflight request doesn't pass access control check: The 'Access-Control-Allow-Origin' header contains multiple values '*, http://localhost:8100', but only one is allowed. Origin 'http://localhost:8100' is therefore not allowed access.

it seems because my http request have 2 definitions of Access-Control-Allow-Headers and Access-Control-Allow-Origin :

Request URL:http://sub.domain.com/app_dev.php/api/login_check
Request Method:OPTIONS
Status Code:200 OK
Remote Address:x.x.x.x:80
Response Headers
view source
Access-Control-Allow-Credentials:true
Access-Control-Allow-Headers:Origin, X-Requested-With, Content-Type, Accept
Access-Control-Allow-Headers:origin, content-type, x-requested-with, accept
Access-Control-Allow-Methods:POST, PUT, GET, DELETE, OPTIONS
Access-Control-Allow-Origin:http://localhost:8100
Access-Control-Allow-Origin:*
Access-Control-Max-Age:3600

but why ???____???

If anyone have an idea, its really appreciated =) Thanx for your help


This request CURL is working:

curl -X POST http://sub.domain.com/app_dev.php/api/login_check -d '{"username": "user", "password": "pass"}' -H "Content-Type: application/json"
2
  • what's the web server you are using ? are you sure that web server is not adding the extra Access-Control-Allow-Origin ? .. Commented May 15, 2016 at 4:39
  • I ha ve used Nginx, i add my virtual host in this configuration. I dont know if nginx could add header in this request. Commented May 16, 2016 at 13:02

1 Answer 1

2

I had same issue with OPTIONS. My backend is Spring. I found something equivalent for PHP.

Getting Cors Working

You need to focus on preflight. I think you need to add this to your backend code.

  // respond to preflights
if ($_SERVER['REQUEST_METHOD'] == 'OPTIONS') {
  // return only the headers and not the content
  // only allow CORS if we're doing a GET - i.e. no saving for now.
  if (isset($_SERVER['HTTP_ACCESS_CONTROL_REQUEST_METHOD']) && $_SERVER['HTTP_ACCESS_CONTROL_REQUEST_METHOD'] == 'GET') {
    header('Access-Control-Allow-Origin: *');
    header('Access-Control-Allow-Headers: X-Requested-With');
  }
  exit;
}
Sign up to request clarification or add additional context in comments.

2 Comments

Thanx for your answer. I didn't understand how this configuration could delete one of these headers ? :s i have readed the remysharp post, but this topic is very specific.
I have little php knowledge . gist.github.com/alexjs/4165271 gist.github.com/Stanback/7145487. I found something for nginx .maybe you can do in configuration.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.