#c# #razor #authorization #blazor
#c# #razor #авторизация #blazor
Вопрос:
Я пишу SPA с использованием Blazor Wasm. Я использовал стандартный шаблон и включил учетные записи пользователей, размещенные на сервере, который также создал серверное приложение. Пока все в порядке. Я бы добавил, что я использую.Net5 RC2 но я не думаю, что это моя проблема здесь.
Я хочу иметь несколько «обычных» страниц razor на сервере, а также в клиентском приложении. Сервер идентификации учетных записей пользователей создал структуру папок / Areas/Identity/Pages/…. Я добавил /Areas/Management/Pages/Admin/Test.cshtml и Test.cshtml.cs Это очень простые тестовые файлы…
РЕДАКТИРОВАТЬ — я отредактировал это, чтобы отразить вопросы, заданные @enet.
Файл razor:
@page
@model ProjName.Server.Areas.Management.Pages.Admin.TestModel
<h1>Test Page</h1>
@if (User.Identity.IsAuthenticated)
{
@if (User.IsInRole("Administrator"))
{
<h2>User is Admin</h2>
}
else
{
<h2>User is not an admin</h2>
}
}
else
{
<h2>User is Not Authenticated</h2>
}
@{
}
Файл .CS:
namespace ProjName.Server.Areas.Management.Pages.Admin
{
[Authorize] <<<--- See case B.
public class TestModel : PageModel
{
public void OnGet()
{
}
}
}
Я хочу, чтобы на странице было указано, что либо пользователь является администратором, либо пользователь не является администратором.
В случае A: если [Авторизовать] удалено, страница загрузится, но всегда будет показывать, что пользователь не авторизован. Итак, страница визуализируется, и простой тест выдает случай «else»..
В случае B: страница вообще не будет отображаться. (Эта страница не работает! — сообщение от браузера). Итак, из моих исследований в этом:
Соглашения об авторизации страниц Razor
Я изменил свой startup.cs с этого:
services.AddRazorPages();
к этому:
services.AddRazorPages(options =>
{
options.Conventions.AuthorizeAreaFolder("Management", "/Admin");
});
*** Я удалил вышеупомянутое и сбросил его до того, как это было ***
Когда я это делаю, получается тот же результат, что и в случае B, с или без [Авторизовать] в файле .cs. Я думаю, это имеет смысл, когда вы читаете документы.
Так что, я думаю, мне нужно вернуть какую-то форму токена авторизации обратно или?
Страницы идентификации не требуют никакой авторизации, поэтому это не проблема. Мои службы настройки выглядят так:
public void ConfigureServices(IServiceCollection services)
{
services.AddDbContext<RGDbContext>(options =>
options.UseSqlServer(
Configuration.GetConnectionString("DefaultConnection")));
services.AddDatabaseDeveloperPageExceptionFilter();
services.AddDefaultIdentity<ApplicationUser>(options => options.SignIn.RequireConfirmedAccount = true)
.AddRoles<IdentityRole>()
.AddEntityFrameworkStores<RGDbContext>();
// This was put in to try to sort this https://github.com/dotnet/AspNetCore.Docs/issues/17517
//services.Configure<IdentityOptions>(options =>
// options.ClaimsIdentity.UserIdClaimType = ClaimTypes.NameIdentifier);
services.AddIdentityServer()
.AddApiAuthorization<ApplicationUser, RGDbContext>(options => {
options.IdentityResources["openid"].UserClaims.Add("name");
options.ApiResources.Single().UserClaims.Add("name");
options.IdentityResources["openid"].UserClaims.Add("role");
options.ApiResources.Single().UserClaims.Add("role");
});
services.AddAuthentication()
.AddIdentityServerJwt();
services.AddControllersWithViews();
//services.AddRazorPages();
services.AddRazorPages(options =>
{
options.Conventions.AuthorizeAreaFolder("Management", "/Admin");
});
.... more of my own stuff...
*** Переход на страницу сервера осуществляется с кнопки в NavMenu, вызывающей событие onclick для этого:
private void ServerPageTest()
{
Navigation.NavigateTo("/Management/Admin/Test", true);
}
У меня такое чувство, что мне не хватает некоторых опций в моем запуске, есть мысли..
Ответ №1:
Я думаю, у меня есть ответ…
Изменение файла Startup.cs, где у нас есть:
services.AddAuthentication();
Я изменил его на:
services.AddAuthentication(options =>
{
options.DefaultAuthenticateScheme = IdentityConstants.ApplicationScheme;
options.DefaultChallengeScheme = IdentityConstants.ApplicationScheme;
})
Затем это позволяет серверу обслуживать страницы razor с аутентификацией.
Это также имело еще один побочный эффект, заключающийся в изменении того, как утверждения воспринимаются обратно на сервере, и приводит к тому, что любые контроллеры API могут работать более традиционным способом контроллера. Я объясню. У меня также есть «ApplicationUserController» с конечной точкой API «AddUpdateUser», которая делает то, что написано на tin.
У меня был этот код для проверки зарегистрированного пользователя:
public async Task<ActionResult<ApplicationUserDTO>> AddUpdateUser(ApplicationUserDTO sentUser)
{
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}
// Get the logged in user.
// This line should work but doesnt and I dont know why.
ApplicationUser loggedinUserX = await _userManager.GetUserAsync(User).ConfigureAwait(false);
Но он всегда возвращал null. и поэтому мне пришлось прибегнуть к поиску идентификатора пользователя из утверждений с помощью этого кода:
string loggedinUserId = User.FindFirstValue(ClaimTypes.NameIdentifier);
ApplicationUser loggedinUser = _context.Users.Find(loggedinUserId);
Мне также пришлось искать, как это сделать. Конечно, нашел это на этом замечательном сайте.
Но добавление двух строк при запуске нарушило этот код и заставило исходный код работать. Думаю, теперь я понимаю, почему, и людям очень хорошо говорить «прочитайте документацию», но иногда это просто слишком сложно.
В любом случае, я надеюсь, что это поможет некоторым людям.