Azure active directory 从blazor调用Api并传递身份验证令牌

Azure active directory 从blazor调用Api并传递身份验证令牌,azure-active-directory,blazor-webassembly,Azure Active Directory,Blazor Webassembly,我有一个blazor webassembly项目,它是从中创建的 它基本上是当您为Blazor应用程序使用.net核心模板时创建的项目,该应用程序通过AD B2B进行身份验证 dotnet new blazorwasm -au SingleOrg --client-id "{CLIENT ID}" -o {APP NAME} --tenant-id "{TENANT ID}" 当用户登录时,我可以调用graph.api。然后,我尝试使用该身份验证调用自己

我有一个blazor webassembly项目,它是从中创建的

它基本上是当您为Blazor应用程序使用.net核心模板时创建的项目,该应用程序通过AD B2B进行身份验证

dotnet new blazorwasm -au SingleOrg --client-id "{CLIENT ID}" -o {APP NAME} --tenant-id "{TENANT ID}"
当用户登录时,我可以调用graph.api。然后,我尝试使用该身份验证调用自己的Api,如中所述

我曾经

   builder.Services.AddHttpClient<ITestDataService, TestDataService>(
      client => client.BaseAddress = new Uri("https://localhost:44342/"))
        .AddHttpMessageHandler(x =>
        {
            var handler = x.GetRequiredService<AuthorizationMessageHandler>()
                .ConfigureHandler(new[] { "https://localhost:44342/" },
                    scopes: new[] { "https://graph.microsoft.com/User.Read" });

            return handler;
        });
你知道少了什么吗


完整的源代码可以在github上找到

如果您想在一个blazor webassembly项目中调用Microsoft graph和自定义API,我们可以通过创建不同的HTTP客户端来调用不同的API来实现

比如说

  • 注册服务器API应用程序

  • 为服务器API应用程序注册AAD应用程序
  • 注册客户端应用程序

  • 注册客户端应用程序
  • 添加API权限。(图形API权限和API应用程序权限)
  • 配置API应用程序

