暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

AGC安全规则是如何简化用户授权和验证请求

Gauss松鼠会 2022-06-02
285

概述

大多数应用开发过程中,您可能需要通过大量的工作来解决身份验证和授权两大问题,如构建和维护多台服务器。Cloud DB安全规则,可以为您简化向用户授权和验证请求的工作,让您可以专注于构建良好的用户体验,无需管理基础架构或编写服务端身份验证和授权代码。

安全规则以简单明了的格式提供访问控制和数据验证,您可以将云数据、安全规则和认证服务结合使用,构筑基于用户和角色的访问控制来确保数据安全,帮助您的产品取得成功。

  • 身份验证

    在构建应用时,您经常需要确认用户的真实身份,Cloud DB安全规则为您提供了一种简单易用且安全的身份验证机制,只需要简单的代码,就可以帮助您轻松实现验证用户身份的有效性、真实性。通过身份验证的用户,可以获得数据资源访问的权限。而未通过身份验证的用户,则会被限制对数据资源的访问。

  • 授权

    安全规则以简单明了的格式,允许您通过授权的方式,控制用户对特定路径下数据的访问。通过身份验证的用户,需要获得对指定资源的授权以后,才能实现对Cloud DB中特定路径下数据的访问和操作。

使用入门

您可基于AppGallery Connect控制台管理安全规则。安全规则发布之后,规则界面会按时间顺序排列当前应用的所有安全规则,您可查看任意版本安全规则,同时也可基于最新版本编写新的安全规则。

格式约定

格式意义
粗体命令行关键字(命令中保持不变、必须照输的部分)采用加粗字体表示。
斜体命令行参数(命令中必须由实际值进行替代的部分)采用斜体表示。
[ ]表示用“[ ]”括起来的部分在命令配置时是可选的。
表示前面的元素可重复出现。
{ x / y / … } [ ,… ]表示可选多个参数,至少选一个,如果选择多个参数,则参数之间用逗号分隔。

编写或修改安全规则

您可通过AppGallery Connect控制台编写或修改安全规则。Cloud DB使用match表达式和allow表达式来实现安全规则编写,match表达式用于识别数据在Cloud DB中的数据结构路径,allow表达式用于控制用户对该路径下数据的操作权限。

注意事项

  • 仅支持在基于最新版本的安全规则进行编写或修改新的安全规则,其他历史版本仅允许查看不允许修改。
  • 由于Cloud DB端侧仅提供批量查询接口,安全规则不提供对单个数据读取权限的控制。
  • 在编写的安全规则时,对于Long类型的数据仅支持使用 ‘==’ 两个等于来判断数据内容是否相等。

操作步骤

  • 登录AppGallery Connect网站,选择“我的项目”。
  • 在项目列表页面中选择项目,单击项目下需要编写或者修改安全规则的应用。
  • 在导航树上选择“构建 > 云数据库”,进入云数据库页面。
  • 选择“规则”页签,单击“修改规则”进入安全规则修改页面。
  • 根据需要执行以下操作:
  • 编写新的安全规则
  • 在规则编辑框编辑新的安全规则。
  • 修改已有的安全规则
  • 选择左侧安全规则列表中第一个安全规则进行编辑。说明:

  • 编写安全规则的语法,请参见设计安全规则。
  • 编写安全规则时,控制台会自动对您的安全规则进行语法校验,不合法的语句在将会在界面高亮显示。

测试安全规则

AppGallery Connect控制台提供规则测试平台,供您快速测试Cloud DB安全规则。

