部署到生产后的Passport.js TokenError [英] Passport.js TokenError After Deployment to Production

查看:73
本文介绍了部署到生产后的Passport.js TokenError的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个MERN堆栈应用程序,该应用程序使用Passport.js进行Facebook/Twitter/Google身份验证.在开发环境中,一切正常,我们能够对用户进行身份验证并将其登录到应用程序中.

I have a MERN stack app which uses Passport.js for Facebook/Twitter/Google authentication. In the development environment, everything works well and we are able to authenticate the user and log them into the application.

在确认开发环境中的功能之后,我们将其部署到了Heroku,但该功能在生产环境中不起作用,并且Passport.js失败并显示"TokenError",表明该应用程序的域中未包含域URL (即使我们确认它已在应用程序的域中列出).

After confirming the functionality in the development environment, we deployed to Heroku, but the same functionality is not working in production, and Passport.js is failing with a "TokenError" stating that the Domain URL is not included in the app's domains (even though we confirmed it is listed in the app's domains).

下面列出了该代码以及屏幕快照,这些屏幕快照确认该URL在应用程序的域中.您还可以在此记录中看到从Facebook成功调用了回调的实时行为- https://thiag0 .tinytake.com/tt/MzcxMjIyNV8xMTI5MTA3MA

The code is listed below along with screenshots confirming that the URL is in the app's domains. You can also see the live behavior of the callback being successfully called from Facebook in this recording - https://thiag0.tinytake.com/tt/MzcxMjIyNV8xMTI5MTA3MA

非常感谢您为我指明正确的方向!

Any help pointing me in the right direction is greatly appreciated!

Server.js

Server.js

const express = require('express');
const connectDB = require('./config/db');
const configurePassport = require('./config/passport');
const path = require('path');
const fs = require('fs');
const https = require('https');

const app = express();

// Connect Database
connectDB();

// Init Middleware
app.use(express.json({ extended: false }));

// Passport Middleware
configurePassport(app);

// Define Routes
app.use('/api/users', require('./routes/api/users'));
app.use('/api/auth', require('./routes/api/auth'));
app.use('/api/profile', require('./routes/api/profile'));
app.use('/api/posts', require('./routes/api/posts'));

// Serve static assets in production
if (process.env.NODE_ENV === 'production') {
  // Set static folder
  app.use(express.static('client/build'));

  app.get('*', (req, res) => {
    res.sendFile(path.resolve(__dirname, 'client', 'build', 'index.html'));
  });
}

const PORT = process.env.PORT || 5000;

if (process.env.NODE_ENV === 'production') {
  app.listen(PORT, () => console.log(`Server started on port ${PORT}`));
} else {
  https
    .createServer(
      {
        key: fs.readFileSync('config/certificate/server.key'),
        cert: fs.readFileSync('config/certificate/server.cert')
      },
      app
    )
    .listen(PORT, () => console.log(`Server started on port ${PORT}`));
}

Passport.js

Passport.js

const passport = require('passport');
const config = require('config');
const session = require('express-session');
const jwt = require('jsonwebtoken');
const gravatar = require('gravatar');
const bcrypt = require('bcryptjs');
const uuid = require('uuid');

const FacebookStrategy = require('passport-facebook').Strategy;
const TwitterStrategy = require('passport-twitter').Strategy;
const GoogleStrategy = require('passport-google-oauth2').Strategy;

const User = require('../models/User');

const webHost = config.get('webHost');

passport.serializeUser(function(user, done) {
  done(null, user.id);
});

passport.deserializeUser(function(id, done) {
  User.findById(id, function(err, user) {
    done(err, user);
  });
});

