【问题标题】:Blazor WASM httpcontext alternativeBlazor WASM httpcontext 替代方案
【发布时间】: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


【解决方案1】:

我发现了问题所在:Startup.csConfigureServices 方法中的排序。

我将 use authenticationauthorization 移到此方法的最顶部,HttpContext 现在可以正常工作了。

感谢大家的帮助

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-10-05
    • 2010-09-10
    • 2012-12-05
    • 2013-11-22
    • 2020-11-23
    • 2013-08-07
    • 2015-09-11
    相关资源
    最近更新 更多