0

我正在关注 Microsfot.document 中关于如何使用 Azure AD (Microsoft Identity) 保护 api 的教程。

我采取的步骤如下:对不起,我试图提供可能有用但太多的信息,大多数时间贡献者要求截图或代码。

我关注了几个文档和视频教程,但这里是其中之一的链接: https ://docs.microsoft.com/en-us/learn/modules/identity-secure-custom-api/2-secure-api-microsoft -身份

WebAPI。

  1. 使用核心 5 创建了一个 webapi。在 Azure AD 中注册它。
  2. 创建单一范围“检查”并允许用户和管理员权限。

Webapp Created webapp using .net(classic) 注意 webapi 是 core 5。

  1. 创建了一个 webapp 并在 Azure AD 中注册它。
  2. 设置身份验证并创建 OnAuthorizationCodeReceived 以获取访问令牌以调用 api。

配置: 1.从 Azure AD->Webapi 注册-> 选择的应用程序(上面创建的 Web 应用程序)并授予范围权限。

在此处输入图像描述 2.对于Azure AD->Webapp注册->访问权限->委托->选择范围。 在此处输入图像描述

测试: 1.运行测试。在此刻; 我在调用的 api 方法上没有 [Authorization]。2、Webapp成功获取到api返回的字符串。在某种程度上,我认为管道是正确的。

  1. 在 app 方法上添加了 [Authorize] 过滤器。
  2. 结果 401 未经授权。

我已经检查了多次,查看了多个教程并重写了我的代码,观看了几个视频并更新了我的代码,但我总是收到 401 错误。

下面是代码;API 控制器:

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启动:公共类启动{公共启动(IConfiguration配置){配置=配置;}

    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);
        }
    }
4

1 回答 1

0

在 Api 启动课程中,我失踪了app.UseAuthentication()
我从没想过这会是个问题。一旦我添加了这段代码。我得到了预期的响应,而不是 401 Unauthorized 错误

于 2022-02-09T04:42:01.117 回答