У меня есть собственный токен, который содержит полезную нагрузку appid для идентификации сторонних приложений.
Я хотел бы проверить чтение / запись в мои данные таким образом, чтобы:
- пользователь вошел в систему (есть действительный uid / токен)
- appid зарегистрирован в коллекции
/apps
- uid и appid являются полями в записи и соответствуют учетным данным
- (не связано с этим вопросом, но будет завершено) эта запись соответствует схеме для документа.
текущее лучшее решение и оставшиеся вопросы
Этот ответ, на который я в конце концов наткнулся, довольно хорошо , но это может быть улучшено.
Первое, что мне нужно было сделать, это правильно определить полезную нагрузку, которую я давал в пользовательском токене - потому что я использую функцию облачного сервиса для генерации полезной нагрузки (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
}
}
}
Кто-то мог бы сделать лучше.
есть ли способ проверить appid без использования существующего запроса (и без записи цепочки if-else, если ) - например, с помощью массива непосредственно в правилах?
как я могу убедиться, что 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