【问题标题】:Jawbone API OAuth access_token handling with node.js (express & passport)使用 node.js 处理 Jawbone API OAuth access_token(快递和护照)
【发布时间】:2015-10-01 23:04:54
【问题描述】:

有没有人为他们的 REST API 成功导航 Jawbone's OAuth2.0 authentication

我无法弄清楚如何访问和发送authorization_code 以获得access_tokenJawbone API Authorization Documentation 中的步骤 4 和 5)。我想将access_token 重用于后续(AJAX 样式)调用,并避免每次都要求用户重新授权。

API (get.sleeps) 的每次调用都需要完整的身份验证过程往返行程,包括此重新授权以获得authorization_token(屏幕截图)。 Jawbone 和Passport 文档在这一点上都含糊其辞。

我的堆栈涉及node.jsjawbone-up NPMexpress.jspassport.js。当我取回有效数据时,Jawbone 的 Passport Strategy 似乎工作正常。

jawbone-up NPM 明确无助于维护会话 (access_token),表示“此库无法帮助通过 OAuth 获取 access_token...”

问题:我如何在 API 调用中实际使用 OAUTH access_token?有人可以给我看一些代码吗?

谢谢

var dotenv = require('dotenv').load(),
    express = require('express'),
    app = express(),
    ejs = require('ejs'),
    https = require('https'),
    fs = require('fs'),
    bodyParser = require('body-parser'),
    passport = require('passport'),
    JawboneStrategy = require('passport-oauth').OAuth2Strategy,
    port = 5000,
    jawboneAuth = {
       clientID: process.env.JAWBONE_CLIENT_ID,
       clientSecret: process.env.JAWBONE_CLIENT_SECRET,
       authorizationURL: process.env.JAWBONE_AUTH_URL,
       tokenURL: process.env.JAWBONE_AUTH_TOKEN_URL,
       callbackURL: process.env.JAWBONE_CALLBACK_URL 
    },
    sslOptions = {
        key: fs.readFileSync('./server.key'),
        cert: fs.readFileSync('./server.crt')
    };
    app.use(bodyParser.json());
    app.use(express.static(__dirname + '/public'));
    app.set('view engine', 'ejs');
    app.set('views', __dirname + '/views');

// ----- Passport set up ----- //
app.use(passport.initialize());

app.get('/', 
    passport.authorize('jawbone', {
        scope: ['basic_read','sleep_read'],
        failureRedirect: '/'
    })
);

app.get('/done',
    passport.authorize('jawbone', {
        scope: ['basic_read','sleep_read'],
        failureRedirect: '/'
    }), function(req, res) {
        res.render('userdata', req.account);
    }
);

passport.use('jawbone', new JawboneStrategy({
    clientID: jawboneAuth.clientID,
    clientSecret: jawboneAuth.clientSecret,
    authorizationURL: jawboneAuth.authorizationURL,
    tokenURL: jawboneAuth.tokenURL,
    callbackURL: jawboneAuth.callbackURL
}, function(token, refreshToken, profile, done) {
    var options = {
            access_token: token,
            client_id: jawboneAuth.clientID,
            client_secret: jawboneAuth.clientSecret
        },
        up = require('jawbone-up')(options);

    up.sleeps.get({}, function(err, body) {
        if (err) {
            console.log('Error receiving Jawbone UP data');
        } else {
        var jawboneData = JSON.parse(body).data;
        console.log(jawboneData);
        return done(null, jawboneData, console.log('Jawbone UP data ready to be displayed.'));
        }
    });
}));
// HTTPS
var secureServer = https.createServer(sslOptions, app).listen(port, function(){
    console.log('UP server listening on ' + port);
});

