6

我是 Oauth 和服务器端的新手,所以请耐心等待。

我有一个使用dropbox-js对用户进行身份验证的 Web 应用程序。一切都很简单。该应用程序使用 dropbox-js 的client.authenticate功能,如果用户通过身份验证,应用程序将自动重定向到初始页面,并在该页面执行身份验证回调。从那一刻起,我知道我很高兴通过 Dropbox 进行了身份验证,并且我可以使用应用程序的 Dropbox 目录做一些事情。

我有一个当前什么都不做的公共 node.js 服务器。我想做的是:

  • 客户端通过身份验证后,立即调用我的服务器并告诉它用户已通过身份验证
  • 如果用户在服务器数据库中不存在,请为他/她的用户数据库创建一个条目(我不需要详细说明来执行此操作)。如果存在,则发回用户的关联数据。

我怎样才能以安全的方式做到这一点?我的意思是,服务器如何判断用户是有效的 Dropbox 用户?服务器是否应该使用用户凭据对 Dropbox 进行身份验证?这些情况下的工作流程是什么?

4

1 回答 1

10

在身份验证过程结束时,您将获得一个访问令牌,用于调用 API。如果客户端和服务器都需要调用 API,那么两者都需要有访问令牌。

如果您今天在进行身份验证客户端,您可以以某种方式提取访问令牌(不确定它是否/如何从库中公开,但它在某处并存储在本地存储中)并将其传递给服务器. 然后,服务器可以使用它来调用/account/info并获取经过身份验证的用户的 Dropbox 用户 ID。

另一种方法是反过来做。使用“代码流”(而不是“令牌流”)对用户进行身份验证,并首先在服务器上获取访问令牌。然后您可以将其传递给客户端,并将其作为Dropbox.Client构造函数中的选项传递。我认为dropbox-js这本身就支持这一点,但自己做也不难。下面是一些原始的 Express 代码,用于登录用户并显示他或她的姓名:

var crypto = require('crypto'),
    express = require('express'),
    request = require('request'),
    url = require('url');

var app = express();
app.use(express.cookieParser());

// insert your app key and secret here
var appkey = '<your app key>';
var appsecret = '<your app secret>';

function generateCSRFToken() {
    return crypto.randomBytes(18).toString('base64')
        .replace(/\//g, '-').replace(/\+/g, '_');
}
function generateRedirectURI(req) {
    return url.format({
            protocol: req.protocol,
            host: req.headers.host,
            pathname: app.path() + '/callback'
    });
}

app.get('/', function (req, res) {
    var csrfToken = generateCSRFToken();
    res.cookie('csrf', csrfToken);
    res.redirect(url.format({
        protocol: 'https',
        hostname: 'www.dropbox.com',
        pathname: '1/oauth2/authorize',
        query: {
            client_id: appkey,
            response_type: 'code',
            state: csrfToken,
            redirect_uri: generateRedirectURI(req)
        }
    }));
});

app.get('/callback', function (req, res) {
    if (req.query.error) {
        return res.send('ERROR ' + req.query.error + ': ' + req.query.error_description);
    }

    // check CSRF token
    if (req.query.state !== req.cookies.csrf) {
        return res.status(401).send(
            'CSRF token mismatch, possible cross-site request forgery attempt.'
        );
    } else {
        // exchange access code for bearer token
        request.post('https://api.dropbox.com/1/oauth2/token', {
            form: {
                code: req.query.code,
                grant_type: 'authorization_code',
                redirect_uri: generateRedirectURI(req)
            },
            auth: {
                user: appkey,
                pass: appsecret
            }
        }, function (error, response, body) {
            var data = JSON.parse(body);

            if (data.error) {
                return res.send('ERROR: ' + data.error);
            }

            // extract bearer token
            var token = data.access_token;

            // use the bearer token to make API calls
            request.get('https://api.dropbox.com/1/account/info', {
                headers: { Authorization: 'Bearer ' + token }
            }, function (error, response, body) {
                res.send('Logged in successfully as ' + JSON.parse(body).display_name + '.');
            });

            // write a file
            // request.put('https://api-content.dropbox.com/1/files_put/auto/hello.txt', {
            //  body: 'Hello, World!',
            //  headers: { Authorization: 'Bearer ' + token }
            // });
        });
    }
});

app.listen(8000);
于 2013-08-01T15:18:56.223 回答