【问题标题】:Azure API Management : validate jwt token scopeAzure API 管理:验证 jwt 令牌范围
【发布时间】:2017-11-16 07:43:14
【问题描述】:

我们想使用 validate-jwt 策略来保护 API 操作调用,但是当我使用 required-claims 检查范围时遇到了问题。 示例:我有一个令牌,其范围包括几个值,例如“xxx.READ xxx.WRITE yyy.READ yyy.WRITE ...” 对于特定操作,我想使用 validate-jwt 策略来检查令牌是否包含链接的范围,例如:

    <required-claims>
            <claim name="scp" match="any">
                <value>xxx.READ</value>
            </claim>
    </required-claims>

但是由于 scp 中的多个值,验证总是失败......我如何检查这个声明?我必须先提取 scp 值吗?如果是,我该怎么做?

提前致谢

【问题讨论】:

    标签: api oauth-2.0 jwt azure-api-management


    【解决方案1】:

    要验证 JWT 中是否存在范围,请使用设置为 "," 的 separator 属性,因为这是一个多值声明,如下所示:"scope": ["api1.write", "角色","个人资料"] .

    例如:

    <required-claims>
       <claim name="scope" match="all" separator=",">
            <value>api1.write</value>
       </claim>
    </required-claims>
    

    【讨论】:

    • 范围不是'scp'吗?
    【解决方案2】:

    我也在使用 B2C 设置 API 管理,我遇到了完全相同的问题。 我使用的解决方案更简单。

    <policies>
        <inbound>
            <base />
            <validate-jwt header-name="Authorization" failed-validation-httpcode="401" failed-validation-error-message="The Scope claim does not contain the read permission." require-expiration-time="true" require-scheme="Bearer" require-signed-tokens="true" clock-skew="0">
                <openid-config url="{{your-openid-config-url}}" />
                <required-claims>
                    <claim name="scp" match="any" separator=" ">
                        <value>read</value>
                    </claim>
                </required-claims>
            </validate-jwt>
        </inbound>
        <backend>
            <base />
        </backend>
        <outbound>
            <base />
        </outbound>
        <on-error>
            <base />
        </on-error>
    </policies>
    

    【讨论】:

      【解决方案3】:

      多值声明应在 JWT 令牌中表示为数组:

      "scp": ["xxx.READ", "xxx.WRITE", "yyy.READ", "yyy.WRITE"]
      

      您发布的策略配置完全支持这种情况。

      但是,如果您将它们表示为单个字符串(“xxx.READ xxx.WRITE yyy.READ yyy.WRITE”),那么您必须使用手动表达式来验证此类令牌,​​类似于以下内容:

      <choose>
          <when condition="@(context.Request.Headers.ContainsKey("Authorization"))">
              <set-variable name="token" value="@(context.Request.Headers.GetValueOrDefault("Authorization", string.Empty).AsJwt())" />
              <choose>
                  <when condition="@{
      if (context.Variables["token"] == null) {
          return false;
      }
      
      var scp = ((Jwt)context.Variables["token"]).Claims.GetValueOrDefault("scp", (string[])null);
      if (scp == null || scp.Length == 0) {
          return false;
      }
      
      return scp.Any(c => c.Contains("xxx.READ"));
                  }">
                      <return-response response-variable-name="existing response variable">
                          <set-status code="401" reason="Unauthorized" />
                      </return-response>
                  </when>
              </choose>
          </when>
          <otherwise>
              <return-response response-variable-name="existing response variable">
                  <set-status code="401" reason="Unauthorized" />
              </return-response>
          </otherwise>
      </choose>
      

      【讨论】:

      • 好的。是 Microsoft 的 Azure AD B2C 生成 scp,格式为我解释的“xxx.READ yyy.READ ...”
      • 哦,那不好。我会调查一下,感谢您的报告。
      • 会很棒的。我们计划在 Azure AD B2C 上使用新的“已发布范围”和“api 访问”选项,即使目前我们仍然没有链接到目标范围的页面来征求用户的同意。我尝试使用您的示例,但由于条件错误而失败。谢谢
      • 在我研究如何处理多值索赔时,您从条件中收到了什么错误?
      • 您好,感谢您的支持:trace --> select (130 ms) { "messages": [ { "message": "Expression evaluation failed.", "expression": "!(( Jwt)context.Variables[\"token\"]).Claims[\"scp\"].Any(c => c.Contains(\"randomscope.WRITE\"))", "details": "对象引用未设置为对象的实例。” }, "表达式评估失败。对象引用未设置为对象的实例。", "对象引用未设置为对象的实例。" ] }
      猜你喜欢
      • 2021-09-10
      • 1970-01-01
      • 1970-01-01
      • 2016-08-10
      • 1970-01-01
      • 2015-07-03
      • 2018-10-13
      • 2016-12-02
      • 1970-01-01
      相关资源
      最近更新 更多