Aspnet 核心网站 api 受 Azure 保护

Aspnet core web api protected with Azure

我的组织中有一个使用 aspnet 核心构建的网站 api。我们想要发布 api 以供 android 应用程序、mvc5 应用程序和 aspnet 核心 mvc6 应用程序使用。如何在 azure 中配置网络 api,以便使用它的应用程序不要求登录。 Web 应用程序已经受到 azure 的保护,但是当我使用 azure 保护 web api 时,我在向它发出请求时收到 401。我不知道如何在 azure 中配置应用程序或我必须在 api 中配置的代码。我读了很多书,但我找不到完成这个的方法。我只想登录我的网络应用程序,网络应用程序开始通过 ajax 向网络请求数据 api。我应该在 ajax 请求中发送某种裸令牌,但我不知道我必须在 Azure 和应用程序中进行哪些配置。我希望你能帮助我。

使用 Azure AD 保护网络 API 后,我们需要将访问令牌发送到网络请求 API 以进行授权。当用户从网络应用程序调用网络 API 时,我们可以获得访问令牌。以下是网页端获取token的代码,供大家参考:

public async Task<IActionResult> Index()
{
        AuthenticationResult result = null;
        List<TodoItem> itemList = new List<TodoItem>();

        try
        {
            string userObjectID = (User.FindFirst("http://schemas.microsoft.com/identity/claims/objectidentifier"))?.Value;
            AuthenticationContext authContext = new AuthenticationContext(Startup.Authority, new NaiveSessionCache(userObjectID, HttpContext.Session));
            ClientCredential credential = new ClientCredential(Startup.ClientId, Startup.ClientSecret);
            result = await authContext.AcquireTokenSilentAsync(Startup.TodoListResourceId, credential, new UserIdentifier(userObjectID, UserIdentifierType.UniqueId));

            //
            // Retrieve the user's To Do List.
            //
            HttpClient client = new HttpClient();
            HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Get, TodoListBaseAddress + "/api/todolist");
            request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", result.AccessToken);
            HttpResponseMessage response = await client.SendAsync(request);

            //
            // Return the To Do List in the view.
            //
            if (response.IsSuccessStatusCode)
            {
                List<Dictionary<String, String>> responseElements = new List<Dictionary<String, String>>();
                JsonSerializerSettings settings = new JsonSerializerSettings();
                String responseString = await response.Content.ReadAsStringAsync();
                responseElements = JsonConvert.DeserializeObject<List<Dictionary<String, String>>>(responseString, settings);
                foreach (Dictionary<String, String> responseElement in responseElements)
                {
                    TodoItem newItem = new TodoItem();
                    newItem.Title = responseElement["title"];
                    newItem.Owner = responseElement["owner"];
                    itemList.Add(newItem);
                }

                return View(itemList);
            }
            else
            {
                //
                // If the call failed with access denied, then drop the current access token from the cache, 
                //     and show the user an error indicating they might need to sign-in again.
                //
                if (response.StatusCode == System.Net.HttpStatusCode.Unauthorized)
                {
                    var todoTokens = authContext.TokenCache.ReadItems().Where(a => a.Resource == Startup.TodoListResourceId);
                    foreach (TokenCacheItem tci in todoTokens)
                        authContext.TokenCache.DeleteItem(tci);

                    ViewBag.ErrorMessage = "UnexpectedError";
                    TodoItem newItem = new TodoItem();
                    newItem.Title = "(No items in list)";
                    itemList.Add(newItem);
                    return View(itemList);
                }
            }
        }
        catch (Exception ee)
        {
            if (HttpContext.Request.Query["reauth"] == "True")
            {
                //
                // Send an OpenID Connect sign-in request to get a new set of tokens.
                // If the user still has a valid session with Azure AD, they will not be prompted for their credentials.
                // The OpenID Connect middleware will return to this controller after the sign-in response has been handled.
                //
                return new ChallengeResult(OpenIdConnectDefaults.AuthenticationScheme);
            }

            //
            // The user needs to re-authorize.  Show them a message to that effect.
            //
            TodoItem newItem = new TodoItem();
            newItem.Title = "(Sign-in required to view to do list.)";
            itemList.Add(newItem);
            ViewBag.ErrorMessage = "AuthorizationRequired";
            return View(itemList);
        }


        //
        // If the call failed for any other reason, show the user an error.
        //
        return View("Error");
}

下面是代码示例,它使用 JwtBearerAppBuilderExtensions 将 OpenIdConnect Bearer 身份验证功能添加到 Web 的 HTTP 应用程序管道 API 以验证令牌:

public class Startup
{
        // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
        public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
        {
            // Add the console logger.
            loggerFactory.AddConsole(LogLevel.Debug);

            // Configure the app to use Jwt Bearer Authentication
            app.UseJwtBearerAuthentication(new JwtBearerOptions
            {
                AutomaticAuthenticate = true,
                AutomaticChallenge = true,
                Authority = String.Format(Configuration["AzureAd:AadInstance"], Configuration["AzureAD:Tenant"]),
                Audience = Configuration["AzureAd:Audience"],
            });
        }
}

您可以参考完整的代码示例here

注意:为了运行这个样本成功,我们需要将TitleOwner修改为小写title, owner 在网络应用的 ToDoController:

 foreach (Dictionary<String, String> responseElement in responseElements)
 {
     TodoItem newItem = new TodoItem();
     newItem.Title = responseElement["title"];
     newItem.Owner = responseElement["owner"];
     itemList.Add(newItem);
 }

您可以使用 Azure OpenIdConnect 进行联合身份验证。下面是一篇来自微软的好文章 -

Calling a web API in a web app using Azure AD and OpenID Connect