Заголовок Angular и PHP-проекта Access-Control-Allow-Origin содержит несколько значений - PullRequest
0 голосов
/ 06 ноября 2018

Я работаю над одностраничным приложением на основе php и angular 6.

Проект работает нормально, за исключением сегодняшнего дня, когда я увидел на консоли следующую ошибку:

Доступ к XMLHttpRequest по адресу http://dev.local/scripts/login.php' из origin 'http://localhost:4200' заблокирован политикой CORS: Заголовок «Access-Control-Allow-Origin» содержит несколько значений 'http://localhost:4200, *', но разрешен только один.

Под dev.local Я имею в виду виртуальный хост, созданный с помощью wampserver для тестирования.

На login.php у меня есть следующие скрипты:

PHP Сценарий вызова:

<?php

require_once('../api.php');

//Getting username and password from Angular

$user = $_POST['username'];
$password = $_POST['password'];

$newApi = new api();
$conn = $newApi->connection();
//var_dump($conn);
$res = $newApi->login($conn, $user, $password);

echo json_encode($res);
?>

В API:

<?php
header('Access-Control-Allow-Origin: *');
header('Access-Control-Allow-Headers: *');
header('Content-Type: application/json');
header('Access-Control-Allow-Methods: GET, POST, PUT, PATCH, DELETE, HEAD, OPTIONS');
header('Content-Type', 'application/x-www-form-urlencoded; charset=UTF-8');
error_reporting(E_ALL);

require_once('JWT.php');

include_once('../phpmailer/PHPMailer.php');
include_once('../phpmailer/POP3.php');
include_once('../phpmailer/SMTP.php');
include_once('../phpmailer/Exception.php');
class api {
    private $username ="root";
    private $password ="root";
    private $db="reg_sys";
    private $host = "localhost";
    public $conn;
    public $key = "key123";
    public $sessionJwt;
    public function connection(){
        session_start();
        try{
            $this->conn = new PDO("mysql:host=$this->host;dbname=$this->db", $this->username, $this->password);
            $this->conn->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
            $this->conn->exec("SET CHARACTER SET utf8");

            return $this->conn;
        }
        catch(PDOException $e){
            return $e->getMessage();
        }

    }
public function login($conn, $user, $password){

        try{
            $exist = $this->checkIfUserExist($conn, $user);
            if($exist['exist'])
            {
                //Check Password and Generate a token
                $checkPassword = "SELECT user_id, user_name, user.role_id, roles.role_type 
                FROM user
                    LEFT JOIN roles ON user.role_id = roles.role_id 
                WHERE 
                    user_name = :user 
                AND 
                    user_password = :pass
                LIMIT 1";

                $execCheckPassword = $this->conn->prepare($checkPassword);
                $execCheckPassword->bindValue('user', $user);
                $execCheckPassword->bindValue('pass', $password);
                $execCheckPassword->execute();
                $fetchRes = $execCheckPassword->fetch();
                $resFound = $execCheckPassword->rowCount();
                //Then
                if($resFound>0)
                {
                    //Generate a JWT
                    //Array to generate a JWT from

                    $arrayJWT = 
                    [
                        'login_id'=>$fetchRes['user_id'],
                        'username'=> $fetchRes['user_name'], 
                        'user_role'=>$fetchRes['role_type']
                    ];

                    $encodedJWT = JWT::encode($arrayJWT, $this->key);

                    $resArray = 
                    [
                        'jwt'=> $encodedJWT,
                        'user_exist'=> 'true', 
                        'user_id'=>$fetchRes['user_id'],  
                        'username'=> $fetchRes['user_name'], 
                        'user_role'=>$fetchRes['role_type']
                    ];

                    $_SESSION['jwt']=$encodedJWT;


                }
                else
                {
                    $resArray = ['user_exist'=> 'false', 'errorMsg' => "Incorrect Password!!!"];
                    //Insert into login_attempt table
                    $sql = "INSERT INTO login_attempt(login_attempt_date, login_attempt_status, user_id)
                            VALUES(:date_time, :attempt_status, :user_id)";
                    $exec = $conn->prepare($sql);
                    $exec->bindValue(':date_time', $this->currentDateTime);
                    $exec->bindValue(':attempt_status', 'Active');
                    $exec->bindValue(':user_id', $exist['user_id']);
                    $exec->execute();
                }
            }
            else
            {
                $resArray = ['user_exist'=> 'false', 'errorMsg' => "Username doesn't exist"];
            }
            return $resArray;
        }
        catch(PDOException $e)
        {
            echo $e->getMessage();
        }



    }
}

