如何使用Azure身份验证在Azure功能中获取当前用户身份?

时间:2017-06-16 10:36:04

标签: c# azure azure-active-directory azure-functions azure-authentication

我创建了一个新的功能应用程序,为其启用了应用服务身份验证/授权(“使用身份验证/授权来保护您的应用程序并使用每用户数据”)并禁用未经身份验证的请求。

到目前为止,一切似乎都正常。如果我尝试请求我的HttpTrigger ed函数,则需要我先登录;一旦我登录,所有请求都将按原样处理。所以“保护你的应用程序”部分没有问题。

但是,我完全坚持“使用每用户数据”部分。我的Azure函数被调用为

public static async Task<HttpResponseMessage> Run([HttpTrigger(AuthorizationLevel.Anonymous, "get", "post", Route = null)]HttpRequestMessage req, TraceWriter log)

HttpRequestMessage中与身份验证无关。 (AuthorizationLevel.Anonymous似乎控制了完全不同的东西 - 即,如果该函数可以被任何人调用,或者只能由具有固定API密钥的人调用。)

如何获取调用该函数的经过身份验证的用户的身份?

5 个答案:

答案 0 :(得分:2)

使用Azure Function runtime v2.0.12309,您可以从通过Run方法注入的authenticated user information实例中检索ClaimsPrincipal

public static async Task<HttpResponseMessage> Run(
    [HttpTrigger(AuthorizationLevel.Anonymous, "get", "post", Route = null)]
    HttpRequest httpRequest, 
    ILogger logger, 
    ClaimsPrincipal claimsPrincipal)
 {
            // Explores the authenticated user's claims in claimsPrincipal.
 }

答案 1 :(得分:0)

似乎可以从全局状态System.Security.Claims.ClaimsPrincipal.Current.Identity.Name获取当前用户名(当我最初发布此问题时,我不知道)。但是,目前还不清楚这是否是一种可靠或推荐的登录用户信息的方法。

示例:

using System.Net;
using System.Net.Http;
using System.Security.Claims;
using System.Threading.Tasks;
using Microsoft.Azure.WebJobs;
using Microsoft.Azure.WebJobs.Extensions.Http;
using Microsoft.Azure.WebJobs.Host;

namespace FunctionApp
{
    public static class Function1
    {
        [FunctionName("HttpTriggerCSharp")]
        public static async Task<HttpResponseMessage> Run([HttpTrigger(AuthorizationLevel.Anonymous, "get", "post", Route = null)]HttpRequestMessage req, TraceWriter log)
        {
            return req.CreateResponse(HttpStatusCode.OK, "Hello " + ClaimsPrincipal.Current.Identity.Name);
        }
    }
}

答案 2 :(得分:0)

与App Service EasyAuth的第一级集成还没有到位,但我们正在我们的回购here中进行跟踪。我们现在正在考虑这个问题,很快就会在这方面有一些改进。

正如您所发现的,您可以启用EasyAuth,它将需要登录,并将通过经过身份验证的主体,允许您通过标准.NET API(如ClaimsPrincipal.Current等)访问它。但问题是您必须使用auth级别Anonymous标记您的方法,这不是您想要的,并且要求您在方法中拒绝未经身份验证的请求(请参阅上面提到的问题中的注释)。

我们将在即将发布的版本中尽快解决所有这些问题。

答案 3 :(得分:0)

逻辑上,AuthorizationLevel.Anonymous 不会为您提供当前的声明主体

不幸的是,只是更改为AuthorizationLevel.Function也无济于事: 对我来说,即使在通过Azure Active Directory B2C成功进行身份验证后,我发现ClaimsPrincipal.Current为null。

最后,我尝试了AuthorizationLevel.User,但azure函数目前不支持,请参阅here

我相信您需要按照this SO question上接受的答案执行相应的步骤(我现在正在尝试...)

答案 4 :(得分:0)

从我的问题复制,其目的是找到如何使用Azure Active Directory经过身份验证的用户在本地进行调试 https://stackoverflow.com/a/49402152/3602057

这适用于使用Azure功能在Azure上配置的任何提供程序,并且适用于本地调试和部署方案。

