【发布时间】:2021-11-11 14:29:06
【问题描述】:
我有一个带有 ASP.net 核心托管的 blazor wasm 项目。身份验证,即登录,注册位于通过剃刀页面(.cshtml)在服务器项目上。当用户成功登录到应用程序时,如果当前用户已登录,我需要能够更改这些剃须刀页面上 UI 的某些方面。在过去的 asp.net 核心项目中,通常的过程是利用HTTPContext 例如
@if (!HttpContext.User.Identity.IsAuthenticated)
{
<li><a class="log-in-cta" asp-area="identity" asp-page="/account/login">Log in</a></li>
}
else
{
<li><a class="log-in-cta" asp-page="/home">Log otut</a></li>
}
但是,无论当前用户是否登录,这都会返回 false。我在网上看了一下,很多人都说 HTTPcontext 不应该在 blazor 应用程序中使用。我的问题是,如果是这种情况,对于 blazor 应用程序的服务器项目上的 razor 页面,还有什么替代方法?
项目解决方案
登录页面尝试使用 httpcontext
@page
@model LoginModel
@{
ViewData["Title"] = "Log in";
}
@if (HttpContext.User.Identity.IsAuthenticated)
{
<p>You are already logged in </p>
<a asp-page="./Logout">Logout</a>
}
else
{
<div class="lighthouse-bg">
<div class="container">
<div class="account-form-wrapper">
<a href="/"><img class="beacon-logo" src="/img/logos/beacon-assist-logo.png" alt="beacon assist logo"></a>
<div class="account-form">
<div class="account-form-titles">
<h1 class="account-form__title">Login</h1>
</div>
<!-- Login form-->
<form method="post" asp-route-returnurl="@ViewData["ReturnUrl"]">
<input asp-for="@Model.ReturnUrl" type="hidden" />
<!-- Form Group (email address)-->
<span asp-validation-for="Input.Email"></span>
<div class="account-form-input">
<div class="input-wrapper">
<div class="input-icon" id="email-icon">
<img src="/img/icons/icon-at.svg">
</div>
<input asp-for="Input.Email" id="email" placeholder="email address" type="email" autocomplete="email" tabindex="1" autofocus="" />
</div>
</div>
<!-- Form Group (password)-->
<span asp-validation-for="Input.Password"></span>
<div class="account-form-input">
<div class="input-wrapper">
<div class="input-icon" id="password-icon">
<img src="/img/icons/icon-key.svg">
</div>
<input asp-for="Input.Password" id="password" placeholder="password" type="password" autocomplete="existing-password" />
</div>
</div>
<!-- Form Group (remember password checkbox)-->
<div class="account-form-checkbox-wrapper">
<label class="account-form-checkbox">
Remember me ?
<input asp-for="Input.RememberMe" id="check" type="checkbox" />
<span class="checkmark"></span>
</label>
</div>
<!-- Form Group (login box)-->
<div class="account-form-footer">
<button class="account-form-btn" type="submit">Login</button>
<a class="footer-link" asp-page="./ForgotPassword" tabindex="4">Forgot Password?</a>
</div>
<div asp-validation-summary="ModelOnly" class="font-weight-bold text-danger"></div>
</form>
</div>
</div>
</div>
</div>
}
服务器项目的 Startup.cs,以防我错过了所需的任何配置
namespace Tapiit.Beacon.Server
{
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.AddDbContext<ApplicationDbContext>(options =>
options.UseSqlServer(
Configuration.GetConnectionString("DefaultConnection")));
services.Configure<DatabaseOptions>(o =>
{
o.ConnectionString = Configuration["ConnectionStrings:DefaultConnection"];
});
services.AddDatabaseDeveloperPageExceptionFilter();
services.AddDefaultIdentity<User>(o =>
{
// TODO: this was removed for testing
// o.SignIn.RequireConfirmedAccount = true;
o.Password.RequiredLength = 8;
})
.AddRoles<Role>()
.AddEntityFrameworkStores<ApplicationDbContext>();
services.AddIdentityServer()
.AddApiAuthorization<User, ApplicationDbContext>(o =>
{
// https://github.com/dotnet/AspNetCore.Docs/issues/17649
o.IdentityResources["openid"].UserClaims.Add("role");
o.ApiResources.Single().UserClaims.Add("role");
o.ApiResources.Single().UserClaims.Add("name");
})
.AddProfileService<IdentityProfileService>();
// Need to do this as it maps "role" to ClaimTypes.Role and causes issues
JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Remove("role");
services.AddAuthentication()
.AddIdentityServerJwt();
services.AddAuthorization(o => o.AddAppPolicies());
services
.AddControllersWithViews(o =>
{
o.ModelBinderProviders.Insert(0, new LocalDateTimeModelBinderProvider());
o.ModelBinderProviders.Insert(0, new LocalDateModelBinderProvider());
o.ModelBinderProviders.Insert(0, new LocalTimeModelBinderProvider());
o.Filters.Add(new StatusCodeActionFilter());
})
.AddJsonOptions(o =>
{
o.JsonSerializerOptions.Converters.Add(new LocalDateTimeConverter());
o.JsonSerializerOptions.Converters.Add(new NullableLocalDateTimeConverter());
});
services.AddRazorPages();
services.AddHttpClient();
services.AddQueueService(o =>
{
o.AzureServiceBusConnectionString = Configuration["ConnectionStrings:AzureServiceBus"];
o.QueueName = Configuration["ServiceBusQueueName"];
});
AddHelpers(services);
AddRepositories(services);
AddMediatR(services);
}
private void AddHelpers(IServiceCollection services)
{
services.AddScoped<UserManager<User>>();
services.AddScoped<ISignInManager<User>, ApplicationSignInManager>();
services.AddSingleton<IClock>(NodaTime.SystemClock.Instance);
services.AddSingleton<IDataCache<DataCacheTag>, DataCache<DataCacheTag, DataCacheEntryInfo>>();
services.AddScoped<ISupportTeamUserHelper, SupportTeamUserHelper>();
services.AddSingleton<IVesselUserHelper, VesselUserHelper>();
services.AddSingleton<IVesselSupportTeamHelper, VesselSupportTeamHelper>();
services.AddScoped<IUserClaimIds, UserClaimIds>();
services.AddScoped<IAccountHelper, AccountHelper>();
services.AddScoped<IUserHelper, UserHelper>();
services.AddScoped<IVesselHelper, VesselHelper>();
services.AddScoped<IOrganisationHelper, OrganisationHelper>();
services.AddScoped<ISupportTeamHelper, SupportTeamHelper>();
services.AddScoped<IManageHelper, ManageHelper>();
services.AddScoped<ICityBasedRuleHelper, CityBasedRuleHelper>();
services.AddScoped<IGeoFenceRuleHelper, GeoFenceRuleHelper>();
}
private void AddRepositories(IServiceCollection services)
{
services.AddScoped<ISupportTeamUserRepository, SupportTeamUserRepository>();
services.AddSingleton<IVesselUserRepository, VesselUserRepository>();
services.AddSingleton<IVesselSupportTeamRepository, VesselSupportTeamRepository>();
services.AddScoped<IUserRepository, UserRepository>();
services.AddScoped<IVesselRepository, VesselRepository>();
services.AddScoped<IOrganisationRepository, OrganisationRepository>();
services.AddScoped<ISupportTeamRepository, SupportTeamRepository>();
services.AddScoped<ICityBasedRuleRepository, CityBasedRuleRepository>();
services.AddScoped<IGeoFenceRuleRepository, GeoFenceRuleRepository>();
}
// 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.UseMigrationsEndPoint();
app.UseWebAssemblyDebugging();
}
else
{
app.UseExceptionHandler("/Error");
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseBlazorFrameworkFiles();
app.UseStaticFiles();
app.UseRouting();
app.UseIdentityServer();
app.UseAuthentication();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapRazorPages();
endpoints.MapControllers();
endpoints.MapFallbackToFile("index.html");
});
}
private static void AddMediatR(IServiceCollection services)
{
services.AddValidatorsFromAssembly(typeof(DummyValidator).Assembly);
// Add PipelineBehaviours in order of execution:
services.AddTransient(typeof(IPipelineBehavior<,>), typeof(LoggingBehaviour<,>));
services.AddTransient(typeof(IPipelineBehavior<,>), typeof(ValidationBehaviour<,>));
services.AddMediatR(typeof(DummyRequestHandler).Assembly);
}
}
}
【问题讨论】:
-
是的,我知道它们是不同的东西。我正在处理的项目是一个 blazor 应用程序,但是它仍然使用服务器项目上的 razor 页面来进行身份验证,例如登录,注册,忘记密码。我通过脚手架实现了这些,并且需要根据用户是否已经通过 httpcontext 登录来更改登录页面上的内容,这总是看起来是错误的,这就是为什么我问我是否仍然对这些特定使用 httpcontext剃刀页面,就像它们在 Blazor 应用程序中一样?
-
啊酷,一定有其他原因导致它无法正常工作,可能是我在启动时的配置。感谢您的澄清,我只是不确定它是否应该在与 Blazor 项目相同的方面发挥作用。
-
我解决了这个问题,这是我启动时的顺序,.cs 我将使用身份验证和授权放在配置服务的最顶部,它现在可以正常工作
标签: asp.net-core authentication blazor webassembly httpcontext