簡體   English   中英

使用 Microsoft.Identity.platform 保護 api 時從自定義 Api 獲取 401

[英]Getting 401 from custom Api when using Microsoft.Identity.platform to protect api

我正在按照 Microsfot.document 中的教程學習如何使用 Azure AD (Microsoft Identity) 保護 api。

我采取的步驟如下: 抱歉,我嘗試提供可能有用的信息,但大多數時候貢獻者要求提供屏幕截圖或代碼的信息太多,無法解決問題。

我遵循了幾個文檔和視頻教程,但這是其中一個的鏈接: https://learn.microsoft.com/en-us/learn/modules/identity-secure-custom-api/2-secure-api-microsoft -身份

WebAPI。

  1. 使用核心 5 創建了一個 webapi。在 Azure AD 中注冊它。
  2. 創建單個 scope 'check' 並授予用戶和管理員權限。

Webapp 使用 .net(classic) 創建的 webapp 請注意,webapi 是核心 5。

  1. 創建了一個 webapp 並在公元 Azure 注冊了它。
  2. 設置身份驗證並創建 OnAuthorizationCodeReceived 以獲取訪問令牌以調用 api。

配置: 1.從Azure AD->Registration for Webapi->選擇application(web app created above)並給scope權限。

在此處輸入圖像描述 2.對於Azure AD->Registration for webapp->Access permission->delegate->selected the scope. 在此處輸入圖像描述

測試: 1.運行測試。 這一點; 我正在調用的 api 方法上沒有 [Authorization]。 2. Webapp 成功獲取了 api 返回的字符串。我有點覺得管道是正確的。

  1. 在 app 方法上添加了 [Authorize] 過濾器。
  2. 結果 401 未經授權。

我已經多次檢查並查看了多個教程並重寫了我的代碼,觀看了幾個視頻並更新了我的代碼但我總是遇到 401 錯誤。

下面是代碼; Api controller:

namespace Utility.Controllers
 {
   [Authorize]
    [Route("api/[controller]")]
   [ApiController]
   public class AzAdUtility : ControllerBase
     {
    // GET: api/<AzAdUtility>
    [HttpGet]
    public string Get()
    {
        //HttpContext.VerifyUserHasAnyAcceptedScope(new string[] {"check"});
        var name = "Vaqas";
        return name;
    }        
 }
}

Api 啟動:public class Startup { public Startup(IConfiguration configuration) { Configuration = configuration; }

    public IConfiguration Configuration { get; }

    // This method gets called by the runtime. Use this method to add services to the container.
    public void ConfigureServices(IServiceCollection services)
    {
        services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
        .AddMicrosoftIdentityWebApi(Configuration.GetSection("AzureAd"));   
        services.AddControllers();
        services.AddSwaggerGen(c =>
        {
            c.SwaggerDoc("v1", new OpenApiInfo { Title = "GlobalNetApiUtility", Version = "v1" });
        });
    }

    // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
    public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
    {
        if (env.IsDevelopment())
        {
            app.UseDeveloperExceptionPage();
            app.UseSwagger();
            app.UseSwaggerUI(c => c.SwaggerEndpoint("/swagger/v1/swagger.json", "Utility v1"));
        }

        app.UseHttpsRedirection();
        app.UseRouting(); 
        app.UseAuthorization();
        app.UseEndpoints(endpoints =>
        {
            endpoints.MapControllers();
        });
    }
}

Api 應用設置:

"AzureAd": {
"Instance": "https://login.microsoftonline.com/",
"Domain": "myorg.onmicrosoft.com",
"ClientId": "abcd.............................",
"TenantId": "dabcd.............................."

},

Webapp 啟動:只添加啟動頁面,因為起初我在 OnAuthorizationCodeReceived 中獲取一些用於測試目的的數據。

