【问题标题】:Developing Azure functions locally在本地开发 Azure 功能
【发布时间】:2018-08-31 10:34:06
【问题描述】:

我正在领导一个由 azure 函数开发人员组成的大型团队。因此,Microsoft 引用的大多数使用 azure Web 界面的示例都不适合我。我正在使用模拟器在本地开发 Azure 功能以节省一些成本。我通过 Visual Studio 将我的所有功能发布到我的集成环境中。

我正在开发一堆需要 api 网关来处理使用 Azure AD B2C 的身份验证工作流的 azure 函数。现在,没有可以在本地运行的 api 网关模拟器或 Azure AD B2C 模拟器。我的身份验证工作流包括拦截对 api 的请求,将它们重定向到 AD B2C 进行身份验证,然后将 auth-token 添加到 http 标头,然后调用 http 触发的 azure 函数。

现在,问题变成了,如何测试身份验证工作流程? 如何设置 api 网关以将我在 Visual Studio 中本地运行的函数注册为我在云端的 api 网关的 api 端点?

【问题讨论】:

  • 目前,我们不支持在本地测试身份验证。向功能应用程序添加Easy Auth 支持正在跟踪器here。使用 AAD 凭据添加对本地开发的支持是路线图的一部分,但目前还没有 ETA。
  • 我正在尝试构建一个可扩展的开放世界互联网平台。我不想为安全构建自己的 OAuth 框架和拦截机制。我想使用 API 网关,这样我就可以限制 API 吞吐量。如果网关可以处理身份验证,那么我不必为了安全而设置一堆其他集成。当您开始使用 api 网关等服务时,Azure bizspark 积分会很快用完。我正在努力寻找一个好的模型来促进本地开发,而不是为了让我的开发人员高效工作而将自己扭曲成一个椒盐脆饼。

标签: azure azure-functions restful-authentication azure-ad-b2c azure-api-management


【解决方案1】:

如果您正在通过Easy Auth 开发使用 Azure-AD 或 Azure B2C 的 SPA,这是另一种选择,它将为您进行 JWT 令牌验证并让您执行以下操作:

您的 SPA 甚至会在本地获得令牌,因此请执行以下操作:

  1. ClaimPrincipal 注入您的函数中
  2. 检查用户是否经过身份验证(例如,principal.Identity.IsAuthenticated),如果没有则返回 UnauthorizedResult。
  3. 检查颁发者声明。如果委托人有一个,它会通过 Express Auth.,您的 JWT 令牌已通过它验证,您可以立即从中获取您的声明。
  4. 如果没有颁发者,则为本地开发,您可以转到标头并自己提取 JWT 令牌并获取您的声明。您也可以 IFDEF 将其用于条件构建,以便您更加确定它是本地开发。

以下是一些将 JWT 令牌从标头中提取出来的示例代码(HttpRequest 被注入到每个函数中):

private JwtSecurityToken ReadJwtTokenFromHeader(HttpRequest req)
{
   if (req.Headers.ContainsKey("Authorization"))
   {
       var authHeader = req.Headers["Authorization"];
       var headerValue = AuthenticationHeaderValue.Parse(authHeader);

       var handler = new JwtSecurityTokenHandler();
       return handler.ReadJwtToken(headerValue.Parameter);
   }

   return null;
}

注意:这需要 System.IdentityModel.Tokens.Jwt NuGet 包才能使用 JwtSecurityTokenHandler。

【讨论】:

  • 在我的开发环境中,我将 IsAuthenticated 设为 true,但没有 AuthorizationHeader。我怎样才能得到这个标题?
  • @RohanKulkarni,您的客户应发送“授权:承载...”标头
【解决方案2】:

接受@David-Yates 的回答,我在本地运行时替换了校长

module Debug = begin

    open System.IdentityModel.Tokens.Jwt
    open System.Net.Http.Headers
    open System.Security.Claims

    let setPrincipalFromBearerToken (log : ILogger) (req : HttpRequest) =
        log.LogInformation ("Reading Authorization header")
        let success, authHeader = req.Headers.TryGetValue("Authorization")
        if not success
        then log.LogWarning ("Authorization header missing")
        else
        match Seq.tryExactlyOne authHeader with
        | None -> log.LogWarning ("Authorization header has 0 or more than 1 value")
        | Some headerValue ->
            let headerValue = AuthenticationHeaderValue.Parse(headerValue);
            log.LogInformation ("Authorization header succesfully parsed")

            let handler = new JwtSecurityTokenHandler();
            let token = handler.ReadJwtToken(headerValue.Parameter);
            log.LogInformation ("JWT succesfully parsed")
            let identity =
                ClaimsIdentity(
                    req.HttpContext.User.Identity,
                    token.Claims)//,
                    //Microsoft.AspNetCore.Authentication.JwtBearer.JwtBearerDefaults.AuthenticationScheme),
                    //"oid", "roles")
            let principal = ClaimsPrincipal(identity)
            req.HttpContext.User <- principal
            let userIdClaim =
                principal.Claims
                |> Seq.where (fun c -> c.Type = "oid") // TODO: Use const from MS package if possible
                |> Seq.head
            log.LogInformation ("Principal succesfully updated, user ID '{0}'", userIdClaim.Value)
end

let isLocal = String.IsNullOrEmpty(Environment.GetEnvironmentVariable("WEBSITE_INSTANCE_ID"))
if isLocal then Debug.setPrincipalFromBearerToken log req

【讨论】:

  • 顺便说一句,我尝试从 Azure 门户上的函数中获取 MSI_TOKEN 并将其放入 .NET 5 函数中的 localsettings.json 文件中,现在它通过 Azure 完美地向 KeyVault 进行身份验证广告
【解决方案3】:

我做了什么:

  1. 添加了一个“授权”API,用于处理针对外国当局的通用授权。此 API 返回我自己的 JWT 以及我自己的自定义声明,该声明会持续一段时间。
  2. 更改了我的所有其他 API 以使用我的自定义 JWT。

优点:

  • 本地测试超级容易。我只是将#if DEBUG 部分添加到授权 API 以跳过正常授权并为我提供我设计的 JWT。
  • 我可以在声明中添加任何我想要的内容,因此我将其用作缓存以减少外部授权调用。

【讨论】:

    猜你喜欢
    • 2019-03-26
    • 2016-08-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多