操作步骤

  1. 登录AppGallery Connect网站,选择“我的项目”。
  2. 在项目列表页面中选择项目,单击项目下需要测试安全规则的应用。
  3. 在导航树上选择“构建 > 云数据库”,进入云数据库页面。
  4. 选择“规则”页签,单击“修改规则”,进入安全规则修改页面。
  5. 单击右侧“规则测试平台”,模拟测试安全规则。
  6. 选择模拟类型。
    1. list:批量读取数据。
    2. create:写入单条数据。
    3. update:更新已有单条数据。
    4. delete:删除单条数据。
  7. 填入数据存储的位置路径。

    位置路径必须为完整的实际路径,不允许使用变量和通配符。
    当模拟类型为“list”时,路径仅允许指定到key层,无需指定主键值。
    当对象类型为复合主键时,key层的值是所有<key,value>键值对的JSONString值,例如当主键包含id和name两个字段时,key层应该写入{“id”:1,“name”:“alice”}。

  8. (可选)当模拟类型为“create”和“update”时,单击“构造数据”,可以构造单条数据进行模拟测试。

    说明

    构建数据时,最多可输入128个字段值。

    构建数据的字段名和数据类型可填写已创建对象类型包含的所有字段和数据类型。

  9. (可选)选择是否需要通过身份认证。
    开启身份认证时,需手动填入如下信息进行模拟。
    • UID:用户ID,对应在两个字段中:request.auth.uid, request.auth.token.sub。
    • 供应方:用户登录认证服务的供应方,其中可选15种认证服务的供应方。对应字段:request.auth.token.agc.sign_in_provider。
    • 电子邮件地址:用户的电子邮箱地址。对应字段:request.auth.token.email。
    • 已验证电子邮件地址:用户的电子邮箱是否验证。对应字段:request.auth.token.email_verified。
      • true:已验证。
      • false:未验证。
      • null:未填写。
    • 用户名称:用户名称。对应字段:request.auth.token.name。

    • 电话号码:用户电话号码。对应字段:request.auth.token.phone。

    • 身份认证有效负载:无需填写,根据已填写的身份认证信息自动生成。即request.auth字段中的内容。
      说明:
      开启身份认证后,UID与供应方为必填选项,其他选填,不填写默认对应字段为空。

  10. “运行”。

  • 运行成功,页面提示安全规则运行通过,表示安全规则允许模拟的操作。


  • 运行失败,页面提示ERROR,表示安全规则拒绝模拟的操作。

发布安全规则

当安全规则满足要求后,发布安全规则。安全规则发布成功后,应用的请求必须要满足安全规则,才能访问相关数据。

注意事项

每个应用发布的安全规则的版本应小于等于20个,若您的安全规则已经达到20个限额,请先删除历史版本,然后才能发布新的安全规则。

操作步骤

  1. 登录AppGallery Connect网站,选择“我的项目”。
  2. 在项目列表页面中选择项目,单击项目下需要发布安全规则的应用。
  3. 在导航树上选择“构建 > 云数据库”,进入云数据库页面。
  4. 选择“规则”页签,单击“修改规则”,进入安全规则修改页面。
  5. 单击“发布”,发布满足要求的安全规则。

说明:
安全规则列表中显示“”,为当前生效的安全规则。

删除安全规则

您可以删除历史版本的安全规则。若删除的安全规则为当前生效安全规则时,表示禁用安全规则,需等待下次重新发布安全规则之后,端侧请求才走安全规则校验逻辑。

操作步骤

  1. 单击弹出框中的“确定”,删除当前指定的安全规则登录AppGallery Connect网站,选择“我的项目”。
  2. 在项目列表页面中选择项目,单击项目下需要删除安全规则的应用。
  3. 在导航树上选择“构建 > 云数据库”,进入云数据库页面。
  4. 选择“规则>修改规则”页签,单击“修改规则”,进入安全规则修改页面。
  5. 选择左侧列表中要删除的安全规则,单击“删除”。


  6. 单击弹出框中的“确定”,删除当前指定的安全规则。

监控安全规则

您可以可通过AppGallery Connect控制台监控安全规则校验结果。