const configurePassport = app => {
  app.use(
    session({
      secret: config.get('jwtSecret'),
      resave: false,
      saveUninitialized: true
    })
  );
  app.use(passport.initialize());
  app.use(passport.session());

  passport.use(
    new FacebookStrategy(
      {
        clientID: config.get('facebook_app_id'),
        clientSecret: config.get('facebook_app_secret'),
        callbackURL: config.get('facebook_callback_url'),
        profileFields: ['email', 'name']
      },
      async (accessToken, refreshToken, profile, done) => {
        const { email, last_name, first_name, id } = profile._json;

        let user = await User.findOne({ facebook_id: id });

        if (!user) {
          // Create user if they don't exist
          user = new User({
            ...
          });

          await user.save();
        }

        done(null, user);
      }
    )
  );

  passport.use(
    new TwitterStrategy(
      {
        consumerKey: config.get('twitter_consumer_key'),
        consumerSecret: config.get('twitter_consumer_secret'),
        callbackURL: config.get('twitter_callback_url'),
        userProfileURL:
          'https://api.twitter.com/1.1/account/verify_credentials.json?include_email=true'
      },
      async function(token, tokenSecret, profile, done) {
        const { email, name, id } = profile._json;

        let user = await User.findOne({ twitter_id: id });

        if (!user) {
          // Create user if they don't exist
          user = new User({
            ...
          });

          await user.save();
        }

        done(null, user);
      }
    )
  );

  // Use the GoogleStrategy within Passport.
  //   Strategies in Passport require a `verify` function, which accept
  //   credentials (in this case, an accessToken, refreshToken, and Google
  //   profile), and invoke a callback with a user object.
  passport.use(
    new GoogleStrategy(
      {
        clientID: config.get('google_app_id'),
        clientSecret: config.get('google_app_secret'),
        callbackURL: config.get('google_callback_url')
      },
      async function(accessToken, refreshToken, profile, done) {
        const { email, name, sub } = profile._json;

        let user = await User.findOne({ google_id: sub });

        if (!user) {
          // Create user if they don't exist              
          user = new User({
            ...
          });

          await user.save();
        }

        done(null, user);
      }
    )
  );

  app.get(
    '/auth/facebook/callback',
    passport.authenticate('facebook', {
      session: false,
      failureRedirect: webHost + '/login'
    }),
    function(req, res) {
      const payload = {
        user: {
          id: req.user._id
        }
      };

      jwt.sign(
        payload,
        config.get('jwtSecret'),
        { expiresIn: 36000 },
        (err, token) => {
          if (err) throw err;
          return res.redirect(webHost + '/social/facebook/' + token);
        }
      );
    }
  );

  app.get(
    '/auth/facebook',
    passport.authenticate('facebook', {
      session: false,
      scope: ['email', 'user_posts']
    })
  );

  // Redirect the user to Twitter for authentication.  When complete, Twitter
  // will redirect the user back to the application at /auth/twitter/callback
  app.get(
    '/auth/twitter',
    passport.authenticate('twitter', {
      session: false
    })
  );

  // Twitter will redirect the user to this URL after approval.  Finish the
  // authentication process by attempting to obtain an access token.  If
  // access was granted, the user will be logged in.  Otherwise, authentication has failed.
  app.get(
    '/auth/twitter/callback',
    passport.authenticate('twitter', {
      session: false,
      failureRedirect: webHost + '/login'
    }),
    function(req, res) {
      const payload = {
        user: {
          id: req.user._id
        }
      };

      jwt.sign(
        payload,
        config.get('jwtSecret'),
        { expiresIn: 36000 },
        (err, token) => {
          if (err) throw err;
          return res.redirect(webHost + '/social/twitter/' + token);
        }
      );
    }
  );

  // GET /auth/google
  app.get(
    '/auth/google',
    passport.authenticate('google', {
      session: false,
      scope: [
        'https://www.googleapis.com/auth/plus.login',
        'https://www.googleapis.com/auth/userinfo.email'
      ]
    })
  );

  // GET /auth/google/callback
  app.get(
    '/auth/google/callback',
    passport.authenticate('google', {
      session: false,
      failureRedirect: webHost + '/login'
    }),
    function(req, res) {
      const payload = {
        user: {
          id: req.user._id
        }
      };

      jwt.sign(
        payload,
        config.get('jwtSecret'),
        { expiresIn: 36000 },
        (err, token) => {
          if (err) throw err;
          return res.redirect(webHost + '/social/google/' + token);
        }
      );
    }
  );
};

module.exports = configurePassport;

Heroku日志

2019-08-20T20:04:52.264433+00:00 app[web.1]: FacebookTokenError: Can't Load URL: The domain of this URL isn't included in the app's domains. To be able to load this URL, add all domains and subdomains of your app to the App Domains field in your app settings.
2019-08-20T20:04:52.264453+00:00 app[web.1]: at Strategy.parseErrorResponse (/app/node_modules/passport-facebook/lib/strategy.js:198:12)
2019-08-20T20:04:52.264456+00:00 app[web.1]: at Strategy.OAuth2Strategy._createOAuthError (/app/node_modules/passport-oauth2/lib/strategy.js:405:16)
2019-08-20T20:04:52.264460+00:00 app[web.1]: at /app/node_modules/passport-oauth2/lib/strategy.js:175:45
2019-08-20T20:04:52.264462+00:00 app[web.1]: at /app/node_modules/oauth/lib/oauth2.js:191:18
2019-08-20T20:04:52.264465+00:00 app[web.1]: at passBackControl (/app/node_modules/oauth/lib/oauth2.js:132:9)
2019-08-20T20:04:52.264466+00:00 app[web.1]: at IncomingMessage.<anonymous> (/app/node_modules/oauth/lib/oauth2.js:157:7)
2019-08-20T20:04:52.264469+00:00 app[web.1]: at IncomingMessage.emit (events.js:203:15)
2019-08-20T20:04:52.264470+00:00 app[web.1]: at endReadableNT (_stream_readable.js:1145:12)
2019-08-20T20:04:52.264472+00:00 app[web.1]: at process._tickCallback (internal/process/next_tick.js:63:19)

推荐答案

使用 passport-twitter-token 代替包含Twitter身份验证策略的Passport-twitter库,但是该库不适合用于RESTful API.它更适合用于某些服务器渲染的Express.js应用程序 使用Twitter策略初始化Passport的代码如下:

use passport-twitter-token instead of passport-twitter library that contains a strategy for Twitter authentication, but this library is not suitable for RESTful API. It is better suited for Express.js applications which are used with some server rendering The code for initialization of Passport with Twitter strategy looks like this:

'use strict';

var passport = require('passport'),
  TwitterTokenStrategy = require('passport-twitter-token'),
  User = require('mongoose').model('User');

module.exports = function () {

  passport.use(new TwitterTokenStrategy({
      consumerKey: 'KEY',
      consumerSecret: 'SECRET',
      includeEmail: true
    },
    function (token, tokenSecret, profile, done) {
      User.upsertTwitterUser(token, tokenSecret, profile, 
function(err, user) {
        return done(err, user);
      });
    }));

};

我在此处使用了该解决方案 https://www.soccermass.com 您可以阅读有关该解决方案的更多信息此处 https://medium.com/@robince885/如何通过反应和宁静的api-e525f30c62bb进行推特身份验证

I used the solution here https://www.soccermass.com you can read more on the solution here https://medium.com/@robince885/how-to-do-twitter-authentication-with-react-and-restful-api-e525f30c62bb

这篇关于部署到生产后的Passport.js TokenError的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