好几个小时后(OK,很多),我现在已经找到了解决方案。这适用于本地和部署方案。我在这里发布了一个模板解决方案:

https://github.com/Mike-EEE/Stash/tree/master/AzureV2Authentication/AzureV2Authentication

以下是概述整个过程的步骤:

  1. 使用https:// function-name .azurewebsites.net
  2. 登录您的功能
  3. Chrome中的CTRL-SHIFT-C - &gt;申请 - &gt; Cookies - &gt; - &GT; AppServiceAuthSession - &gt;复制值
  4. 打开local.settings.json并粘贴AuthenticationToken设置中上一步的值。
  5. 当您在那里时,请粘贴AuthenticationBaseAddress
  6. 中第一步的网址
  7. 启动应用程序。
  8. 交叉手指。
  9. 享受魔力(希望。)
  10. 这是主要事件:

    public static class AuthenticationExtensions
    {
        public static Authentication Authenticate(this HttpRequest @this)
        {
            var handler = new HttpClientHandler();
            var client = new HttpClient(handler) // Will want to make this a singleton.  Do not use in production environment.
            {
                BaseAddress = new Uri(Environment.GetEnvironmentVariable("AuthenticationBaseAddress") ?? new Uri(@this.GetDisplayUrl()).GetLeftPart(UriPartial.Authority))
            };
            handler.CookieContainer.Add(client.BaseAddress, new Cookie("AppServiceAuthSession", @this.Cookies["AppServiceAuthSession"] ?? Environment.GetEnvironmentVariable("AuthenticationToken")));
    
            var service = RestService.For<IAuthentication>(client);
    
            var result = service.GetCurrentAuthentication().Result.SingleOrDefault();
            return result;
        }
    }
    

    请注意:

    1. 为每次通话创建HttpClient。这违反了最佳做法。
    2. 示例代码基于EasyAuth sample by @stuartleeks
    3. 此解决方案利用优秀的Refit项目来获取其数据。
    4. 为了完整起见,以下是其余感兴趣的课程:

      public class Authentication // structure based on sample here: https://cgillum.tech/2016/03/07/app-service-token-store/
      {
          [JsonProperty("access_token", NullValueHandling = NullValueHandling.Ignore)]
          public string AccessToken { get; set; }
          [JsonProperty("provider_name", NullValueHandling = NullValueHandling.Ignore)]
          public string ProviderName { get; set; }
          [JsonProperty("user_id", NullValueHandling = NullValueHandling.Ignore)]
          public string UserId { get; set; }
          [JsonProperty("user_claims", NullValueHandling = NullValueHandling.Ignore)]
          public AuthenticationClaim[] UserClaims { get; set; }
          [JsonProperty("access_token_secret", NullValueHandling = NullValueHandling.Ignore)]
          public string AccessTokenSecret { get; set; }
          [JsonProperty("authentication_token", NullValueHandling = NullValueHandling.Ignore)]
          public string AuthenticationToken { get; set; }
          [JsonProperty("expires_on", NullValueHandling = NullValueHandling.Ignore)]
          public string ExpiresOn { get; set; }
          [JsonProperty("id_token", NullValueHandling = NullValueHandling.Ignore)]
          public string IdToken { get; set; }
          [JsonProperty("refresh_token", NullValueHandling = NullValueHandling.Ignore)]
          public string RefreshToken { get; set; }
      }
      public class AuthenticationClaim
      {
          [JsonProperty("typ")]
          public string Type { get; set; }
          [JsonProperty("val")]
          public string Value { get; set; }
      }
      interface IAuthentication
      {
          [Get("/.auth/me")]
          Task<Authentication[]> GetCurrentAuthentication();
      }
      public static class Function1
      {
          [FunctionName("Function1")]
          public static IActionResult Run([HttpTrigger(AuthorizationLevel.Function, "get", "post", Route = null)]HttpRequest req, TraceWriter log)
          {
              log.Info("C# HTTP trigger function processed a request.");
      
              var authentication = req.Authenticate();
      
              return authentication != null
                  ? (ActionResult)new OkObjectResult($"Hello, {authentication.UserId}")
                  : new BadRequestObjectResult("Authentication not found. :(");
          }
      }