22

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

到目前为止,一切似乎都正常工作。如果我尝试请求我的HttpTriggered 功能,它需要我先登录;登录后,所有请求都会按原样处理。所以“保护您的应用程序”部分没有问题。

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

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

并且没有任何与身份验证相关的内容HttpRequestMessage。(AuthorizationLevel.Anonymous 似乎控制了完全不同的事情——即,如果该函数可以由任何人调用,或者只能由具有固定 API 密钥的人调用)。

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

4

5 回答 5

12

使用Azure Function runtime v2.0.12309,您可以从方法中注入的ClaimsPrincipal实例中检索经过身份验证的用户信息Run

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.
 }
于 2019-03-18T11:45:03.987 回答
1

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

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

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

我相信你需要按照这个 SO question的公认答案执行这些步骤(我现在正在尝试它......)

于 2018-01-13T12:58:37.700 回答
0

从我的问题here复制,旨在了解如何使用 Azure Active Directory 身份验证用户进行本地调试。
https://stackoverflow.com/a/49402152/3602057

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


好吧,又过了几个小时(好吧,很多),我现在想出了一个解决方案。这适用于本地和部署的场景。我在这里发布了一个模板解决方案:

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

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

  1. function-name在 https: //.azurewebsites.net登录您的函数
  2. Chrome 中的 CTRL-SHIFT-C -> 应用程序 -> Cookies -> -> AppServiceAuthSession -> 复制值
  3. 打开local.settings.json并粘贴上一步AuthenticationToken设置中的值。
  4. 当你在那里时,粘贴第一步中的 URLAuthenticationBaseAddress
  5. 启动程序。
  6. 十指交叉。
  7. 享受魔法(希望如此。)

这是主要事件:

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. 示例代码基于@stuartleeks 的 EasyAuth 示例
  3. 该解决方案利用优秀的Refit项目来获取其数据。

为了完整起见,以下是其余感兴趣的类别:

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. :(");
    }
}
于 2018-03-21T09:24:24.197 回答
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);
        }
    }
}
于 2017-06-16T10:57:43.637 回答
0

与 App Service EasyAuth 的一流集成尚未到位,但我们正在我们的 repo 中进行跟踪。我们现在正在研究这一点,并且可能很快就会在这方面有所改进。

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

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

于 2017-06-16T18:20:25.783 回答