FacebookTokenError:这个授权码已被使用

好的,所以这是很多原因的常见错误。 我正在尝试修改现有的Node-Passport-Facebook模块,让桌面上的本地图像在login后上传到用户的Facebook帐户。这是我的目标。
这是我正在扩展的代码模块
https://github.com/passport/express-4.x-local-example

而这又是基于https://github.com/jaredhanson/passport-facebook

我从来没有通过console.log('错误在这里..错误, “这个授权码已被使用。”
令人困惑的是,返回的authentication代码总是不一样! 所以当我尝试将它换成访问令牌时,它怎么能被使用呢?
任何人都可以提供一些build议,或者我可能会尝试下一步? 我的直觉是有一些关于Passport.js没有正确实施。
所以我的问题是,我将如何修改下面的代码(基于这个护照的例子) https://github.com/passport/express-4.x-facebook-example/blob/master/server.js
login后上传图片?

var express = require('express'); var passport = require('passport'); var Strategy = require('passport-facebook').Strategy; var CLIENTSECRET ='<client secret>'; var APPID ='<app id>'; // Configure the Facebook strategy for use by Passport. // // OAuth 2.0-based strategies require a `verify` function which receives the // credential (`accessToken`) for accessing the Facebook API on the user's // behalf, along with the user's profile. The function must invoke `cb` // with a user object, which will be set at `req.user` in route handlers after // authentication. passport.use(new Strategy({ clientID: APPID, clientSecret: CLIENTSECRET, callbackURL: 'http://localhost:3000/login/facebook/return', enableProof: true //callbackURL: 'http://localhost:3000/login/facebook/return' }, function(accessToken, refreshToken, profile, cb) { // In this example, the user's Facebook profile is supplied as the user // record. In a production-quality application, the Facebook profile should // be associated with a user record in the application's database, which // allows for account linking and authentication with other identity // providers. cb(null, profile); })); // Configure Passport authenticated session persistence. // // In order to restore authentication state across HTTP requests, Passport needs // to serialize users into and deserialize users out of the session. In a // production-quality application, this would typically be as simple as // supplying the user ID when serializing, and querying the user record by ID // from the database when deserializing. However, due to the fact that this // example does not have a database, the complete Twitter profile is serialized // and deserialized. passport.serializeUser(function(user, cb) { cb(null, user); }); passport.deserializeUser(function(obj, cb) { console.log(" "); console.log("ASSERT passport.deserializeUser being called"); console.log(" "); cb(null, obj); }); // Create a new Express application. var app = express(); // Configure view engine to render EJS templates. app.set('views', __dirname + '/views'); app.set('view engine', 'ejs'); // Use application-level middleware for common functionality, including // logging, parsing, and session handling. app.use(require('morgan')('combined')); app.use(require('cookie-parser')()); app.use(require('body-parser').urlencoded({ extended: true })); app.use(require('express-session')({ secret: 'keyboard cat', resave: true, saveUninitialized: true })); // Initialize Passport and restore authentication state, if any, from the // session. app.use(passport.initialize()); //app.use(passport.session()); // Define routes. app.get('/', function(req, res) { res.render('home', { user: req.user }); }); app.get('/login', function(req, res){ res.render('login'); }); app.get('/login/facebook', passport.authenticate('facebook')); app.get('/login/facebook/return', passport.authenticate('facebook', { failureRedirect: '/login' }), function(req, res) { //my code changes start here!! var code = req.query.code; console.log("1 ASSERT after successful login! code="+code); if(req.query.error) { // user might have disallowed the app return res.send('login-error ' + req.query.error_description); } else if(!code) { return res.redirect('/'); } var options={ host:'graph.facebook.com', path:'/oauth/access_token?client_id='+APPID+'&code='+code +'&client_secret='+CLIENTSECRET+'&redirect_uri=http://localhost:3000/login/faceboo k/return' } var https=require('https'); https.get(options,function(res){ res.setEncoding('utf8'); res.on('data', function (chunk) { console.log('ERROR HERE'+chunk); }); }); console.log("2 ASSERT after successful login!") //my code changes end here!! }); app.get('/profile', require('connect-ensure-login').ensureLoggedIn(), function(req, res){ res.render('profile', { user: req.user }); }); app.listen(3000); 

你根本不需要向/oauth/access_token个请求(好吧,但是护照已经为你处理了)。 该端点用于在没有访问令牌的情况下获取访问令牌,但您已经在此获得访问令牌:

 passport.use(new Strategy({ clientID: APPID, clientSecret: CLIENTSECRET, callbackURL: 'http://localhost:3000/login/facebook/return', enableProof: true //callbackURL: 'http://localhost:3000/login/facebook/return' }, function(accessToken, refreshToken, profile, cb) { // You have the access token here! cb(null, profile); })); 

您需要以某种方式保存accessToken ,以便稍后在向Graph API发出请求时使用它。 您可能想要将其保存到用户的会话中,但也可以使用如下的策略: https : //stackoverflow.com/a/24474900/772035

如果您希望用户授予发布权限(您将需要这些权限,以便能够发布到其提要),则还需要将每个呼叫都replace为passport.authenticate

 passport.authenticate('facebook', { scope: ['publish_actions'] } ); 

因此,当用户第一次添加您的应用程序时请求发布权限。 然后,您将可以使用/ user / photos端点上传照片,并将之前保存的accessToken传递给查询string。

你需要编码你的查询参数。

 var qs = { client_id: APPID, redirect_uri: 'http://localhost:3000/login/facebook/return', client_secret: CLIENTSECRET, code: code, }; options = { host:'graph.facebook.com', path:'/oauth/access_token?' + require('querystring').stringify(qs), }; 

我认为这是你的问题。 代码本身看起来很好,除此之外。 你会希望查询string模块也可以parsing结果。