在本地开发Azure功能

时间:2018-03-22 05:15:43

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

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

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

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

3 个答案:

答案 0 :(得分:7)

如果您正在开发通过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。

答案 1 :(得分:2)

在@ David-Yates的回答下,我在本地运行时替换了Principal

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

答案 2 :(得分:1)

我做了什么:

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

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