ASP.NET Core MVC 身份功能在发布到服务器时不起作用

Posted

技术标签:

【中文标题】ASP.NET Core MVC 身份功能在发布到服务器时不起作用【英文标题】:ASP.NET Core MVC Identity features not working when published to server 【发布时间】:2021-07-22 13:58:07 【问题描述】:

我有一个 ASP.NET Core MVC Web 应用程序,它使用 Entity Framework 和 Microsoft Identity 作为用户帐户。我能够在调试中运行应用程序并创建帐户/登录等,但是,当发布到 iis 时,我收到以下错误:

Error Message

有问题的代码在下面的 _Layout.cshtml 中,据我所知,它没有像在调试中那样实现用户身份。

_Layout.cshtml

@using Microsoft.AspNetCore.Identity
@using MyApp.Areas.Identity.Data
@inject UserManager<MyAppUser> userManger
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>@ViewData["Title"] - MyApp</title>
    <link rel="stylesheet" href="~/lib/bootstrap/dist/css/bootstrap.min.css" />
    <link rel="stylesheet" href="~/css/site.css" />
</head>
<body>
    <header>
        <nav class="navbar navbar-expand-sm navbar-toggleable-sm navbar-light bg-white border-bottom box-shadow mb-3">
            <div class="container">
                <div style="height:30px; margin-top:0px;">
                    <img class="navbar-brand" style="height:auto; width:auto; max-height:100%; max-width:100%;" src="~/images/AASLogoDarkMinimal.png" />
                </div>
                <a class="navbar-brand" asp-area="" asp-controller="Home" asp-action="Index">My App</a>
                <button class="navbar-toggler" type="button" data-toggle="collapse" data-target=".navbar-collapse" aria-controls="navbarSupportedContent"
                        aria-expanded="false" aria-label="Toggle navigation">
                    <span class="navbar-toggler-icon"></span>
                </button>
                <div class="navbar-collapse collapse d-sm-inline-flex flex-sm-row-reverse">
                    <partial name="_LoginPartial.cshtml" />






                    <ul class="navbar-nav flex-grow-1">

                          @if (User.Identity.IsAuthenticated)
                            
                                var user = await userManger.GetUserAsync(User);

                                var rolesArray = userManger.GetRolesAsync(user).Result;

                                if (rolesArray.Contains("Administrator") || rolesArray.Contains("Sales Administrator"))
                                
                                <li class="nav-item dropdown">

                                    <a class="nav-link dropdown-toggle text-info" href="#" id="navbarDropdown" role="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
                                        Admin Tools
                                    </a>
                                    <div class="dropdown-menu" aria-labelledby="navbarDropdown">
                                        @if (rolesArray.Contains("Administrator"))
                                            
                                        <a type="button" class="dropdown-item btn btn-info btn-sm" asp-controller="User" asp-action="Index">User Management</a>
                                            
                                        @if (rolesArray.Contains("Sales Administrator"))
                                            
                                        <a type="button" class="dropdown-item btn btn-info btn-sm" asp-controller="User" asp-action="Index">Price Management</a>
                                            

                                    </div>

                                </li>

                                

                            
                            

                    </ul>


                </div>
            </div>
        </nav>
    </header>
    <div class="container">
        <main role="main" class="pb-3">
            @RenderBody()
        </main>
    </div>

    <footer class="border-top footer text-muted">
        <div class="container">
            &copy; @DateTime.Now.Year - My Application
        </div>
    </footer>
    <script src="~/lib/jquery/dist/jquery.min.js"></script>
    <script src="~/lib/bootstrap/dist/js/bootstrap.bundle.min.js"></script>
    <script src="~/js/site.js" asp-append-version="true"></script>
    @RenderSection("Scripts", required: false)
</body>
</html>

可能与 IdentityHostingStartup.cs 有关吗?

IdentityHostingStartup.cs

