[英]Blazor WASM protected with Azure Active Directory can't call protected WebAPI
我目前正在開發一個 Blazor wasm webapp,它受 Azure Active Directory 和 WebAPI 保護,它也受 AAD 保護。 APP本身也調用MSGraph API獲取用戶基本信息。
當前工作:如果未經授權,用戶將無法訪問該頁面,如果未經授權,他將被重定向到微軟頁面以登錄/獲得授權。 訪問該頁面后,我還可以按照本教程通過 msgraph 獲取基本用戶信息: 官方 MS GraphAPI 教程並添加 GraphClientExtension class。
我的網絡API:
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.AddCors(options =>
{
options.AddDefaultPolicy(builder =>
builder.WithOrigins("*")
.AllowAnyMethod()
.AllowAnyHeader());
});
services.AddControllers();
services.AddSwaggerGen(c =>
{
c.SwaggerDoc("v1", new OpenApiInfo { Title = "X.Y.API", 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", "X.Y.API v1"));
}
//app.UseHttpsRedirection();
app.UseRouting();
app.UseCors();
app.UseAuthentication();
app.UseAuthorization();
app.UseEndpoints(endpoints => { endpoints.MapControllers(); });
}
}
我要調用的控制器/端點:
[Authorize]
[ApiController]
[Route("[controller]")]
public class WeatherForecastController : ControllerBase
{
private static readonly string[] Summaries = new[]
{
"Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching"
};
private readonly ILogger<WeatherForecastController> _logger;
public WeatherForecastController(ILogger<WeatherForecastController> logger)
{
_logger = logger;
}
[HttpGet]
public IEnumerable<WeatherForecast> Get()
{
var rng = new Random();
return Enumerable.Range(1, 5).Select(index => new WeatherForecast
{
Date = DateTime.Now.AddDays(index),
TemperatureC = rng.Next(-20, 55),
Summary = Summaries[rng.Next(Summaries.Length)]
})
.ToArray();
}
}
AzureAD 設置
"AzureAd": {
"Instance": "https://login.microsoftonline.com/",
"Domain": "<company>.onmicrosoft.com",
"TenantId": "d3c98095-xyz",
"ClientId": "a51b0337-xyz",
}
Blazor Wasm:
程序.cs:
public class Program
{
public static async Task Main(string[] args)
{
var builder = WebAssemblyHostBuilder.CreateDefault(args);
builder.RootComponents.Add<App>("#app");
AddMsIdentityAuthentication(builder);
AddMsGraphServices(builder);
AddHttpClients(builder);
AddExternalServices(builder);
await builder.Build().RunAsync();
}
private static void AddHttpClients(WebAssemblyHostBuilder builder)
{
builder.Services.AddHttpClient<LocalHttpClient>(client => client.BaseAddress = new Uri(builder.HostEnvironment.BaseAddress));
builder.Services.AddHttpClient<ProtectedAPIHttpClient>(client =>
{
client.BaseAddress = new Uri("http://localhost:5000");
});
}
private static void AddMsIdentityAuthentication(WebAssemblyHostBuilder builder)
{
builder.Services.AddMsalAuthentication(options =>
{
builder.Configuration.Bind("AzureAd", options.ProviderOptions.Authentication);
options.ProviderOptions.DefaultAccessTokenScopes.Add("a51b0337-xyz/Read");
options.ProviderOptions.LoginMode = "redirect";
});
}
private static void AddMsGraphServices(WebAssemblyHostBuilder builder)
{
builder.Services.AddGraphClient();
}
private static void AddExternalServices(WebAssemblyHostBuilder builder)
{
builder.Services.AddTelerikBlazor();
}
}
受保護的APIHttpClient
public class ProtectedAPIHttpClient
{
private readonly HttpClient _http;
public ProtectedAPIHttpClient(HttpClient http)
{
_http = http;
}
public async Task<string> GetDataTest()
{
try
{
var test = await _http.GetStringAsync("WeatherForecast");
Console.WriteLine(test);
return test;
}
catch (Exception e)
{
Console.WriteLine(e);
if(e is HttpRequestException ex)
{
Console.WriteLine((int)ex.StatusCode);
}
throw;
}
}
}
App.razor:
<CascadingAuthenticationState>
<Router AppAssembly="@typeof(Program).Assembly" PreferExactMatches="@true">
<Found Context="routeData">
<AuthorizeRouteView RouteData="@routeData" DefaultLayout="@typeof(MainLayout)">
<NotAuthorized>
@if (!context.User.Identity.IsAuthenticated)
{
<RedirectToLogin/>
}
else
{
<p>You are not authorized to access this resource.</p>
}
</NotAuthorized>
</AuthorizeRouteView>
</Found>
<NotFound>
<LayoutView Layout="@typeof(MainLayout)">
<p>Sorry, there's nothing at this address.</p>
</LayoutView>
</NotFound>
</Router>
</CascadingAuthenticationState>
重定向登錄:
@inject NavigationManager _navigation
@code {
protected override void OnInitialized()
{
_navigation.NavigateTo($"authentication/login?returnUrl={Uri.EscapeDataString(_navigation.Uri)}");
}
}
驗證:
@page "/authentication/{action}"
@attribute [AllowAnonymous]
<RemoteAuthenticatorView Action="@Action">
<LoggingIn></LoggingIn>
<LogInFailed></LogInFailed>
<CompletingLoggingIn></CompletingLoggingIn>
<LogOut></LogOut>
<LogOutFailed></LogOutFailed>
<LogOutSucceeded></LogOutSucceeded>
<CompletingLogOut></CompletingLogOut>
</RemoteAuthenticatorView>
@code{
[Parameter]
public string Action { get; set; }
}
AzureAD 配置:
"AzureAd": {
"Authority": "https://login.microsoftonline.com/d3c98095-xyz",
"ClientId": "b02ce171-xyz",
"ValidateAuthority": true
},
我還向 _Imports.cs 添加了@attribute [Authorize]
幾天來,我一直在糾結這個問題。 如果我刪除/注釋掉 program.cs 中的 API Scope "options.ProviderOptions.DefaultAccessTokenScopes" 一切正常:用戶被迫登錄並可以在應用程序中導航(並從中獲取圖片、名字等用戶信息圖表)。 但是,如果我添加 DefautAccessTokenScopes,則根本不可能登錄頁面。 它在某種登錄重定向循環中。 我也嘗試改用 AdditionalScopesToConsent,但結果相同。 我已經遵循了很多教程,並且在大多數教程中,像這樣配置應用程序/api 對於一個簡單的受保護 api 調用示例來說應該足夠了……但我似乎誤解了一些東西。 有誰知道或知道我做錯了什么?
I checked my solution working similar to this, what I found is that App.razor should not contain NotAuthorized
section und AuthorizeRouteView
this should be in the MailLayout.razor or Index.razor etc. under AuthorizeView
.
App.razor 樣品:
<CascadingAuthenticationState>
<CascadingBlazoredModal>
<Router AppAssembly="@typeof(Program).Assembly">
<Found Context="routeData">
<AuthorizeRouteView RouteData="@routeData" DefaultLayout="@typeof(MainLayout)" />
</Found>
<NotFound>
<LayoutView Layout="@typeof(MainLayout)">
<p>Sorry, there's nothing at this address.</p>
</LayoutView>
</NotFound>
</Router>
</CascadingBlazoredModal>
</CascadingAuthenticationState>
在某些 *.razor 頁面上:
<AuthorizeView Policy="@($"{PermissionLevel.XYZ}")">
<Authorized>
<p>You are able to see the page</p>
<p> Even more content</p>
</Authorized>
</AuthorizeView>
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.