Azure Functions 的身份验证

Authentication for Azure Functions

在过去的 24 小时里,我阅读了有关如何创建 Azure Functions 的所有内容,并成功地将 MVC WebApi 转换为具有多个功能的新 Function App。我的问题是我没有找到任何关于如何使用它们进行最基本的身份验证的明确文档或教程。

我的方案非常简单。在我的 AAD 中配置用户,然后授予这些用户访问特定功能的权限。网站上的用户将单击 UI 元素,这些元素又会触发 Javascript 调用我的 Azure Functions。在函数中,我需要能够以某种方式验证它们的身份,因为我会将其传递给与 SQL 实例交互的其他函数。

有人可以指点我的文档、文章、示例等说明我如何实现这一目标的东西吗?

根据记录,我在门户中找到了我的 Function App 的 "Authentication" 配置,并选择了 AAD 作为我的身份验证提供程序。我已将我的 Function App 添加到其中并配置了一些用户。然后我编写了以下测试函数:

[FunctionName("GetThings")]
public static HttpResponseMessage Run([HttpTrigger(AuthorizationLevel.User, "GET", Route = null)]HttpRequestMessage req, TraceWriter log)
{
    log.Info("Getting all the things");
    var identity = ClaimsPrincipal.Current.Identity;

    return identity.IsAuthenticated ?
        req.CreateResponse(HttpStatusCode.Unauthorized, "Not authenticated!") :
        req.CreateResponse(HttpStatusCode.OK, $"Hi {identity.Name}!");
}

目前,当我尝试直接访问端点时,我被重定向到登录页面...所以我猜这部分工作正常。我不清楚如何生成/检索用户令牌,将它们根据请求发送给函数,或者在服务器上处理它们。

帮忙?

一旦用户通过 Azure AD 进行身份验证,您将收到一个 AppServiceAuthSessoin cookie。这是一个不透明的 cookie,但您可以通过调用

将其交换为可读的 id 令牌
https://yourFunctionApp.azurewebsites.net/.auth/me

并将不透明 cookie 作为 Cookie header 传递。此外,您取回的 id_token 可以用作 Bearer 令牌。

实际上它 对我来说很合适,我还没有真正测试过它作为 Bearer,所以要小心一点。

该机制称为 Easy Auth,Google 该名称更容易。

更多关于代币存储的信息——
https://cgillum.tech/2016/03/07/app-service-token-store/

...这表示您只需读取来自用户浏览器的 HTTP headers 即可获取声明:

Accessing the Tokens

From within your backend code, accessing these tokens is as easy as reading an HTTP request header. The headers are named like X-MS-TOKEN-{provider}-{type}. The possible token header names are listed below:

Azure Active Directory Token Request Headers:

X-MS-TOKEN-AAD-ID-TOKEN
X-MS-TOKEN-AAD-ACCESS-TOKEN
X-MS-TOKEN-AAD-EXPIRES-ON
X-MS-TOKEN-AAD-REFRESH-TOKEN

实际上我现在才发现,所以感谢您的提问!

更新:

我的预感是正确的,id_token 也可以作为 Bearer:

$ curl -isk https://{funcApp}.azurewebsites.net/api/{someFunc} \
       -H "Authorization: Bearer eyJ0eXAiOi....oEU-Q"

HTTP/1.1 200 OK
Cache-Control: no-cache
Server: Microsoft-IIS/8.0
...

两种读取声明的方式(读取 headers 与使用用户的 Cookie 从后端调用 /.auth/me)之间的主要区别在于您获得的详细信息量。后者还有更多。

这是您从 Easy Auth 获得的一组 headers Twitter 认证用户:

{
   "cookie": "AppServiceAuthSession=Lx43...xHDTA==",
   ...
   "x-ms-client-principal-name": "evilSnobu",
   "x-ms-client-principal-id": "35....",
   "x-ms-client-principal-idp": "twitter",
   "x-ms-token-twitter-access-token": "35...Dj",
   "x-ms-token-twitter-access-token-secret": "OK3...Jx",
}

以及您通过调用 /.auth/me:

获得的声明
{
   "access_token": "35...FDj",
   "access_token_secret": "OK3...sJx",
   "provider_name": "twitter",
   "user_claims": [
      {
         "typ": "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/nameidentifier",
         "val": "352660979"
      },
      {
         "typ": "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/upn",
         "val": "evilSnobu"
      },
      {
         "typ": "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name",
         "val": "Safarihat Hacker"
      },
      {
         "typ": "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/webpage",
         "val": "..."
      },
      {
         "typ": "urn:twitter:description",
         "val": "GENIUS. HAVE BRAIN. WILL TRAVEL."
      },
      {
         "typ": "urn:twitter:location",
         "val": ""
      },
      {
         "typ": "urn:twitter:time_zone",
         "val": "London"
      },
      {
         "typ": "urn:twitter:lang",
         "val": "en"
      },
      {
         "typ": "urn:twitter:verified",
         "val": "False"
      },
      {
         "typ": "urn:twitter:profile_image_url_https",
         "val": "https://pbs.twimg.com/profile_images/867473646876545024/1elebfK1_normal.jpg"
      }
   ],
   "user_id": "evilSnobu"
}

AuthorizationLevel.User 当前不受 azure 函数支持,请参阅 here

As of December 2017 this isn't fully implemented.

我为 Azure Functions v2 创建了一个小扩展, 与不记名令牌一起使用时可能会对您有所帮助。

例如,当您希望允许对应用程序的匿名请求时使用 Azure B2C。

因此您可以在 Azure Function 中获得您的 ClaimsPrincipal 权利,而无需使用任何样板文件。

[FunctionName("Example")]
public async Task<IActionResult> Run(
    [HttpTrigger(AuthorizationLevel.Function, "get", Route = null)] HttpRequest req,
    [FunctionToken] FunctionTokenResult token,
    ILogger log)
{
    log.LogInformation("C# HTTP trigger function processed a request.");
    return (ActionResult) new OkObjectResult($"Hello, {token}");
}

代码发布到Github