using System;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Identity.UI;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using MyApp.Areas.Identity.Data;
using MyApp.Data;

[assembly: HostingStartup(typeof(MyApp.Areas.Identity.IdentityHostingStartup))]
namespace MyApp.Areas.Identity

    public class IdentityHostingStartup : IHostingStartup
    
        public void Configure(IWebHostBuilder builder)
        
            builder.ConfigureServices((context, services) => 
                services.AddDbContext<MyAppAuthDbContext>(options =>
                    options.UseSqlServer(
                        context.Configuration.GetConnectionString("MyAppAuthDbContextConnection")));

                services.AddDefaultIdentity<MyAppUser>(options => options.SignIn.RequireConfirmedAccount = true)
                    .AddRoles<IdentityRole>()
                    .AddEntityFrameworkStores<MyAppAuthDbContext>();
            );
        
    

Startup.cs

public class Startup
    
        public Startup(IConfiguration configuration)
        
            Configuration = configuration;
        

        public IConfiguration Configuration  get; 


        public void ConfigureServices(IServiceCollection services)
        


           
           
            services.AddDbContext<DbContextSQLIdentity>(options => options.UseSqlServer(Configuration.GetConnectionString("SQLIdentDB")));


           

            services.AddTransient<IEmailSender, EmailSender>();
            services.Configure<AuthMessageSenderOptions>(Configuration);


            services.AddControllersWithViews().AddRazorRuntimeCompilation();
            
            services.AddRazorPages();

        
        

       
        public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
        
            if (env.IsDevelopment())
            
                app.UseDeveloperExceptionPage();
            
            else
            
                app.UseExceptionHandler("/Home/Error");
              
                app.UseHsts();
            
         
            app.UseStaticFiles();

            app.UseRouting();

            app.UseAuthentication();
            app.UseAuthorization();

            app.UseEndpoints(endpoints =>
            
                endpoints.MapControllerRoute(
                    name: "default",
                    pattern: "controller=Home/action=Index/id?");
                endpoints.MapRazorPages();
            );
        
    

【问题讨论】:

您登录的用户是否有关联的角色? 我无法进入登录屏幕,这是应用程序加载时出现的错误。我在 Home 控制器索引上有 [Authorize],它应该会提示返回登录屏幕。这是调试中发生的情况,但是当发布到服务器时,它会失败。 【参考方案1】:

我猜这行:

var rolesArray = userManger.GetRolesAsync(user).Result;

返回 null,因此使用 .Contains 的下一行将因 NRE 而失败。

这表明您的登录用户没有角色。

顺便说一句,在 Task 上调用 .Result 不是一种好的做法,有时会导致任务锁定。

【讨论】:

我还没到可以登录用户的阶段。我在主控制器索引上有 [Authorize],它会提示登录屏幕显示(即在调试中)。发布时,它在第一个障碍时失败并返回错误。感谢您对 .Result 的关注。那是来自复制/粘贴解决方案。 应用启动时,User.Identity.IsAuthenticated() 应该返回false,但看起来返回true,允许嵌套代码运行并导致错误。 我发现了问题!我需要在服务器上的 IIS 中禁用 Windows 身份验证并启用匿名身份验证。【参考方案2】:

我发现了问题!我需要在服务器上的 IIS 中禁用 Windows 身份验证并启用匿名身份验证。

【讨论】:

以上是关于ASP.NET Core MVC 身份功能在发布到服务器时不起作用的主要内容,如果未能解决你的问题,请参考以下文章

ASP.NET Core MVC:设置身份 cookie 过期

从 ASP.NET Core 1.1 MVC 迁移到 2.0 后,自定义 cookie 身份验证不起作用

Asp.Net Core 正确配置身份认证中间件

ASP.NET CORE MVC 身份用户和角色不起作用

从 ASP.NET MVC 迁移到 ASP.NET Core MVC

JWT 身份验证 ASP.NET Core MVC 应用程序