На угловой стороне:

login(username, password): Observable<any> {
    let headerOptions = new HttpHeaders();
    //headerOptions.append('Access-Control-Allow-Origin', '*');
    //headerOptions.append('Access-Control-Request-Headers', '*');
    headerOptions.append('Access-Control-Allow-Credentials', 'true');
    headerOptions.append('Content-Type', 'application/json');
    headerOptions.append('Access-Control-Allow-Methods', 'GET,PUT,POST,DELETE,PATCH,OPTIONS');
    headerOptions.append('Content-Type', 'application/x-www-form-urlencoded; charset=UTF-8');


    this.credentials = { user: username, pass: password };
    const httpParams = new HttpParams()
      .set('username', username)
      .set('password', password);


    return this.http.post(this.globalVar.login, httpParams, {
      headers: headerOptions,
    })
  }

Как видите, я прокомментировал следующее:

//headerOptions.append('Access-Control-Allow-Origin', '*');
//headerOptions.append('Access-Control-Request-Headers', '*');

На httpd-vhosts.conf:

# Virtual Hosts
#
<VirtualHost *:80>
  ServerName localhost
  ServerAlias localhost
  DocumentRoot "${INSTALL_DIR}/www"
  <Directory "${INSTALL_DIR}/www/">
    Options +Indexes +Includes +FollowSymLinks +MultiViews
    Header set Access-Control-Allow-Origin "*"
    AllowOverride All
    Require local
    Allow from 127.0.0.1
    Allow from 192.168.10.0
    Allow from 192.168.0.217
    Require all granted
  </Directory>
</VirtualHost>


#dev.local
<VirtualHost *:80>

    ServerAdmin it@m.org
    DocumentRoot "c:/wamp64/www/dev"
    ServerName dev.local    
    ServerAlias www.dev.local

    <Directory  "c:/wamp64/www/dev/">

        AllowOverride All
        Require local
        Allow from 127.0.0.1
        #Allow from 192.168.10.0
        #Allow from 192.168.0.140
        Require ip 192.168.0
        Require ip 192.168.1    
        Require ip 192.168.10
        Require all granted     
                Allow from all
    </Directory>
</VirtualHost>

И я включил mod_headers в httpd.conf.

Я попробовал решение из этого вопроса в стеке, и этот ответ тоже, но ничего не изменилось, и все еще получаю ту же ошибку.

XHRResponse:

enter image description here

получить ( "http://dev.local/scripts/login.php", { "полномочия": "опустить", "заголовки": { "принимает": "применение / JSON, текст / равнина, / * * +1059 " "тип содержимого": "применение / х-WWW-форм-urlencoded; кодировка = UTF-8"}, "ссылающаяся":" http://localhost:4200/login","referrerPolicy":"no-referrer-when-downgrade","body":"username=test&password=test1","method":"POST","mode":"cors"});

1 Ответ

0 голосов
/ 06 ноября 2018

Я сталкивался с этой проблемой довольно много раз при разработке с бэкэндами. На сервере, когда ваше приложение размещено, вы можете находиться в том же домене, используя URL-адрес в службе как \login вместо http://localhost:8000/login.

Для локальной разработки используйте proxy config для запуска angular dev server. Пожалуйста, прочитайте https://github.com/angular/angular-cli/blob/master/docs/documentation/stories/proxy.md для того же. Это изменит происхождение /login с http://localhost:4200 на http://localhost:8000.

Обновление: (localhost: 8000 - просто пример, ваш может отличаться) Убедитесь, что браузеры не допускают контент из смешанных источников (смесь HTTP и HTTPS) и из разных источников (данные из XHR из разных источников). Так что прокси используется для того, чтобы обмануть браузер.

Ваше приложение отправляет \login на localhost:4200, а ваша конфигурация прокси-сервера на сервере угловой разработки направляет весь трафик на \login на localhost:8000, поскольку там находится API \login. Но браузер увидит, что вы отправляете запрос на localhost:4200\login, поэтому больше не возникает проблема с CORS. Ваш угловой сервер разработки позаботится о маршрутизации ваших внутренних API. Вам просто нужно добавить конфигурации для того же.

Не стесняйтесь задавать больше сомнений, если вы не понимаете. Попробую другой подход объяснить.

Надеюсь, это поможет вам. Это устранит проблемы с CORS.

...