Задний план

Я настроил приложение Express.js за прокси-сервером , чтобы пользователи могли войти в систему, прежде чем они будут перенаправлены в веб-приложение. Это приложение не может обслуживать некоторые изображения в Safari (macOS / iOS), потому что Safari не отправляет cookie обратно с запросами изображений , которые исходят из метода loadImage() в моем p5.js код. Этого не происходит в Chrome (macOS).

Когда я загружаю страницу, браузер нормально запрашивает ресурсы. Но запросы, исходящие из моего приложения, возвращают другой сеанс, который не вошел в систему, и перехватывается Express:

// Request for the main page by the browser
Session {
  cookie:
   { path: '/',
     _expires: 2020-05-04T16:26:00.291Z,
     originalMaxAge: 259199998,
     httpOnly: true,
     secure: true },
  loggedin: true }

// Request for image assets by a script in my application
Session {
  cookie:
   { path: '/',
     _expires: 2020-05-04T16:26:00.618Z,
     originalMaxAge: 259200000,
     httpOnly: true,
     secure: true } }

HTTP-запросы от Safari

GET https://mydomain/app/img/svg/Water.svg HTTP/1.1
Host: mydomain
Origin: https://mydomain
Connection: keep-alive
If-None-Match: W/"5e6-171c689d240"
Accept: image/png,image/svg+xml,image/*;q=0.8,video/*;q=0.8,*/*;q=0.5
If-Modified-Since: Wed, 29 Apr 2020 15:24:13 GMT
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_4) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/13.1 Safari/605.1.15
Referer: https://mydomain/app/
Accept-Language: en-us
Accept-Encoding: gzip, deflate, br

HTTP/1.1 302 Found
Date: Fri, 01 May 2020 06:50:07 GMT
Server: Apache/2.4.6 (CentOS) OpenSSL/1.0.2k-fips PHP/7.3.17
X-Powered-By: Express
Location: /
Vary: Accept
Content-Type: text/plain; charset=utf-8
Content-Length: 23
Access-Control-Allow-Origin: *
Keep-Alive: timeout=5, max=100
Connection: Keep-Alive

Found. Redirecting to /

Экспресс приложение

Приложение настроено за HTTPS-прокси, поэтому я установил для объекта Express Session доверенный прокси-сервер и установил безопасность на auto (установка на false не устраняет проблему):

app.set('trust proxy', 1)
app.use(session({
    secret: 'my-secret',
    resave: true,
    saveUninitialized: true,
    cookie: {
        secure: 'auto',
        maxAge: 259200000
    }
}));

Когда пользователь входит в систему, он отправляется в /auth для проверки базы данных.

app.post('/auth', function (request, response) {
    var user = request.body.user;
    var password = request.body.password;

    if (user && password) {
        connection.query('SELECT * FROM accounts WHERE user = ? AND password = ?', [user, password], function (error, results, fields) {
            if (results.length > 0) {

                request.session.loggedin = true;

                // If the user logs in successfully, then register the subdirectory
                app.use("/app", express.static(__dirname + '/private/'));

                // Then redirect
                response.redirect('/app');
            } else {
                response.send('Incorrect password!');
            }
            response.end();

            if (error) {
                console.log(error);
            }
        });
    } else {
        response.send('Please enter Username and Password!');
        response.end();
    }
});

Они перенаправляются на /app при входе в систему:

app.all('/app/*', function (request, response, next) {

    if (request.session.loggedin) {    
        next(); // allow the next route to run
    } else {
        // The request for images from my p5 script fails and these request redirect to "/"
        response.redirect("/");
    }
})

Вопрос

Что я могу сделать, чтобы Safari передал cookie-файл сеанса со своим запросом, чтобы Express вернул правильный ресурс?


Редактировать

Включая функцию, которая вызывает loadImage(). Это встроено в класс ES6, который загружает изображения для частиц в химическом моделировании. Этот класс должен успешно разрешать обещания, чтобы другие классы более высокого порядка могли устанавливать правильные свойства.

loadParticleImage() {

    return new Promise((resolve, reject) => {

        loadImage(this.imageUrl, (result) => {

            // Resolves the Promise with the result
            resolve(result);

        }, (reason) => {

            console.log(reason);
        });
    })
}

Редактировать № 2

Включая заголовки для успешного запроса непосредственно к URL-адресу актива изображения:

GET https://mydomain/app/img/svg/Water.svg HTTP/1.1
Host: mydomain
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Cookie: connect.sid=s%3A2frOCv41gcVRf1J4t5LlTcWkdZTdc8NT.8pD5eEHo6JBCHcpgqOgszKraD7AakvPsMK7w2bIHlr4
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_4) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/13.1 Safari/605.1.15
Accept-Language: en-us
Accept-Encoding: gzip, deflate, br
Connection: keep-alive
1
dfd0226 1 Май 2020 в 19:58

2 ответа

Лучший ответ

Я предлагаю использовать статическое промежуточное программное обеспечение Express для обслуживания статических файлов. При этом вам не потребуется сеанс для получения изображений, js, css и т. Д. Кроме того, это ускоряет работу вашего приложения. Вам нужно разместить

app.use(express.static( ... )) 

Перед оператором app.use(session( ... )), если вам нужна дополнительная производительность, потому что если вы это сделаете, Express не будет пытаться создать сеанс для статических файлов.

2
CoderFF 1 Май 2020 в 18:56

fetch() вызов в для этой функции loadImage() не устанавливает опция credentials, которая определяет, включены ли файлы cookie в запрос или нет, поэтому они не отправляются вместе с запросом.

Вы действительно нуждаетесь в аутентификации перед передачей изображения? Если нет, вы можете изменить порядок обслуживания изображений на своем сервере, чтобы они могли обслуживаться без аутентификации, используя express.static(), указывающий на каталог, содержащий только ресурсы, которые можно обслуживать без аутентификации. Если они действительно должны быть аутентифицированы, вам, возможно, придется пропатчить код loadImage(), чтобы использовать опцию credentials: include, или загрузить свои изображения другим способом.

2
jfriend00 1 Май 2020 в 17:51