public class Startup
    {
        // The Client ID is used by the application to uniquely identify itself to Azure AD.
       static string clientId = System.Configuration.ConfigurationManager.AppSettings["ClientId"];

        // RedirectUri is the URL where the user will be redirected to after they sign in.
        string redirectUri = System.Configuration.ConfigurationManager.AppSettings["RedirectUri"];

        // Tenant is the tenant ID (e.g. contoso.onmicrosoft.com, or 'common' for multi-tenant)
       static string tenant = System.Configuration.ConfigurationManager.AppSettings["Tenant"];

    // Authority is the URL for authority, composed by Microsoft identity platform endpoint and the tenant name (e.g. https://login.microsoftonline.com/contoso.onmicrosoft.com/v2.0)
     string authority = String.Format(System.Globalization.CultureInfo.InvariantCulture, System.Configuration.ConfigurationManager.AppSettings["Authority"], tenant);
    //string authority = "https://login.microsoftonline.com/" + tenant + "/adminconsent?client_id=" + clientId;
    string clientSecret = System.Configuration.ConfigurationManager.AppSettings["ClientSecret"];
    /// <summary>
    /// Configure OWIN to use OpenIdConnect 
    /// </summary>
    /// <param name="app"></param>
    public void Configuration(IAppBuilder app)
        {
            app.SetDefaultSignInAsAuthenticationType(CookieAuthenticationDefaults.AuthenticationType);

            app.UseCookieAuthentication(new CookieAuthenticationOptions());
            app.UseOpenIdConnectAuthentication(
            new OpenIdConnectAuthenticationOptions
            {
            // Sets the ClientId, authority, RedirectUri as obtained from web.config
            ClientId = clientId,
                Authority = authority,
                RedirectUri = redirectUri,
            // PostLogoutRedirectUri is the page that users will be redirected to after sign-out. In this case, it is using the home page
            PostLogoutRedirectUri = redirectUri,
                Scope = OpenIdConnectScope.OpenIdProfile,
                // ResponseType is set to request the code id_token - which contains basic information about the signed-in user
                //ResponseType = OpenIdConnectResponseType.CodeIdToken,
                ResponseType = OpenIdConnectResponseType.CodeIdToken,


                // OpenIdConnectAuthenticationNotifications configures OWIN to send notification of failed authentications to OnAuthenticationFailed method
                Notifications = new OpenIdConnectAuthenticationNotifications
                {
                   AuthorizationCodeReceived = OnAuthorizationCodeReceived,
                    AuthenticationFailed = OnAuthenticationFailed
                  
                   
                }
            }
        );
        }

    private async Task OnAuthorizationCodeReceived(AuthorizationCodeReceivedNotification notification)
    {
        notification.HandleCodeRedemption();

        var idClient = ConfidentialClientApplicationBuilder.Create(clientId)
            .WithRedirectUri(redirectUri)
            .WithClientSecret(clientSecret)
            .WithAuthority(authority)               
            .Build();

        try
        {

            var apiScope = "api://28......................../check2 api://28................/check api://28...........................1d/AzAdUtility.Get";
            string[] scopes = apiScope.Split(' ');

            //gettig the token no issues.
            var result = await idClient.AcquireTokenByAuthorizationCode(
                scopes, notification.Code).ExecuteAsync();

            var myurl = "https://localhost:99356/api/AzAdUtility";

            var client = new HttpClient();
            // var accessToken = await tokenAcquisition.GetAccessTokenForUserAsync(Constants.ProductCatalogAPI.SCOPES);
            client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", result.AccessToken); //accessToken

            var json = await client.GetStringAsync(myurl);

            var serializerOptions = new JsonSerializerOptions
            {
                PropertyNamingPolicy = JsonNamingPolicy.CamelCase
            };

           
            //getting 401 response
            var checkResponse = JsonSerializer.Deserialize(json, typeof(string), serializerOptions) as string;

        }


        catch (Exception ex)
        {
            string message = "AcquireTokenByAuthorizationCodeAsync threw an exception";
            notification.HandleResponse();
            notification.Response.Redirect($"/Home/Error?message={message}&debug={ex.Message}");
        }

    }

    /// <summary>
    /// Handle failed authentication requests by redirecting the user to the home page with an error in the query string
    /// </summary>
    /// <param name="context"></param>
    /// <returns></returns>
    private Task OnAuthenticationFailed(AuthenticationFailedNotification<OpenIdConnectMessage, OpenIdConnectAuthenticationOptions> context)
        {
            context.HandleResponse();
            context.Response.Redirect("Error/AccessDenied/?errormessage=" + context.Exception.Message);
            return Task.FromResult(0);
        }
    }

在 Api 啟動 class 中,我缺少app.UseAuthentication()
我從沒想過這會成為一個問題。 一旦我添加了這段代碼。 我得到了預期的響應,而不是 401 未經授權的錯誤

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM