【发布时间】:2019-02-11 14:08:26
【问题描述】:
我有一个自定义令牌,其中包含 appid 有效负载,用于识别第三方应用。
我想验证对我的数据的读取/写入,以便:
- 用户已登录(有一个有效的uid/令牌)
-
appid 已在
/apps集合中注册 - uid 和 appid 是记录中的字段并与凭据匹配
- (与此问题无关,但要完整)此记录与文档的架构匹配。
当前最佳解决方案和剩余问题
我最终偶然发现的这个答案相当不错,但可能会有所改进。
我要做的第一件事是正确识别我在自定义令牌中提供的有效负载——因为我使用云服务功能来生成有效负载 (graphcool),我的有效负载是 default: { appid } 而不仅仅是 @ 987654323@。从那里开始,只需对权限进行一些改写就足以使用我想象的当前规则成功验证:
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 if 链)——就像使用数组一样也许直接在规则中?
-
如何确保负载中指定的 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 控制台的 Authentication -> Users 选项卡中看到了新的非匿名用户:
— 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/{auto-generated}
注释:
将要注册的应用程序数量很少——从财务角度来看,如果可能的话,将其设置为权限文件中的静态数组可能是有意义的,而不是 get 请求。
重大改进 - 我刚刚注意到
request.auth.token.appid应该是request.auth.token.default.appid因为我使用的是export default而不是modules.export
【问题讨论】:
标签: firebase firebase-authentication google-cloud-firestore firebase-security