Express, Create-React-App и Passport-Twitter

Я настраиваю Twitter на моем create-react-app приложение с помощью вспомогательной функции (через axios) на переднем конце, чтобы начать passport Ойут процесс на моем бэкэнде. В данный момент я нахожусь в разработке, поэтому я размещаю свой экспресс-сервер в порту 3001 и мой фронт в порту 3000 с прокси на входе в порт 3001. Я установил разрешения CORS через cors Пакет Npm.

Независимо от того, какой набор конфигураций я пробую, я не могу завершить процесс OAuth в Twitter. Я пробовал переключать порты, сохраняя те же порты; Я попытался прокси мой бэкэнд с express-http-proxy,

я использовал http://127.0.0.1 вместо localhost как в моей функции обратного вызова, так и в моем первоначальном вызове API, пробуя оба порта 3000 а также 3001,

Я нахожусь в точке, где я не уверен, где я иду не так, или если мне нужно отказаться от passport-twitter для других решений.

В каждом случае я получаю следующую ошибку:

Failed to load https://api.twitter.com/oauth/authenticate?
oauth_token=alphanumericcoderedactedherebyme: No 'Access-Control-Allow-Origin' 
header is present on the requested resource. Origin 'http://localhost:3000' is 
therefore not allowed access.

В зависимости от конфигурации, которую я попытался, я получаю null или же http://localhost:3001 или же http://127.0.0.1,

Обратите внимание, что я успешно вызываю API своего сервера несколько раз по другим причинам, например, при подключении к Yelp Fusion API, Более того, я использую промежуточное программное обеспечение для регистрации данных сеанса и вижу, что я успешно получаю oauth_token а также oauth_token_secret из твиттера Вызов не выполняется на следующем этапе процесса oauth:

[0] *************SESSION MIDDLEWARE***************
[0] Session {
[0]   cookie:
[0]    { path: '/',
[0]      _expires: 2018-01-06T20:20:31.913Z,
[0]      originalMaxAge: 2678400000,
[0]      httpOnly: true },
[0]   'oauth:twitter':
[0]    { oauth_token: 'alphanumericcoderedactedherebyme',
[0]      oauth_token_secret: 'alphanumericcoderedactedherebyme' } }
[0]
[0] Logged In:
[0] __________ false
[0] **********************************************

Вот соответствующие части моего кода -

BACKEND CODE

SERVER.JS

// Dependencies

const express = require("express");
const cors = require("cors");
const passport = require('passport');

// Initialize Express Server
const app = express();

// Specify the port.
var port = process.env.PORT || 3001;
app.set('port', port);

app.use(passport.initialize());
app.use(passport.session());

//enable CORS
app.use(cors());

//set up passport for user authentication
const passportConfig = require('./config/passport');

require("./controllers/auth-controller.js")(app);

// Listen on port 3000 or assigned port
const server = app.listen(app.get('port'), function() {
    console.log(`App running on ${app.get('port')}`);
});

PASSPORT.JS

const passport = require('passport');
const TwitterStrategy = require('passport-twitter').Strategy;

passport.use(new TwitterStrategy({
    consumerKey: process.env.TWITTER_CONSUMER_KEY,
    consumerSecret: process.env.TWITTER_CONSUMER_SECRET,
    callbackURL: process.env.NODE_ENV === 'production' ? process.env.TWITTER_CALLBACK_URL : 'http://localhost:3000/auth/twitter/callback'
    },
    function(accessToken, refreshToken, profile, done) {
        ...etc, etc, etc

AUTH-CONTROLLER.JS

const router = require('express').Router();
const passport = require('passport');

module.exports = function(app) {
    router.get('/twitter', passport.authenticate('twitter'));

    router.get('/twitter/callback',
        passport.authenticate('twitter', {
            successRedirect: '/auth/twittersuccess',
            failureRedirect: '/auth/twitterfail'
        })
    );

    router.get('/twittersuccess', function(req, res) {
        // Successful authentication
        res.json({ user: req.user, isAuth: true });
    })

    router.get('/twitterfail', function(req, res) {
        res.statusCode = 503;
        res.json({ err: 'Unable to Validate User Credentials' })
    })

    app.use('/auth', router);
}

FRONTEND CODE

HELPERS.JS

import axios from 'axios';

export function authUser() {
    return new Promise((resolve, reject) => {
        axios.get('/auth/twitter', {
            proxy: {
                host: '127.0.0.1',
                port: 3001
            }
        }).then(response => {
            resolve(response.data);
        }).catch(err => {
            console.error({ twitterAuthErr: err })
            if (err) reject(err);
            else reject({ title: 'Error', message: 'Service Unavailable - Please try again later.' });
        });
    });
}



ОБНОВЛЕНИЕ Я проверил, что Проверка подлинности паспорта работает на моем внутреннем порту. Я вызвал конечную точку прямо в браузере и был перенаправлен на авторизацию Twitter, которая затем вернула моему обратному вызову новый пользователь, сохраненный в моей схеме, который был сохранен в данных сеанса.

Это означает, что проблема заключается в использовании Create-React-App на другом порту, чем мой бэкэнд.

http://127.0.0.1:3001/auth/twittersuccess

"user": {
    "_id": "redactedbyme",
    "name": "Wesley L Handy",
    "__v": 0,
    "twitterId": "redactedbyme",
    "favorites": [],
    "friends": []
},
"isAuth": true

2 ответа

Решение

Я не смог найти решение проблемы под рукой, посоветовавшись с несколькими разработчиками и разместив этот вопрос на других форумах.

Однако, согласно этому блогу, passport-twitter не оптимизирован для RESTful API. Этот же блог предоставляет полезное руководство для использования этого passport-twitter-token стратегия вместе с react-twitter-auth нашел здесь

Проблема связана с тем, что с Create-React-App приложение работает на двух разных серверах, один для внешнего интерфейса и другой для задней части. Невозможно обойти проблему CORS без последовательной связи между интерфейсом и сервером, что не разрешено в паспорте. Passport - отличный инструмент для обработки OAuth на одном сервере, но в OAuth требуется немало информации, требующей большей сложности.

Учебное пособие Ивана Васильевича является полезной отправной точкой для понимания и проработки этой сложности.

Если кто-нибудь, пришедший сюда, застрял в поиске пользователей с помощью Reactjs из passport-twitterстратегия, Вот решение, которое я нашел.

Все, что вам нужно сделать, это разрешить учетные данные

Включение учетных данных дает возможность использовать файлы cookie или express-sessionна фронтенде. Прочтите MDN для более подробной информации.

Бэкэнд:

      // cors policy setup
app.use(
  cors({
    origin: "http://localhost:3000", // front end url
    optionsSuccessStatus: 200,
    credentials: true,
  })
);

Внешний интерфейс:

      axios.get(`${apiURL}/profile`, { withCredentials: true })
Другие вопросы по тегам