跨域请求被阻止 Symfony/AngularJS

Posted

技术标签:

【中文标题】跨域请求被阻止 Symfony/AngularJS【英文标题】:Cross-Origin Request Blocked Symfony/AngularJS 【发布时间】:2017-12-14 05:06:40 【问题描述】:

我目前在尝试使用 Angular 从返回 JSON 的 Symfony API 获取数据时遇到错误:

“跨域请求被阻止:同源策略不允许读取位于 http://localhost:8000/customers 的远程资源。(原因:缺少 CORS 标头“Access-Control-Allow-Origin”)。”

这是完整结果的截图:

我知道这个问题已被多次询问,但我找不到有效的答案。

当我不尝试在 api 控制器中检索 $session 时,它可以工作并且我得到了我需要的所有数据,但它没有,这是我的 api 控制器:

/**
 * @Rest\View(statusCode=Response::HTTP_CREATED)
 * @Rest\Get("/customers")
 */

/**
 * @Rest\View(statusCode=Response::HTTP_CREATED)
 * @Rest\Get("/index")
 */
public function getIndexAction(Request $request)

    $loginad = $this->getUser()->getUsername();

    $nom_ad = "******";
    $port_ad = ******;
    $compte_ad = "*******";
    $password_ad = "******";
    //parcours de l'AD
    // Connexion LDAP
    $ldapconn = ldap_connect($nom_ad, $port_ad)
    or die("Impossible de se connecter au serveur LDAP $nom_ad");
    if ($ldapconn)
        $ldapbind = ldap_bind($ldapconn, $compte_ad, $password_ad)
        or die("Impossible de se binder au serveur LDAP $nom_ad");
        if($ldapbind)
            $employeeID = false;
            $dn = "OU=CER35,DC=CeRNum,DC=dom";
            $filter="(samAccountName=$loginad)";
            $justtheseattributes = array( "ou", "sn", "givenname", "mail", "employeeid", "samaccountname");
            $sr=ldap_search($ldapconn, $dn, $filter, $justtheseattributes);
            $info = ldap_get_entries($ldapconn, $sr);
            for ($i=0;$i<$info["count"];$i++) 
                $employeeID = $info[$i]["employeeid"][0];
            
            if (!$employeeID) 
                $dn = "OU=CER56,DC=CeRNum,DC=dom";
                $filter="(samAccountName=$loginad)";
                $justtheseattributes = array( "ou", "sn", "givenname", "mail", "employeeid", "samaccountname");
                $sr=ldap_search($ldapconn, $dn, $filter, $justtheseattributes);
                $info = ldap_get_entries($ldapconn, $sr);
                for ($i=0;$i<$info["count"];$i++) 
                    $employeeID = $info[$i]["employeeid"][0];
                
            
        
    

    $agent = $this->get('doctrine')
        ->getRepository('CERAgentBundle:Agent', 'agent')
        ->findByCode($employeeID);

    $session = new Session();
    $session->set('agent', $agent);

    $formatted = [
        'civilite' => $agent[0]->getCivilite(),
        'prenom' => $agent[0]->getPrenom(),
        'nom' => $agent[0]->getNom()
        ];

    return new JsonResponse($formatted);

所以当我调用“localhost:8000/index”时,用于 CAS 服务器身份验证的包也会调用 https URL,这样用户就可以向 Intranet 的公司进行身份验证,完成后,他们最终可以从 localhost:8000/ 检索结果索引

这是我的 Angular 控制器:

angular.module('frontProfilDeveloppementApp')
.controller('ClientsCtrl', function ($scope, $http)
    $http.get('http://localhost:8000/customers')
        .then(function (data) 
            $scope.result = data;
        );
);

nelmio_cors 包配置:

nelmio_cors:
    defaults:
        allow_credentials: true
        allow_origin: ['*']
        allow_headers: ['*']
        allow_methods: ['POST', 'PUT', 'GET', 'DELETE']
        max_age: 3600
        hosts: []
        origin_regex: false

CAS 捆绑配置:

