Ваш код страдает от нескольких недугов ... Основная проблема заключается в том, что в вашем коде отсутствует механизм запроса вызова проверки подлинности, который обеспечивает перенаправление на агент проверки подлинности, такой как IdentityServer. Это возможно только с HttpContext, который недоступен в SignalR (Blazor Server App). Чтобы решить эту проблему, мы добавим пару страниц Razor, где доступен HttpContext. Подробнее в ответ ...
Ниже приведено полное и рабочее решение вопроса:
- Создание приложения Blazor Server.
- Install-Package Microsoft .AspNetCore.Authentication.OpenIdConnect -Version 3.1.0
Создать компонент с именем LoginDisplay (LoginDisplay.razor) и поместить его в общую папку. Этот компонент используется в компоненте MainLayout
<AuthorizeView>
<Authorized>
<a href="logout">Hello, @context.User.Identity.Name !</a>
<form method="get" action="logout">
<button type="submit" class="nav-link btn btn-link">Log out</button>
</form>
</Authorized>
<NotAuthorized>
<a href="login?redirectUri=/">Log in</a>
</NotAuthorized>
</AuthorizeView>
Добавьте компонент LoginDisplay к компоненту MainLayout, чуть выше элемента привязки About, например,
<div class="top-row px-4">
<LoginDisplay />
<a href="https://docs.microsoft.com/aspnet/" target="_blank">About</a>
</div>
Примечание. Чтобы перенаправить запросы на вход и выход на IdentityServer, нам нужно создать две страницы Razor следующим образом: 1. Создать страницу Razor для входа Login.cs html (Login.cs * 1084). * .cs) и поместите их в папку «Страницы» следующим образом:
Login.cs html .cs
using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Authentication.OpenIdConnect;
using Microsoft.AspNetCore.Authentication.Cookies;
using Microsoft.IdentityModel.Tokens;
public class LoginModel : PageModel
{
public async Task OnGet(string redirectUri)
{
await HttpContext.ChallengeAsync("oidc", new
AuthenticationProperties { RedirectUri = redirectUri } );
}
}
Этот код запускает вызов для схемы аутентификации Open Id Connect, которую вы определено в классе запуска.
Создайте страницу Logaz Razor Logout.cs html (Logout.cs html .cs) и поместите их также в папку Pages:
Logout.cs html. cs
using Microsoft.AspNetCore.Authentication;
public class LogoutModel : PageModel
{
public async Task<IActionResult> OnGetAsync()
{
await HttpContext.SignOutAsync();
return Redirect("/");
}
}
Этот код выводит вас, перенаправляя на домашнюю страницу вашего приложения Blazor.
Замените код в App.razor следующим кодом:
@inject NavigationManager NavigationManager
<CascadingAuthenticationState>
<Router AppAssembly="@typeof(Program).Assembly">
<Found Context="routeData">
<AuthorizeRouteView RouteData="@routeData" DefaultLayout="@typeof(MainLayout)">
<NotAuthorized>
@{
var returnUrl = NavigationManager.ToBaseRelativePath(NavigationManager.Uri);
NavigationManager.NavigateTo($"login?redirectUri={returnUrl}", forceLoad: true);
}
</NotAuthorized>
<Authorizing>
Wait...
</Authorizing>
</AuthorizeRouteView>
</Found>
<NotFound>
<LayoutView Layout="@typeof(MainLayout)">
<p>Sorry, there's nothing at this address.</p>
</LayoutView>
</NotFound>
</Router>
</CascadingAuthenticationState>
Замените код в классе запуска следующим:
using Microsoft.AspNetCore.Authentication.OpenIdConnect;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc.Authorization;
using System.Net.Http;
using Microsoft.AspNetCore.Authentication.Cookies;
using Microsoft.IdentityModel.Tokens;
using Microsoft.IdentityModel.Protocols.OpenIdConnect;
using Microsoft.IdentityModel.Logging;
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.
// For more information on how to configure your application, visit https://go.microsoft.com/fwlink/?LinkID=398940
public void ConfigureServices(IServiceCollection services)
{
services.AddRazorPages();
services.AddServerSideBlazor();
services.AddAuthorizationCore();
services.AddSingleton<WeatherForecastService>();
services.AddAuthentication(sharedOptions =>
{
sharedOptions.DefaultAuthenticateScheme =
CookieAuthenticationDefaults.AuthenticationScheme;
sharedOptions.DefaultSignInScheme =
CookieAuthenticationDefaults.AuthenticationScheme;
sharedOptions.DefaultChallengeScheme =
OpenIdConnectDefaults.AuthenticationScheme;
})
.AddCookie()
.AddOpenIdConnect("oidc", options =>
{
options.Authority = "https://demo.identityserver.io/";
options.ClientId = "interactive.confidential.short";
options.ClientSecret = "secret";
options.ResponseType = "code";
options.SaveTokens = true;
options.GetClaimsFromUserInfoEndpoint = true;
options.UseTokenLifetime = false;
options.Scope.Add("openid");
options.Scope.Add("profile");
options.TokenValidationParameters = new
TokenValidationParameters
{
NameClaimType = "name"
};
options.Events = new OpenIdConnectEvents
{
OnAccessDenied = context =>
{
context.HandleResponse();
context.Response.Redirect("/");
return Task.CompletedTask;
}
};
});
}
// 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();
}
else
{
app.UseExceptionHandler("/Error");
// The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.UseAuthentication();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapBlazorHub();
endpoints.MapFallbackToPage("/_Host");
});
}
}
ВАЖНО : во всем приведенном выше примере кода вам придется добавлять операторы по мере необходимости. Большинство из них предоставляются по умолчанию. Предоставленное здесь использование - это то, что необходимо для включения процесса аутентификации и авторизации.
- Запустите ваше приложение, нажмите на кнопку входа в систему для аутентификации. Вы будете перенаправлены на тестовый сервер IdentityServer, который позволит вам выполнить вход с OID C. Вы можете ввести имя пользователя: bob и пароль bob , и после нажатия кнопки ОК вы будете перенаправлены на домашнюю страницу. Также обратите внимание, что вы можете использовать внешний логин провайдера Google (попробуйте). Обратите внимание, что после входа в систему с помощью сервера идентификации компонент LoginDisplay отображает строку «Hello».
Примечание. Во время экспериментов с приложением следует очистить данные просмотра, если вы хотите быть перенаправлены на страницу входа на сервер идентификации, в противном случае ваш браузер может использовать кэшированные данные. Помните, что это механизм авторизации на основе Cook ie ...
Обратите внимание, что создание механизма входа в систему, как это делается здесь, не делает ваше приложение более защищенным, чем раньше. Любой пользователь может получить доступ к вашим веб-ресурсам без необходимости входа в систему вообще. Чтобы защитить части вашего веб-сайта, вы также должны реализовать авторизацию, обычно аутентифицированный пользователь авторизуется для доступа к защищенному ресурсу, если не применяются другие меры, такие как роли, политики и т. Д. c. Ниже приведена демонстрация того, как вы можете защитить свою страницу Fetchdata от неавторизованных пользователей (опять же, аутентифицированный пользователь считается авторизованным для доступа к странице Fetchdata).
- В верхней части страницы компонента Fetchdata добавьте @ Директива атрибута для атрибута Authorize, например:
@attribute [Authorize]
Когда пользователь, не прошедший проверку подлинности, пытается получить доступ к странице Fetchdata, выполняется свойство делегата AuthorizeRouteView.NotAuthorized
, поэтому мы можем добавить некоторый код для перенаправления пользователя на страницу входа того же сервера идентификации аутентифицировать. Код в элементе NotAuthorized выглядит следующим образом:
<NotAuthorized>
@{
var returnUrl =
NavigationManager.ToBaseRelativePath(NavigationManager.Uri);
NavigationManager.NavigateTo($"login?redirectUri=
{returnUrl}", forceLoad: true);
}
</NotAuthorized>
Получает URL последней страницы, к которой вы пытались получить доступ, страницу Fetchdata, а затем переходит на страницу Login Razor, с которой выполняется запрос пароля, то есть пользователь перенаправляется на страницу входа на сервер идентификации.
После аутентификации пользователь перенаправляется на страницу Fetchdata.
Удачи ...