2013-03-23 37 views
8

为我的应用创建了一个配置文件页面后,我想显示该用户所在的社交服务列表。它让我感到最简单的方法就是使用Meteor的内置账户系统。如何将外部服务登录添加到Meteor中已有的帐户?

有没有一种很好的方式将外部服务添加到现有帐户?

此外,用户是否可以使用他的密码从我的应用程序(例如)Facebook 登录?

另一个自然会出现的问题:是否有一种很好的方法可以将特定于应用程序的密码添加到使用外部服务创建的帐户中?

+0

我在学习,你能做到它喜欢它的答案,或者您自己的方式解释真实? – jptsetung 2013-05-19 13:53:55

+0

[使用流星帐户包链接多个服务]可能的重复(http://stackoverflow.com/questions/18358007/using-meteor-accounts-package-to-link-multiple-services) – BenjaminRH 2013-09-02 15:28:52

回答

1

是的,一个用户帐户可以与多个服务相关联,并且同时具有基于密码的登录。在Meteor docs,你可以看到这样的用户帐户的结构:

{ 
    _id: "bbca5d6a-2156-41c4-89da-0329e8c99a4f", // Meteor.userId() 
    username: "cool_kid_13", // unique name 
    emails: [ 
    // each email address can only belong to one user. 
    { address: "[email protected]", verified: true }, 
    { address: "[email protected]", verified: false } 
    ], 
    createdAt: 1349761684042, 
    profile: { 
    // The profile is writable by the user by default. 
    name: "Joe Schmoe" 
    }, 
    services: { 
    facebook: { 
     id: "709050", // facebook id 
     accessToken: "AAACCgdX7G2...AbV9AZDZD" 
    }, 
    resume: { 
     loginTokens: [ 
     { token: "97e8c205-c7e4-47c9-9bea-8e2ccc0694cd", 
      when: 1349761684048 } 
     ] 
    } 
    } 
} 

如果在添加用户名/密码登录到现有的帐户,您可以在服务器端使用Accounts.sendResetPasswordEmail。这也确保更改发生认证和授权。

当然,您也可以自己更新服务器端的用户记录并使用新密码,但这可能会在您的应用程序中创建一个安全漏洞。如果可能的话,我也建议不要实施你自己的加密协议,如it is hard

如果你想比电子邮件添加其他服务,例如,您可以

  1. 调用,将当前用户的MongoDB的文档中的任意,长令牌,并将其返回到客户端服务器的方法。
  2. 使用Accounts.loginWith[OtherService]将用户重新登录到其他服务。这将使用户在另一服务上使用新帐户登录并重新登录。
  3. 使用第一个方法返回的标记作为参数调用第二个服务器方法。第二种方法搜索具有给定令牌的用户帐户,并将其数据合并到当前(新)帐户中。
+0

是的,但你怎么样添加多个服务? – Swadq 2013-03-24 15:59:10

+0

我编辑了答案。它现在回答你的问题吗? :) – opyh 2013-03-24 23:11:55

+0

开始。绝对看起来像一个可怕的黑客,它应该被内置到流星虽然。如果我有任何的快乐,我会明天给你一个答案,并接受你的答案 – Swadq 2013-03-24 23:28:54

3

这是我如何添加凭据现有用户帐户:.../meteor-how-to-login-with-github-account.html

+0

