我无法让Firebase存储使用自定义规则并使用自定义声明。
在我的Python管理面板中,我执行以下操作来创建用户并分配声明client_id:
# Standard Auth
import firebase_admin
from firebase_admin import db, storage, auth
cred = firebase_admin.credentials.Certificate('path_to_cert_json')
app = firebase_admin.initialize_app(cred, 'config')
bucket = storage.bucket(app=app)
# Create User
auth.create_user(email=email)
# Create custom claims
auth.set_custom_user_claims(uid, {'client_id': client_id})
然后,对于Firebase规则,我尝试允许用户仅在文件位于具有client_id的子文件夹中时读取(或下载)文件:
存储上的文件结构:
/{environment}/{client_id}/other_folders_and_files
我设置了以下存储规则:
service firebase.storage {
match /b/{bucket}/o {
match /{environment}/{client_id}/{allPaths=**} {
allow read: if request.auth.token.client_id == client_id
}
}
}
但这给了我一个错误,即权限被拒绝。
我究竟做错了什么?
注意:
如果我没错,你就错了。应该:
service firebase.storage {
match /b/{bucket}/o {
match /{environment}/{client_id}/{allPaths=**} {
allow read: if request.auth.uid == client_id
}
}
}
令牌返回其他对象,例如:
因此,您可以比较用户ID,您必须使用request.auth.uid
。这种方式将比较客户端客户端ID。如果你想看看docs,那就是request.auth
的一切。
如果您需要自己的自定义令牌,例如:request.auth.token.client_id
,您需要在Python中使用此代码执行此操作:
uid = 'some-uid'
additional_claims = {
'client_id': your_custom_client_id
}
custom_token = auth.create_custom_token(uid, additional_claims)
然后您可以在存储规则中使用:
service firebase.storage {
match /b/{bucket}/o {
match /{environment}/{client_id}/{allPaths=**} {
allow read: if request.auth.token.client_id == client_id
}
}
}
见docs
自定义声明是目前唯一的方法。规则应如下所示:
service firebase.storage {
match /b/{bucket}/o {
function isAuth() {
return request.auth != null && request.auth.uid != null
}
function isAdmin() {
return isAuth() &&
request.auth.token.admin == true;
}
function clientMatch(clientId) { // expects user's "client" field to be ID of client
return isAuth() &&
clientId == request.auth.token.clientId;
}
match /storage/path/{clientId}/{allPaths=**} {
allow read, write: if isAdmin() || clientMatch(clientId)
}
我们在身份验证令牌上使用两个自定义字段:admin
和clientId
。与db同步的云功能可能如下所示:
exports.updateUser = functions.firestore
.document('users/{userId}')
.onWrite( async (change, context) => {
// change.before and change.after are DocumentSnapshot objects
const userid=context.params.userId // (from {userId} above)
const isDeleted = !change.after.exists
const isNew = !change.before.exists
let customClaims = {}
if (!isDeleted) {
let newData = change.after.data()
let oldData = change.before.data()
// do we need to update anything?
if (isNew ||
newData.admin !== oldData.admin ||
newData.client !== oldData.client) {
customClaims.admin = Boolean(newData.admin)
customClaims.clientId = newData.client
}
}
else {
let oldData = change.before.data()
customClaims.admin = false
customClaims.clientId = null
}
// now do the update if needed
if (customClaims !== {}) {
// See https://firebase.google.com/docs/reference/admin/node/admin.auth.Auth
await admin.auth().setCustomUserClaims(userid, customClaims)
console.log(`Updating client for ${isNew?"new":"existing"} user ${userid}: ` +
`${JSON.stringify(customClaims)}`)
}
})
这可以对用户文档进行任何更改,并将其同步到身份验证自定义声明。