разрешения запроса для пользовательского токена - PullRequest
0 голосов
/ 11 февраля 2019

У меня есть собственный токен, который содержит полезную нагрузку appid для идентификации сторонних приложений.

Я хотел бы проверить чтение / запись в мои данные таким образом, чтобы:

  1. пользователь вошел в систему (есть действительный uid / токен)
  2. appid зарегистрирован в коллекции /apps
  3. uid и appid являются полями в записи и соответствуют учетным данным
  4. (не связано с этим вопросом, но будет завершено) эта запись соответствует схеме для документа.

текущее лучшее решение и оставшиеся вопросы

Этот ответ, на который я в конце концов наткнулся, довольно хорошо , но это может быть улучшено.

Первое, что мне нужно было сделать, это правильно определить полезную нагрузку, которую я давал в пользовательском токене - потому что я использую функцию облачного сервиса для генерации полезной нагрузки (graphcool),моя полезная нагрузка была default: { appid } вместо appid.С этого момента достаточно просто переписать разрешения, чтобы успешно проверить их с использованием существующих правил, которые я себе представлял:

service cloud.firestore {
  match /databases/{database}/documents {

    match /sampleData/{type}/{appName}/{record} {
      allow read: if isSignedIn() && isValidApp(database) && ownsExisting() && appIdInExisting()
      allow write: if isSignedIn() && isValidApp(database) && ownsPayload() && appIdInPayload()
    }

    // functions
    function isSignedIn () {
        return request.auth != null
    }

    function isValidApp (database) {
        return exists(/databases/$(database)/documents/apps/$(request.auth.token.appid))
    }

    function ownsExisting () {
        return resource.data.uid == request.auth.uid
    }

    function ownsPayload () {
        return request.resource.data.uid == request.auth.uid
    }

    function appIdInExisting () {
        return resource.data.app_id == request.auth.token.appid
    }

    function appIdInPayload () {
        return request.resource.data.app_id == request.auth.token.appid
    }
  }
}

Кто-то мог бы сделать лучше.

  1. есть ли способ проверить appid без использования существующего запроса (и без записи цепочки if-else, если ) - например, с помощью массива непосредственно в правилах?

  2. как я могу убедиться, что appid , указанный в полезной нагрузке, соответствует тому, который я предполагал, когда я выдал учетные данные службы клиентскому стороннему приложению?

редактировать: оригинальный вопрос

Я думал, что смогу получить хотя бы первые два:

service cloud.firestore {
  match /databases/{database}/documents {

    match /sampleData {
      allow read: if isSignedIn() && isValidApp() && ownsExisting() && appIdInExisting()
      allow write: if isSignedIn() && isValidApp() && ownsPayload() && appIdInPayload()
    }

    // functions
    function isSignedIn () {
        return request.auth != null
    }

    function isValidApp () {
        return get(path('apps')).data.child(request.auth.token.appid).exists()
    }

    function ownsExisting () {
        return resource.data.uid == request.auth.uid
    }

    function ownsPayload () {
        return request.resource.data.uid == request.auth.uid
    }

    function appIdInExisting () {
        return resource.data.app_id == request.auth.token.appid
    }

    function appIdInPayload () {
        return request.resource.data.app_id == request.auth.token.appid
    }
  }
}

/apps имеет 1 документ под названием "sample-app-id "с id и name полями" sample-app-id "... но использование этого в моем токене не работает: FirebaseError: Missing or insufficient permissions

Я генерирую токен с помощью этой функции на моем сервере:

var FirebaseAdmin = require('firebase-admin')
var serviceAccount = require('./firebase-service-credentials.json')
var claims = require('./custom-token-claims') // {appid: 'sample-app-id'}

let credential = FirebaseAdmin.credential.cert(serviceAccount)
FirebaseAdmin.initializeApp({ credential })

const generateTokenWithPayload = async id => {
  try {
    const token = await FirebaseAdmin.auth().createCustomToken(id, claims)

    return { data: { token } }
  } catch (err) {
    return { error }
  }
}

module.exports = async event =>
  await generateTokenWithPayload(event.data.userIdentifier)

и перед публикацией я подписываюсьв - эта часть, которую я могу проверить, кажется, работает, поскольку я вижу нового неанонимного пользователя в моей вкладке Аутентификация -> Пользователи в консоли Firebase:

— Feb 11, 2019 Feb 11, 2019 smaple-user-id

Вотпо сути, код клиента:

await firebase
      .auth()
      .signInWithCustomToken(token)
      .catch(console.error)
const db = await firebase.firestore()
db.collection(path + this.state.appName).add(payload) 

Я публикую запись со схемой {app_id, app_name, date, metric, uid} в sampleData / metrics / sample-app-name / {автоматически сгенерированный}

примечания:

  • количество приложений, которые будут зарегистрированы, невелико - с финансовой точки зрения, возможно, имеет смысл сделать этот статический массив в разрешениях.файл, если это возможно, вместо get запроса.

  • большое улучшение - я только что заметил, что request.auth.token.appid должно быть request.auth.token.default.appid, потому что я использовалexport default вместо modules.export

1 Ответ

0 голосов
/ 11 февраля 2019

Этот ответ довольно хорошо , но его можно улучшить.

Первое, что мне нужно было сделать, это правильно определить полезную нагрузку, которую я давал в пользовательском токене - потому что яЯ использую функцию облачного сервиса для генерации полезной нагрузки (graphcool), моя полезная нагрузка была default: { appid } вместо appid.С этого момента достаточно просто переписать разрешения, чтобы успешно проверить их с использованием существующих правил, которые я себе представлял:

service cloud.firestore {
  match /databases/{database}/documents {

    match /sampleData/{type}/{appName}/{record} {
      allow read: if isSignedIn() && isValidApp(database) && ownsExisting() && appIdInExisting()
      allow write: if isSignedIn() && isValidApp(database) && ownsPayload() && appIdInPayload()
    }

    // functions
    function isSignedIn () {
        return request.auth != null
    }

    function isValidApp (database) {
        return exists(/databases/$(database)/documents/apps/$(request.auth.token.appid))
    }

    function ownsExisting () {
        return resource.data.uid == request.auth.uid
    }

    function ownsPayload () {
        return request.resource.data.uid == request.auth.uid
    }

    function appIdInExisting () {
        return resource.data.app_id == request.auth.token.appid
    }

    function appIdInPayload () {
        return request.resource.data.app_id == request.auth.token.appid
    }
  }
}

Кто-то мог бы сделать лучше.

  1. есть ли способ проверить appid без использования существующего запроса (и без записи цепочки if-else, если ) - например, с помощью массива непосредственно в правилах?

  2. как я могу убедиться, что appid , указанный в полезной нагрузке, совпадает с тем, который я предполагал, когда я выдал учетные данные службы клиентскому стороннему приложению?

...