新しいFunction Appを作成し、App Serviceの認証/承認を有効にしました( "認証/承認を使用してアプリケーションを保護し、ユーザーごとのデータを操作します ")および非認証リクエストを無効にします。
これまでのところ、すべてが正しく機能しているようです。 HttpTrigger
ed関数をリクエストしようとすると、最初にログインする必要があります。ログインすると、すべてのリクエストが適切に処理されます。したがって、「アプリケーションを保護する」部分に問題はありません。
ただし、「ユーザーごとのデータを操作する」という部分にはまったくこだわっています。私のAzure関数は次のように呼び出されます
public static async Task<HttpResponseMessage> Run([HttpTrigger(AuthorizationLevel.Anonymous, "get", "post", Route = null)]HttpRequestMessage req, TraceWriter log)
また、HttpRequestMessage
には認証に関連するものはありません。 (AuthorizationLevel.Anonymousは、まったく別のものを制御しているようです。つまり、関数がだれでも、または固定のAPIキーを持っている人だけが呼び出すことができる場合)。
関数を呼び出した認証済みユーザーのIDを取得するにはどうすればよいですか?
Azure関数ランタイム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.
}
グローバル状態から現在のユーザー名を取得できるようです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);
}
}
}
Azure Active Directoryで認証されたユーザーを使用してローカルでデバッグする方法を見つけることを目的としたここでの私の問題からコピーしました。
https://stackoverflow.com/a/49402152/3602057
これは、Azure Functionを使用してAzureで構成されているすべてのプロバイダーで機能し、ローカルデバッグとデプロイされたシナリオの両方で機能します。
もう数時間(OK、LOT)時間後、私は今のところ解決策を見つけました。これは、ローカルシナリオと展開シナリオの両方で機能します。ここにテンプレートソリューションを投稿しました:
https://github.com/Mike-EEE/Stash/tree/master/AzureV2Authentication/AzureV2Authentication
全体的なプロセスの概要を示す手順は次のとおりです。
function-name
.azurewebsites.netで関数にサインインします。local.settings.json
を開き、前の手順の値をAuthenticationToken
設定に貼り付けます。AuthenticationBaseAddress
の最初のステップのURLを貼り付けます主なイベントは次のとおりです。
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;
}
}
ご了承ください:
HttpClient
は呼び出しごとに作成されます。これはベストプラクティスに反します。完全を期すために、残りの興味深いクラスを次に示します。
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. :(");
}
}
論理的には、AuthorizationLevel.Anonymousは現在のクレームプリンシパルを提供しません。
残念ながら、AuthorizationLevel.Functionに変更するだけでも効果はありません。AzureActive Directory B2Cを介して正常に認証された後でも、ClaimsPrincipal.Currentがnullであることがわかりました。
最後に、AuthorizationLevel.Userを試しましたが、現在、Azure関数ではサポートされていません こちら を参照してください
私はあなたが this SO question で受け入れられた回答に従って手順を実行する必要があると信じています
App Service EasyAuthとのファーストクラスの統合はまだ整っていませんが、リポジトリで追跡しています here 。私たちはこれを現在検討しており、まもなくこの分野でいくつかの改善が見られるでしょう。
発見したとおり、EasyAuthを有効にすると、ログインが必要になり、認証されたプリンシパルがフローし、ClaimsPrincipal.Currentなどの標準.NET APIを介してアクセスできるようになります。ただし、問題は、メソッドをマークする必要があったことです。認証レベルがAnonymousであり、これは望ましいものではなく、メソッドで認証されていないリクエストを拒否する必要があります(上記の問題のメモを参照)。
これらの問題はすべて、近日中にリリースされる予定です。