Ответ 1
Решено!
Я решил проблему путем обратного проектирования пакетов accounts-oauth-X
! Оптимальное решение, которое обрабатывает все крайние случаи, состоит в том, чтобы иметь одну историю для логинов, а другую для явных ассоциаций. Вот решения, написанные в грамотном coffeescript.
Перед
Убедитесь, что у вас есть необходимые пакеты:
meteor add google
meteor add facebook
meteor add oauth
Способ использования Multi-Service Login:
Это автоматически присоединяется к учетным записям, если они имеют одинаковое электронное письмо. Лучше всего использовать для входа, потому что он надежный. Однако это не хорошо для явных ассоциаций, потому что, если адреса электронной почты отличаются, то это не сработает. (И ручное слияние приведет к выходу пользователя из системы и заставит вас снова войти в систему). Чтобы явно связать учетную запись, даже если она имеет другое электронное письмо, см. Решение внизу.
Код на стороне сервера:
Accounts.onCreateUser (options, user) ->
user.city = null
user.networks = []
user.attending =[]
user.profile ?= {}
Нам нужна дополнительная логика, если пользователь зарегистрирован через службу oauth, так что мы можем стандартизировать расположение имени и электронной почты.
if user.services?
service = _.keys(user.services)[0]
Проверьте, есть ли у уже существующей учетной записи письмо, связанное с оказание услуг. Если это так, просто включите информацию о пользователе.
email = user.services[service].email
if email?
oldUser = Meteor.users.findOne({"emails.address": email})
Убедитесь, что у старой учетной записи есть необходимый объект службы.
if oldUser?
oldUser.services ?= {}
if service == "google" or service == "facebook"
Слейте новый ключ службы в нашего старого пользователя. Мы также проверяем, есть ли новые чтобы добавить к нашему пользователю. Затем удалите старого пользователя из БД и просто верните его снова, чтобы создать его снова напрямую. Предполагаемый новый пользователь, который должен был быть создан, отбрасывается.
oldUser.services[service] = user.services[service]
Meteor.users.remove(oldUser._id)
user = oldUser
В противном случае просто создайте пользователя как обычно, стандартизируя поля электронной почты и имени.
else
if service == "google" or service == "facebook"
if user.services[service].email?
user.emails = [{address: user.services[service].email, verified: true}]
else
throw new Meteor.Error(500, "#{service} account has no email attached")
user.profile.name = user.services[service].name
return user
Метод для явных ассоциаций:
Это добавляет услуги к хеш-сервису в записи пользователя, идентично, как если бы она была создана встроенной хэш-системой. Код должен быть на стороне клиента (для доступа к токену с сервисом oauth) и части сервера (для создания дополнительных вызовов API для захвата пользовательских данных и связывания их с записью пользователя).
Клиентский код:
Эта функция является точкой входа для добавления функций в нашу учетную запись.
addUserService = (service) ->
Мы должны использовать Meteor встроенную систему проверки электронной почты, если они выбирают электронную почту.
if service == "email"
else
switch service
Для стандартных служб oauth мы запрашиваем учетные данные на стороне клиента и затем передайте их на сервер, чтобы выполнить дальнейшие вызовы API, чтобы собрать необходимую информацию и добавить эту информацию в нашу учетную запись.
when "facebook"
Facebook.requestCredential(
requestPermissions: ["email", "user_friends", "manage_notifications"],
, (token) ->
Meteor.call "userAddOauthCredentials", token, Meteor.userId(), service, (err, resp) ->
if err?
Meteor.userError.throwError(err.reason)
)
when "google"
Google.requestCredential
requestPermissions: ["email", "https://www.googleapis.com/auth/calendar"]
requestOfflineToken: true,
, (token) ->
Meteor.call "userAddOauthCredentials", token, Meteor.userId(), service, (err, resp) ->
if err?
Meteor.userError.throwError(err.reason)
нам просто нужно установить простую привязку, чтобы склеить ее вместе.
Template.userAddServices.events
"click button": (e) ->
e.preventDefault()
service = $(event.target).data("service")
addUserService(service)
Код на стороне сервера:
Здесь мы определяем методы на стороне сервера, связанные с пользовательской моделью.
Meteor.methods
Это получает данные от клиента, которые захватывают токен доступа уже. Использует токен, чтобы обнаружить остальную информацию о пользователе на этой службе. Затем он проверяет, зарегистрирована ли эта учетная запись, а если нет - добавляет его в текущую учетную запись.
userAddOauthCredentials: (token, userId, service) ->
switch service
when "facebook"
data = Facebook.retrieveCredential(token).serviceData
when "google"
data = Google.retrieveCredential(token).serviceData
selector = "services.#{service}.id"
oldUser = Meteor.users.findOne({selector: data.id})
if oldUser?
throw new Meteor.Error(500, "This #{service} account has already" +
"been assigned to another user.")
updateSelector = "services.#{service}"
Meteor.users.update(userId, {$set: {updateSelector: data }})
Мы также можем проглядеть по электронной почте из этой учетной записи. Если он еще не текущий пользователь, мы можем его захватить и добавить.
if not _.contains(Meteor.user().emails, data.email)
Meteor.users.update(userId, {$push: {"emails": {address: data.email, verified: true} }})