【问题讨论】:

    标签: javascript node.js oauth passport.js jawbone


    【解决方案1】:

    你离得不远了,你已经拿到了令牌。要使您的代码正常工作,需要几个步骤:

    添加“会话”的概念,即从请求到请求存在的数据作为全局变量。当你做一个完整的网络应用程序时,使用 express-sessions 和 passport-sessions 并实施用户管理。但现在我们只是为单个用户状态添加一个全局变量。

    var demoSession = {
        accessToken: '',
        refreshToken: ''
    };
    

    在 JawboneStrategy 的 done() 中传入一个用户对象。这是因为护照的“授权”功能期望用户存在于会话中。它将授权结果附加到该用户。由于我们只是在测试 API,只需传入一个空用户即可。

    // Setup the passport jawbone authorization strategy
    passport.use('jawbone', new JawboneStrategy({
        clientID: jawboneAuth.clientID,
        clientSecret: jawboneAuth.clientSecret,
        authorizationURL: jawboneAuth.authorizationURL,
        tokenURL: jawboneAuth.tokenURL,
        callbackURL: jawboneAuth.callbackURL
    }, function(accessToken, refreshToken, profile, done) {
        // we got the access token, store it in our temp session
        demoSession.accessToken = accessToken;
        demoSession.refreshToken = refreshToken;
        var user = {}; // <-- need empty user
        done(null, user);
        console.dir(demoSession);
    }));
    

    使用特殊页面显示数据“/data”。添加路由,将 auth 与 service 的显示分开。

    app.get('/done', passport.authorize('jawbone', {
            scope: ['basic_read','sleep_read'],
            failureRedirect: '/'
        }), function(req, res) {
            res.redirect('/data');
        }
    );
    

    最后,Jawbone Up sleeps API 有点棘手。您必须在请求中添加一个 YYYYMMDD 字符串:

    app.get('/data', function(req, res) {
    
        var options = {
            access_token: demoSession.accessToken,
            client_id: jawboneAuth.clientID,
            client_secret: jawboneAuth.clientSecret
        };
        var up = require('jawbone-up')(options);
    
        // we need to add date or sleep call fails
        var yyyymmdd = (new Date()).toISOString().slice(0, 10).replace(/-/g, "");
        console.log('Getting sleep for day ' + yyyymmdd);
    
        up.sleeps.get({date:yyyymmdd}, function(err, body) {
            if (err) {
                console.log('Error receiving Jawbone UP data');
            } else {
                try {
                    var result = JSON.parse(body);
                    console.log(result);
                    res.render('userdata', {
                        requestTime: result.meta.time,
                        jawboneData: JSON.stringify(result.data)
                    });
                }
                catch(err) {
                    res.render('userdata', {
                        requestTime: 0,
                        jawboneData: 'Unknown result'
                    });
                }
    
            }
        });
    });
    

    我根据您的代码创建了一个适合我的要点:https://gist.github.com/longplay/65056061b68f730f1421

    【讨论】:

      【解决方案2】:

      Jawbone 访问令牌将在 1 年后过期,因此您绝对不需要每次都重新验证用户身份。此外,您还获得了refresh_token,因此您可以在需要时刷新访问令牌。

      获得access_token 后,您必须将其存储在某个地方,最好是存储在某种数据库或文件存储中以供以后使用,然后您可以将该令牌用于向 Jawbone REST API 发出的每个请求。

      jawbone-up 模块在内部使用request,因此我将向您展示如何使用它发出请求(它应该与任何其他模块几乎相同)。

      以下是获取用户个人资料的方法(最基本的 API 调用):

      var request = require('request')
      request.get({
        uri:'https://jawbone.com/nudge/api/v.1.1/users/@me',
        auth:{bearer:'[ACCESS_TOKEN]'},
        json:true
      }, function (err, res, body) {
        // body is a parsed JSON object containing the response data
      })
      

      还有另一个名为Purest 的模块也在内部使用request,但隐藏了使用REST API 的一些复杂性。以下是使用该模块的相同请求的外观:

      var Purest = require('purest')
      var jawbone = new Purest({provider:'jawbone'})
      jawbone.get('users/@me', {
        auth:{bearer:'[ACCESS_TOKEN]'}
      }, function (err, res, body) {
        // body is a parsed JSON object containing the response data
      })
      

      或者,为了验证用户身份(获取access_token),您可以使用我个人使用的另一个名为Grant 的模块,但任何一个都可以工作。

      【讨论】:

      • Simo,我以前没有接触过这些模块,但会开始阅读。您是否有任何示例代码来处理过期的access_token?这可能是我自己的经验不足,但我发现 Passportjs 和 Jawbone 文档非常无用......
      • 使用请求request.post({uri:'https://jawbone.com/auth/oauth2/token', form:{grant_type:'refresh_token',refresh_token:'..',client_id:'..',client_secret:'..'}}, function(e,r,b){}) :)
      • Simo,我感觉很糟糕,因为这是一个很好的答案,但我无法让格兰特工作。我一直陷入“invalid_redirect”错误。不过,我可能会就此发布另一个问题 - 如果我可以让它工作,它是一个非常干净和优雅的模块。
      • 没问题,我很高兴你觉得这个解决方案很优雅。如果您仍然对它感兴趣,我可能忘记将您指向有关它的文章here。慢慢来,您的 OAuth 应用程序的重定向配置、Grant 的 server.host 配置和您启动流程的主机应该匹配 - 这就是您遇到的错误。
      • 我在这里创建了一个新问题,显示我的配置混乱 - stackoverflow.com/questions/31504030/…
      猜你喜欢
      • 2019-08-07
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-03-02
      • 1970-01-01
      • 2013-05-07
      • 2015-10-12
      • 1970-01-01
      相关资源
      最近更新 更多