请在
Startup.cs

 public void ConfigureServices(IServiceCollection services)
 {
        JwtSecurityTokenHandler.DefaultMapInboundClaims = false;
        services.AddCors(options =>
            {
                options.AddDefaultPolicy(
                    builder => builder.AllowAnyOrigin()
                        .AllowAnyHeader()
                        .AllowAnyMethod());
            });
               services.AddAuthentication(AzureADDefaults.BearerAuthenticationScheme)
                .AddAzureADBearer(options => Configuration.Bind("AzureAd", options));

            services.Configure<JwtBearerOptions>(AzureADDefaults.JwtBearerAuthenticationScheme, options =>
            {
                options.Authority += "/v2.0";


                options.TokenValidationParameters = new TokenValidationParameters
                {
                    
                    ValidIssuers = new[] {
                      $"https://sts.windows.net/{Configuration["AzureAD:TenantId"]}/",
                      $"https://login.microsoftonline.com/{Configuration["AzureAD:TenantId"]}/v2.0"

                    },
                    RoleClaimType = "roles",
                    // The web API accepts as audiences both the Client ID (options.Audience) and api://{ClientID}.
                    ValidAudiences = new[]
                    {
                           options.Audience,
                           $"api://{options.Audience}"
                    }

                };

            });
....
}
  public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
        {
            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
            }
            app.UseSwagger();
            app.UseSwaggerUI(c =>
            {
                c.OAuthClientId(Configuration["Swagger:ClientId"]);
                c.OAuthScopeSeparator(" ");
                c.OAuthAppName("Protected Api");

                c.SwaggerEndpoint("/swagger/v1/swagger.json", "My API V1");
            });
            app.UseHttpsRedirection();

            app.UseRouting();
            app.UseCors();
            app.UseAuthentication();
            app.UseAuthorization();

            app.UseEndpoints(endpoints =>
            {
                endpoints.MapControllers();
            });
        }
  • 将以下代码添加到program.cs
  • 公共类程序
    {
    公共静态异步任务主(字符串[]args)
    {
    var builder=WebAssemblyHostBuilder.CreateDefault(args);
    builder.RootComponents.Add

     public void ConfigureServices(IServiceCollection services)
     {
            JwtSecurityTokenHandler.DefaultMapInboundClaims = false;
            services.AddCors(options =>
                {
                    options.AddDefaultPolicy(
                        builder => builder.AllowAnyOrigin()
                            .AllowAnyHeader()
                            .AllowAnyMethod());
                });
                   services.AddAuthentication(AzureADDefaults.BearerAuthenticationScheme)
                    .AddAzureADBearer(options => Configuration.Bind("AzureAd", options));
    
                services.Configure<JwtBearerOptions>(AzureADDefaults.JwtBearerAuthenticationScheme, options =>
                {
                    options.Authority += "/v2.0";
    
    
                    options.TokenValidationParameters = new TokenValidationParameters
                    {
                        
                        ValidIssuers = new[] {
                          $"https://sts.windows.net/{Configuration["AzureAD:TenantId"]}/",
                          $"https://login.microsoftonline.com/{Configuration["AzureAD:TenantId"]}/v2.0"
    
                        },
                        RoleClaimType = "roles",
                        // The web API accepts as audiences both the Client ID (options.Audience) and api://{ClientID}.
                        ValidAudiences = new[]
                        {
                               options.Audience,
                               $"api://{options.Audience}"
                        }
    
                    };
    
                });
    ....
    }
      public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
            {
                if (env.IsDevelopment())
                {
                    app.UseDeveloperExceptionPage();
                }
                app.UseSwagger();
                app.UseSwaggerUI(c =>
                {
                    c.OAuthClientId(Configuration["Swagger:ClientId"]);
                    c.OAuthScopeSeparator(" ");
                    c.OAuthAppName("Protected Api");
    
                    c.SwaggerEndpoint("/swagger/v1/swagger.json", "My API V1");
                });
                app.UseHttpsRedirection();
    
                app.UseRouting();
                app.UseCors();
                app.UseAuthentication();
                app.UseAuthorization();
    
                app.UseEndpoints(endpoints =>
                {
                    endpoints.MapControllers();
                });
            }
    
    // custom API
    using Microsoft.AspNetCore.Components;
    using Microsoft.AspNetCore.Components.WebAssembly.Authentication;
    
    public class CustomAuthorizationMessageHandler : AuthorizationMessageHandler
    {
        public CustomAuthorizationMessageHandler(IAccessTokenProvider provider,
            NavigationManager navigationManager)
            : base(provider, navigationManager)
        {
            ConfigureHandler(
                authorizedUrls: new[] { "https://localhost:44300/" },
                scopes: new[] { "the API app scope" });
        }
    }
    
    //Graph API
    using Microsoft.AspNetCore.Components;
    using Microsoft.AspNetCore.Components.WebAssembly.Authentication;
    
    public class GraphAuthorizationMessageHandler : AuthorizationMessageHandler
    {
        public GraphAuthorizationMessageHandler(IAccessTokenProvider provider,
            NavigationManager navigationManager)
            : base(provider, navigationManager)
        {
            ConfigureHandler(
                authorizedUrls: new[] { "https://graph.microsoft.com/" },
                scopes: new[] { "https://graph.microsoft.com/User.Read" });
        }
    }
    
    public class Program
        {
            public static async Task Main(string[] args)
            {
                var builder = WebAssemblyHostBuilder.CreateDefault(args);
                builder.RootComponents.Add<App>("app");
    
                builder.Services.AddScoped<CustomAuthorizationMessageHandler>();
                builder.Services.AddScoped<GraphAuthorizationMessageHandler>();
                // register HTTP client to call our own api
                builder.Services.AddHttpClient("MyAPI", client => client.BaseAddress = new Uri("https://localhost:44300/"))
                  .AddHttpMessageHandler<CustomAuthorizationMessageHandler>();
                // register HTTP client to call graph api
                builder.Services.AddHttpClient("GraphAPI", client => client.BaseAddress = new Uri("https://graph.microsoft.com/"))
                  .AddHttpMessageHandler<GraphAuthorizationMessageHandler>();
      
                builder.Services.AddMsalAuthentication(options =>
                {
                    builder.Configuration.Bind("AzureAd", options.ProviderOptions.Authentication);
                    options.ProviderOptions.DefaultAccessTokenScopes.Add("<the API app scope>");
                    options.ProviderOptions.AdditionalScopesToConsent.Add("https://graph.microsoft.com/User.Read");
                });
    
                await builder.Build().RunAsync();
            }
        }
    
    @inject IHttpClientFactory _clientFactory
    
    var httpClient = _clientFactory.CreateClient("<the client name you register>");
    await apiClient.GetStringAsync("path");