p_rayno_cas_auth:
server_login_url: https://extranet-authentification-******/cas-a3net/
server_validation_url: https://extranet-authentification-*****/cas-a3net/serviceValidate
server_logout_url: https://extranet-authentification-****/cas-a3net/logout

(security.yml):

security:
providers:
    cas:
      id: prayno.cas_user_provider
role_hierarchy:
      ROLE_ADMIN:       ROLE_USER
      ROLE_SUPER_ADMIN: ROLE_ADMIN

firewalls:
    dev:
        pattern: ^/(_(profiler|wdt)|css|images|js)/
        security: false
    main:
        anonymous: ~
        logout: ~
        guard:
            authenticators:
                - prayno.cas_authenticator

access_control:
    -  path: /index, roles: ROLE_USER

我认为我的 API 没有设置与 angular 相同的标头,因此浏览器不允许获取。

是否可以直接从 Angular 控制器设置 headers 选项,以便与 api 匹配?

【问题讨论】:

您无法从角度控制标题!。您需要禁用谷歌浏览器的网络安全进行测试 如果我禁用安全性它会起作用(我的错误,已编辑)但无论如何,我不想禁用安全性,我想添加正确的标题(如果可能的话)! 【参考方案1】:

您可以禁用标题。 解决方案在https://www.youtube.com/watch?v=uDy_cvf4nDg&feature=youtu.be

【讨论】:

【参考方案2】:

你应该总是从 Symfony 返回一个 Response 的实例,而不是直接返回你的 $customers 结果集。

以下是如何完成此操作的示例: return new JsonResponse($customers, 200, array('Access-Control-Allow-Origin'=> '*'));

您也可以在此处找到更多详细信息。

AJAX Cross-domain on symfony2

【讨论】:

您能粘贴 Chrome 开发工具网络选项卡中的响应标头吗? (对于我们感兴趣的请求)该标头是从 symfony 设置的吗? "连接 : Keep-Alive Content-Length : 0 Content-Type : text/html;charset=UTF-8 日期 : Tue, 11 Jul 2017 13:11:46 GMT Keep-Alive : timeout =15, max=100 位置:extranet-authentification-cerfrance.35-56.fr/cas-a3net/… %2Findex 服务器:Apache" 我想我贴错了,下面是回复: Access-Control-Allow-Cred... true Access-Control-Allow-Orig... localhost Cache-Control no-cache , private Connection close Content-Type text/html; charset=UTF-8 日期 2017 年 7 月 11 日星期二 13:28:21 GMT 主机 localhost:8000 位置 extranet-authentification-cerfrance.35-56.fr/cas-a3net/… %2Findex Set-Cookie phpSESSID=qg5cle767utjvsdcf5nc7tsmi5;路径=/; HttpOnly X-Debug-Token 0b81f4 X-Debug-Token-Link localhost:8000/_profiler/0b81f4 X-Powered-By PHP/5.5.38 您一定遇到了一些缓存问题或其他怪癖,因为我刚刚在本地主机上进行了测试,并使用该行在响应中正确设置了标题。 HTTP/1.1 200 OK 日期:2017 年 7 月 11 日星期二 13:29:15 GMT 服务器:Apache/2.4.7 (Ubuntu) X-Powered-By:PHP/5.5.9-1ubuntu4.21 Access-Control-Allow-Origin : * Cache-Control: no-cache Content-Length: 23 Keep-Alive: timeout=5, max=100 Connection: Keep-Alive Content-Type: application/json.我认为您应该删除缓存文件夹的内容(对于 dev 和 prod envs),预热缓存并重试。 我怎么知道标头是从 Symfony 设置的?这是一个 symfony url,它为 cas-auth 调用 https url。

以上是关于跨域请求被阻止 Symfony/AngularJS的主要内容,如果未能解决你的问题,请参考以下文章

socket.io 跨域请求被阻止

跨域请求被阻止原因:CORS 预检通道未成功

jQuery ajax 请求因为跨域而被阻止

跨域请求被阻止

AngularJS和跨域请求被阻止[关闭]

跨域请求被阻止:同源策略不允许读取远程资源