尽管这可能在理论上回答这个问题,但[这将是更可取的](http://meta.stackoverflow.com/q/8259)在这里包含了答案的基本部分,并提供了供参考的链接。 – 2015-08-08 09:41:03

7

这里是一个替代方法。在这个解决方案中,我重写了一个核心函数并添加了一些自定义行为。我的目标是将服务数据与当前登录的用户相关联,然后让核心功能像正常一样完成它的工作。

orig_updateOrCreateUserFromExternalService = Accounts.updateOrCreateUserFromExternalService; 
Accounts.updateOrCreateUserFromExternalService = function(serviceName, serviceData, options) { 
    var loggedInUser = Meteor.user(); 
    if(loggedInUser && typeof(loggedInUser.services[serviceName]) === "undefined") { 
    var setAttr = {}; 
    setAttr["services." + serviceName] = serviceData; 
    Meteor.users.update(loggedInUser._id, {$set: setAttr}); 
    } 
    return orig_updateOrCreateUserFromExternalService.apply(this, arguments); 
} 

优点:

  • 避免产生不必要的账户
  • 代码很短,很容易理解
  • 代码很容易,如果这个功能被添加到流星核心删除

缺点:

  • 要求用户登录。如果用户最初使用twitter登录,注销,然后用facebook登录,则会创建两个独立的帐户。
  • 共享计算机的用户可能会无意中合并他们的帐户。
  • 依赖updateOrCreateUserFromExternalService如何工作的知识。这并不可怕 - 因为它是流星公共API的一部分,它可能不会发生大幅度的变化(通常不会)。但它仍然有风险。
+0

这看起来像我可以找到的最佳答案,但我无法使其工作。我将它添加到服务器上运行,包括accounts-password和accounts-facebook。然后我用密码登录,调用Meteor.loginWithFacebook(),并向Meteor().user()添加一个空的服务对象。它还在服务器控制台中记录一个错误,该错误说:调用方法'login'时发生异常错误:只能在方法调用中调用Meteor.userId。在发布函数中使用this.userId。 – fnsjdnfksjdb 2014-02-03 05:46:06

0

查看本示例中的示例并回答。它几乎为您提供了集成多个外部和内部帐户的代码。只需稍作调整,您可以根据需要为每个帐户添加密码字段。

How to use Meteor.loginWithGoogle with mrt:accounts-ui-bootstrap-dropdown

代码:

isProdEnv = function() { 
    if (process.env.ROOT_URL == "http://localhost:3000") { 
     return false; 
    } else { 
     return true; 
    } 
} 

Accounts.loginServiceConfiguration.remove({ 
    service: 'google' 
}); 

Accounts.loginServiceConfiguration.remove({ 
    service: 'facebook' 
}); 

Accounts.loginServiceConfiguration.remove({ 
    service: 'twitter' 
}); 

Accounts.loginServiceConfiguration.remove({ 
    service: 'github' 
}); 

if (isProdEnv()) { 
    Accounts.loginServiceConfiguration.insert({ 
     service: 'github', 
     clientId: '00000', 
     secret: '00000' 
    }); 
    Accounts.loginServiceConfiguration.insert({ 
     service: 'twitter', 
     consumerKey: '00000', 
     secret: '00000' 
    }); 
    Accounts.loginServiceConfiguration.insert({ 
     service: 'google', 
     appId: '00000', 
     secret: '00000' 
    }); 
    Accounts.loginServiceConfiguration.insert({ 
     service: 'facebook', 
     appId: '00000', 
     secret: '00000' 
    }); 
} else { 
    // dev environment 
    Accounts.loginServiceConfiguration.insert({ 
     service: 'github', 
     clientId: '11111', 
     secret: '11111' 
    }); 
    Accounts.loginServiceConfiguration.insert({ 
     service: 'twitter', 
     consumerKey: '11111', 
     secret: '11111' 
    }); 
    Accounts.loginServiceConfiguration.insert({ 
     service: 'google', 
     clientId: '11111', 
     secret: '11111' 
    }); 
    Accounts.loginServiceConfiguration.insert({ 
     service: 'facebook', 
     appId: '11111', 
     secret: '11111' 
    }); 
} 

Accounts.onCreateUser(function (options, user) { 
    if (user.services) { 
     if (options.profile) { 
      user.profile = options.profile 
     } 
     var service = _.keys(user.services)[0]; 
     var email = user.services[service].email; 
     if (!email) { 
      if (user.emails) { 
       email = user.emails.address; 
      } 
     } 
     if (!email) { 
      email = options.email; 
     } 
     if (!email) { 
      // if email is not set, there is no way to link it with other accounts 
      return user; 
     } 

     // see if any existing user has this email address, otherwise create new 
     var existingUser = Meteor.users.findOne({'emails.address': email}); 
     if (!existingUser) { 
      // check for email also in other services 
      var existingGitHubUser = Meteor.users.findOne({'services.github.email': email}); 
      var existingGoogleUser = Meteor.users.findOne({'services.google.email': email}); 
      var existingTwitterUser = Meteor.users.findOne({'services.twitter.email': email}); 
      var existingFacebookUser = Meteor.users.findOne({'services.facebook.email': email}); 
      var doesntExist = !existingGitHubUser && !existingGoogleUser && !existingTwitterUser && !existingFacebookUser; 
      if (doesntExist) { 
       // return the user as it came, because there he doesn't exist in the DB yet 
       return user; 
      } else { 
       existingUser = existingGitHubUser || existingGoogleUser || existingTwitterUser || existingFacebookUser; 
       if (existingUser) { 
        if (user.emails) { 
         // user is signing in by email, we need to set it to the existing user 
         existingUser.emails = user.emails; 
        } 
       } 
      } 
     } 

     // precaution, these will exist from accounts-password if used 
     if (!existingUser.services) { 
      existingUser.services = { resume: { loginTokens: [] }}; 
     } 

     // copy accross new service info 
     existingUser.services[service] = user.services[service]; 
     existingUser.services.resume.loginTokens.push(
      user.services.resume.loginTokens[0] 
     ); 

     // even worse hackery 
     Meteor.users.remove({_id: existingUser._id}); // remove existing record 
     return existingUser;     // record is re-inserted 
    } 
}); 
相关问题