繁体   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