操作步骤

  1. 登录AppGallery Connect网站,选择“我的项目”。
  2. 在项目列表页面中选择项目,单击项目下需要查看监控规则的应用。
  3. 在导航树上选择“构建 > 云数据库”,进入云数据库页面。
  4. 选择“规则>监控规则”页签,进入“监控规则”页面,查看监控规则情况。
  5. 页面展示当前应用下安全规则的允许总次数、拒绝总次数、错误总次数。您可以在页面右上角选择需要查看数据的时间段(过去60分钟、过去24小时、过去7天以及过去30天)。单击图表左上侧的允许总次数、拒绝总次数或者错误总次数,可以选择需要在图表中展示的数据。
    • 允许总次数:通过安全规则校验(返回结果为True)的次数。
    • 拒绝总次数:未通过安全规则校验(返回结果为False)的次数。
    • 错误总次数:在校验安全规则时,安全规则未能正常执行完成(返回结果不是True和False)的次数,错误结果的最终表现是不通过。

设计安全规则

您可以根据自己的需求设置安全规则,授予应用用户对Cloud DB中数据的访问和管理权限。Cloud DB使用match表达式和allow表达式来实现安全规则编写,match表达式用于识别数据在Cloud DB中的数据结构路径,allow表达式用于控制用户对该路径下数据的操作权限。安全规则并非过滤条件,不允许编写一个针对数据库中所有数据执行的查询操作,却期望仅返回当前客户端有权限访问的数据。

注意事项

  • 安全规则必须以“clouddb_securityrules”声明开头。
  • “list”操作是对数据的批量访问,allow语句中存在list方法时,match语句中key层只能为变量或者通配符,且allow语句的条件中,不允许使用该变量,该变量值恒为空。同时条件中也不允许使用系统变量resource。
  • 如果有多个allow语句或者match语句与某个请求匹配,则只要任何一个条件为true,就允许操作。
  • 安全规则内容包含在“[]”中。
  • 如果需要注释时,注释内容限定为常用字符。
    • 注释为单行时,以“//”开头。
    • 注释为多行时,以“/* */”包含。
  • 构建安全规则时,涉及的数据类型和运算符,具体请参见数据类型和运算符。

match表达式

match表达式,用于识别数据在Cloud DB中的数据结构路径,其语法格式需满足match: { },语法格式如下。

match: /databases/clouddbzone_name/objecttype/objecttype_name/key/key_value
  • clouddbzone_name:存储区名称。
  • objecttype_name:对象类型名称。
  • key_value:键值。
    说明:
  • 主键值可以为变量、通配符及特定值。
  • databases、objecttype和key各层级不允许为空。

      match表达式可以指向特定的数据,也可以使用变量或通配符指向特定路径结构下的任意数据。

      • 指向特定数据时,该数据的主键只能为唯一主键。
        • 若主键为复合主键,则match语句中只能使用变量进行匹配。
        • 若需要实现对特定数据进行控制,可在allow语句的if条件中对主键的值进行限定。

          例如,假设uid为Student表复合主键中的一个,则if条件可设置为: key.uid == ‘alice’;其中key为match语句中key层的变量{key}。

      • 使用变量或通配符指向特定路径下的任意数据。
        • 变量格式为{param},表示此层可以匹配任意值,其中param可以在allow语句的条件和自定义函数中使用,使用时无需带括号,其值为所匹配路径对应该层的值。
        • 通配符格式为{param=**},表示从此层开始,后续层次路径可省略,也可在allow语句的条件和自定义函数中使用,但其值为路径,而非单层匹配的值。

          规则示例:

          // 安全规则声明
          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 <condition1>;
                  }
                  match: /objecttype/Teacher/key/{key} {
                      allow read, write: if <condition2>;
                  }
              }
          ]
          

      allow表达式

      allow表达式,用于设置在满足指定的条件下用户拥有该路径下数据的操作权限。系统会根据设置的安全规则,对客户端发起的每个请求进行评估,然后决定是否允许其读取、写入或删除数据。其语法格式如下。

      allow {method1|method2|...}[,...][: if condition];
      

      • method1:规则类型,为list、create、update和delete。
      • condition:枚举值,true和false。
      • allow表达式提供了read规则和write规则两种规则,用于实现对数据执行不同的操作判定条件。
      • read规则
        • list:对数据的批量访问。
      • write规则
        • create:写入单条数据。
        • update:更新已有单条数据。
        • delete:删除单条数据。

      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,但自定义安全规则函数需要遵循以下限制:

      • 函数只能包含一个return语句,不能包含额外的逻辑,无法执行循环或调用外部服务。
      • 函数可以自动访问系统函数和变量。例如,在clouddb_securityrules范围内定义的函数可以访问resource变量以及get()和exists()等内置函数。
      • 函数可以调用其它函数,调用堆栈总深度不得超过20,不能递归。
      • 函数参数的数量不得超过7个。
      • 调用函数时必须携带括号,不支持直接使用函数名调用函数。
      • 自定义函数是用function关键字定义的,可以接受零个或零个以上的参数。例如,您可将登录用户和数据对外可见两种条件组合成一个函数:

      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;
      }

      数据类型

      • null
        当一个值不存在时,使用null标识。
        allow read, write: if request.auth != null;
        
      • bool
        -布尔类型,包含true和false两个值。
        allow read, write: if true; 
        allow read, write: if false;
        

      运算符

      支持的运算符如下所示。

      表1 运算符表
      运算符类型:基本的运算符

      运算符名称运算符符号
      加号+
      减号-
      除号*
      求余/

      运算符类型:条件判断运算符

      运算符名称运算符符号
      大于>
      大于等于>=
      小于<
      小于等于<=
      等于==
      恒等于===
      不等于!=

      运算符类型:逻辑运算符

      运算符名称运算符符号
      逻辑与&&
      逻辑或//
      逻辑非!

      编写数据安全规则条件

      Cloud DB安全规则通过匹配确切路径或者通配符路径,用于确定被授权的用户可以访问哪些路径下的数据,从而实现对您数据的保护。

      通配符匹配

      如果您要将规则应用于任意深度(受限于路径结构的总长度)的层次结构,请使用通配符语法{path=**}。

      clouddb_securityrules[
          match: /databases/{clouddbzone=**} {
              allow read, write:  if true;
          }
      ]
      

      重叠语句匹配

      • 某个数据可以与多个match语句匹配,如果有多个match表达式与某个请求匹配,则只要任意一个条件为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;
            }
        ]
        
      • 某个数据与一个match内多个allow匹配,如果有多个allow表达式与某个请求匹配,则只要任何一个条件为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对象中属性的完整列表如下:
      属性类型说明
      request.authJSONObject用户登录信息。
      request.auth.uid字符串用户登录验证通过后的唯一ID。
      request.auth.tokenJSONObject用户认证信息。
      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.agcJSONObject用户登录认证服务。
      request.auth.token.agc.sign_in_provider整数用户登录供应方数字。请请考AGConnectAuthCredential。
      request.resource.dataJSONObject请求数据,与resource对象的结构相同,仅当执行create、update请求时存在。
      • resource对象中属性的完整列表如下:
      属性类型说明
      resource.dataJSONObject源数据,对应表结构对象,由<key, value>组成的一个JSON结构。仅当执行delete、update请求时存在。

      安全规则限制

      您可以通过本节了解Cloud DB安全规则当前存在的限制,我们后续将会尽可能减少使用Cloud DB安全规则的限制。

      表1 规则集和函数限制

      限制最大值
      单规则集大小64KB
      单个数据调用exists()、get()的最大次数10
      批量数据、事务的调用exists()、get()的最大次数20,说明:单个数据调用exists()、get()的最大次数,同样适用于批量操作中的每个单步操作。
      函数调用深度20
      函数参数的数量上限7
      递归或循环函数调用次数上限0(不允许)
      每个请求中评估的表达式数量上限500






        「喜欢这篇文章,您的关注和赞赏是给作者最好的鼓励」
        关注作者
        【版权声明】本文为墨天轮用户原创内容,转载时必须标注文章的来源(墨天轮),文章链接,文章作者等基本信息,否则作者和墨天轮有权追究责任。如果您发现墨天轮中有涉嫌抄袭或者侵权的内容,欢迎发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

        评论