大多数应用开发过程中,您可能需要通过大量的工作来解决身份验证和授权两大问题,如构建和维护多台服务器。Cloud DB安全规则,可以为您简化向用户授权和验证请求的工作,让您可以专注于构建良好的用户体验,无需管理基础架构或编写服务端身份验证和授权代码。
安全规则以简单明了的格式提供访问控制和数据验证,您可以将云数据、安全规则和认证服务结合使用,构筑基于用户和角色的访问控制来确保数据安全,帮助您的产品取得成功。
您可基于AppGallery Connect控制台管理安全规则。安全规则发布之后,规则界面会按时间顺序排列当前应用的所有安全规则,您可查看任意版本安全规则,同时也可基于最新版本编写新的安全规则。
格式 | 意义 |
---|---|
粗体 | 命令行关键字(命令中保持不变、必须照输的部分)采用加粗字体表示。 |
斜体 | 命令行参数(命令中必须由实际值进行替代的部分)采用斜体表示。 |
[ ] | 表示用“[ ]”括起来的部分在命令配置时是可选的。 |
… | 表示前面的元素可重复出现。 |
{ x / y / … } [ ,… ] | 表示可选多个参数,至少选一个,如果选择多个参数,则参数之间用逗号分隔。 |
您可通过AppGallery Connect控制台编写或修改安全规则。Cloud DB使用match表达式和allow表达式来实现安全规则编写,match表达式用于识别数据在Cloud DB中的数据结构路径,allow表达式用于控制用户对该路径下数据的操作权限。
AppGallery Connect控制台提供规则测试平台,供您快速测试Cloud DB安全规则。
当安全规则满足要求后,发布安全规则。安全规则发布成功后,应用的请求必须要满足安全规则,才能访问相关数据。
每个应用发布的安全规则的版本应小于等于20个,若您的安全规则已经达到20个限额,请先删除历史版本,然后才能发布新的安全规则。
说明:
安全规则列表中显示“”,为当前生效的安全规则。
您可以删除历史版本的安全规则。若删除的安全规则为当前生效安全规则时,表示禁用安全规则,需等待下次重新发布安全规则之后,端侧请求才走安全规则校验逻辑。
登录AppGallery Connect网站,选择“我的项目”。
在项目列表页面中选择项目,单击项目下需要删除安全规则的应用。
在导航树上选择“构建 > 云数据库”,进入云数据库页面。
选择“规则>修改规则”页签,单击“修改规则”,进入安全规则修改页面。
单击弹出框中的“确定”,删除当前指定的安全规则。
您可以可通过AppGallery Connect控制台监控安全规则校验结果。
您可以根据自己的需求设置安全规则,授予应用用户对Cloud DB中数据的访问和管理权限。Cloud DB使用match表达式和allow表达式来实现安全规则编写,match表达式用于识别数据在Cloud DB中的数据结构路径,allow表达式用于控制用户对该路径下数据的操作权限。安全规则并非过滤条件,不允许编写一个针对数据库中所有数据执行的查询操作,却期望仅返回当前客户端有权限访问的数据。
match表达式,用于识别数据在Cloud DB中的数据结构路径,其语法格式需满足match: { },语法格式如下。
match: /databases/clouddbzone_name/objecttype/objecttype_name/key/key_value
match表达式可以指向特定的数据,也可以使用变量或通配符指向特定路径结构下的任意数据。
指向特定数据时,该数据的主键只能为唯一主键。
使用变量或通配符指向特定路径下的任意数据。
// 安全规则声明
clouddb_securityrules[
// 匹配存储区zone1下的对象类型Student中主键值为alice的数据
match: /databases/zone1/objecttype/Student/key/alice{
allow write: if true;
}
// 若Student为复合主键,包含id和name,匹配Student中主键值为id = 1,name = alice的数据
match: /databases/zone1/objecttype/Student/key/{key}{
allow write: if key.id == 1 && key.name == "alice";
}
// 匹配任意存储区下的任意对象类型中主键为任意值的数据
match: /databases/{database}/objecttype/{objecttype}/key/{key} {
allow read, write: if true;
}
// 使用通配符匹配任意存储区下的任意对象类型中主键为任意值的数据
match: /databases/{database=**} {
allow read, write: if true;
}
]
当设置安全规则后,只能访问安全规则明确允许访问和操作的数据,拒绝对其它路径下数据的访问和操作。
// 全部允许
clouddb_securityrules[
match: /databases/{clouddbzone=**} {
allow read, write: if true;
}
]
// 全部拒绝
clouddb_securityrules[
match: /databases/{clouddbzone=**} {
allow read, write: if false;
}
]
当某一层级下存在多个子层级,且需要配置不同的安全规则权限时,可以使用分层match来共用父层级,内层match语句的层级结构始终是相对于共用外层match语句路径的各个子层级路径,且外层match不允许以“/”结尾,内层match必须以“/”开头。使用嵌套match语句时,不允许任何一层match路径为空或非法。
clouddb_securityrules[
match: /databases/{clouddbzone} {
match: /objecttype/Student/key/{key} {
allow read, write: if ;
}
match: /objecttype/Teacher/key/{key} {
allow read, write: if ;
}
}
]
allow表达式,用于设置在满足指定的条件下用户拥有该路径下数据的操作权限。系统会根据设置的安全规则,对客户端发起的每个请求进行评估,然后决定是否允许其读取、写入或删除数据。其语法格式如下。
allow {method1|method2|...}[,...][: if condition];
clouddb_securityrules[
match: /databases/{database}/objecttype/{objecttype}/key/{key}{
allow list: if false;
allow create,update: if true;
allow delete: if false;
}
]
利用get()和exists()函数,安全规则可以针对数据库中其它数据评估传入请求。get()和exists()函数需要指定完整的数据路径, 其参数为一个字符串。使用变量为get()和exists()构建路径时,需要使用字符串拼接,其变量值会在执行权限校验的时候注入,若根据参数所指向的路径找不到数据或者参数所指向的路径非法,则权限校验失败。
get()和exists()函数仅适用于对象类型中主键为单一主键的场景,不适用于对象类型主键为复合主键的场景。
clouddb_securityrules[
match: /databases/{clouddbzone}/objecttype/Student/key/{key} {
allow create: if request.auth != null && exists('/databases/' + clouddbzone + '/objecttype/Teacher/key/' + request.auth.uid);
allow delete: if request.auth != null && get('/databases/' + clouddbzone + '/objecttype/user/key/' + request.auth.uid).data.roleType == "admin";
}
]
随着安全规则变得越来越复杂,您可能需要将条件封装在函数中,以便在规则集中重复使用。安全规则支持自定义函数,自定义函数的语法类似于Java Script,但自定义安全规则函数需要遵循以下限制:
clouddb_securityrules[
match: /databases/{clouddbzone}/objecttype/Student/key/{key} {
allow create: if signedInOrPublic();
allow delete: if signedInOrPublic();
}
]
function signedInOrPublic() {
return request.auth.uid != null || resource.data.visibility == "public";
}
安全规则通过indexOf关键字实现提供判断个例是否在集合中,例如可用于判断Array中包含某对象或String中包含某子串。根据其返回结果是否为-1判断是否存在,-1表示不存在,其它值表示存在。
clouddb_securityrules[
match: /databases/{clouddbzone}/objecttype/Student/key/{key} {
allow create, delete: if isOneOfRoles(resource, ["owner"]);
}
]
function isSignedIn() {
return request.auth.uid != null;
}
function getRole(rsc) {
// Read from the "roles" map in the resource (rsc).
return rsc.data.roles[request.auth.uid];
}
function isOneOfRoles(rsc, array) {
// Determine if the user is one of an array of roles
return isSignedIn() && array.indexOf(getRole(rsc)) > -1;
}
allow read, write: if request.auth != null;
allow read, write: if true;
allow read, write: if false;
支持的运算符如下所示。
表1 运算符表
运算符类型:基本的运算符
运算符名称 | 运算符符号 |
---|---|
加号 | + |
减号 | - |
除号 | * |
求余 | / |
运算符类型:条件判断运算符
运算符名称 | 运算符符号 |
---|---|
大于 | > |
大于等于 | >= |
小于 | < |
小于等于 | <= |
等于 | == |
恒等于 | === |
不等于 | != |
运算符类型:逻辑运算符
运算符名称 | 运算符符号 |
---|---|
逻辑与 | && |
逻辑或 | // |
逻辑非 | ! |
Cloud DB安全规则通过匹配确切路径或者通配符路径,用于确定被授权的用户可以访问哪些路径下的数据,从而实现对您数据的保护。
如果您要将规则应用于任意深度(受限于路径结构的总长度)的层次结构,请使用通配符语法{path=**}。
clouddb_securityrules[
match: /databases/{clouddbzone=**} {
allow read, write: if true;
}
]
clouddb_securityrules[
match: /databases/{database}/objecttype/Student/key/{key} {
allow read, write: if false;
}
// 因第二个match始终为true,则系统允许所有读写操作,即便第一个match始终为false
match: /databases/{database=**} {
allow read, write: if true;
}
]
clouddb_securityrules[
match: /databases/{database}/objecttype/Student/key/{key} {
// 因第二个规则始终为true,则系统允许Student下的所有写操作,即便第一个规则始终为false
allow update: if false;
allow write: if true;
}
]
// 安全规则声明
clouddb_securityrules[
// 匹配存储区zone1下Student表中主键值为alice的特定数据,此场景主键必须为唯一主键
match: /databases/zone1/objecttype/Student/key/alice{
allow read, write: if true;
}
]
当应用用户向Cloud DB发出请求时,系统会校验用户身份,校验通过后,会使用用户的uid填充request.auth.uid变量,以此获得访问权限。而未通过身份验证的用户发出请求时,request.auth变量为null,无法访问数据。因此,您可以通过以下几种常用方法保障数据安全:
对于一些公开数据,可以不通过身份验证进行呈现。因此配置安全规则时,您可以忽略配置request.auth的相关规则,数据权限会默认数据为公开可访问。
clouddb_securityrules[
match: /databases/{database}/objecttype/{objecttype}/key/{key} {
allow read, write: if true;
}
]
在某些情况下,如果您仅希望某些用户可查看数据,则您可通过身份验证进行控制权限。由于未通过身份验证的用户的request.auth变量为 null,无法访问数据。因此配置安全规则时,通过检查用户的request.auth变量是否为null即可。
clouddb_securityrules[
match: /databases/{database}/objecttype/{objecttype}/key/{key} {
allow read, write: if request.auth != null;
}
]
对于隐私文件,为了保证个人用户对其拥有控制权,在配置安全规则时,可通过在数据中包含一个用户唯一的识别信息(例如用户的uid),表结构中存在creator字段。将数据的访问权限设置为用户私有即可。
clouddb_securityrules[
match: /databases/{database}/objecttype/{objecttype}/key/{key} {
allow read, write: if request.auth.uid == resource.data.creator;
}
]
您也根据数据字段值动态地允许或拒绝访问。例如数据存在visibility字段时,可以限定其值为“public”时才允许更新,但是,如果字段为全程加密字段,那么在测试安全规则时,您所能访问到的resource中该字段值恒为null。
clouddb_securityrules[
match: /databases/{database}/objecttype/{objecttype}/key/{key} {
allow update: if resource.data.visiblity == "public";
}
]
request和resource对象可以帮助安全规则获取更多的请求上下文,从而进行更合适的控制。
属性 | 类型 | 说明 |
---|---|---|
request.auth | JSONObject | 用户登录信息。 |
request.auth.uid | 字符串 | 用户登录验证通过后的唯一ID。 |
request.auth.token | JSONObject | 用户认证信息。 |
request.auth.token.sub | 字符串 | 用户登录验证通过后的唯一ID。 |
request.auth.token.name | 字符串 | 用户名称。 |
request.auth.token.email | 字符串 | 用户电子邮箱地址。 |
request.auth.token.phone | 字符串 | 用户电话号码。 |
request.auth.token.email_verified | 布尔值 | 用户电子邮箱是否验证。 |
request.auth.token.agc | JSONObject | 用户登录认证服务。 |
request.auth.token.agc.sign_in_provider | 整数 | 用户登录供应方数字。请请考AGConnectAuthCredential。 |
request.resource.data | JSONObject | 请求数据,与resource对象的结构相同,仅当执行create、update请求时存在。 |
属性 | 类型 | 说明 |
---|---|---|
resource.data | JSONObject | 源数据,对应表结构对象,由 |
您可以通过本节了解Cloud DB安全规则当前存在的限制,我们后续将会尽可能减少使用Cloud DB安全规则的限制。
表1 规则集和函数限制
限制 | 最大值 |
---|---|
单规则集大小 | 64KB |
单个数据调用exists()、get()的最大次数 | 10 |
批量数据、事务的调用exists()、get()的最大次数 | 20,说明:单个数据调用exists()、get()的最大次数,同样适用于批量操作中的每个单步操作。 |
函数调用深度 | 20 |
函数参数的数量上限 | 7 |
递归或循环函数调用次数上限 | 0(不允许) |
每个请求中评估的表达式数量上限 | 500 |