【问题标题】:Change routing in ASP.NET Core Identity UI?在 ASP.NET Core Identity UI 中更改路由?
【发布时间】:2018-06-04 13:45:47
【问题描述】:

我正在使用自 ASP.NET Core 2.1 发布以来可用的新 Identity UI 包。使用新生成的 MVC 项目,这里有一些可用的页面 URL:

/Home/About
/Home/Contact
/Identity/Account/Login
/Identity/Account/Register

如何配置路由以从 URL 中删除 /Identity/ 部分?

【问题讨论】:

  • 伙计们,ASP.NET Core 2.0 具有新的语法糖 @page "/Some/Other/Path",它使您能够删除“/Identity”或“/Identity/Account”。请参阅 docs.microsoft.com/en-us/aspnet/core/?view=aspnetcore-2.0 以获取参考:“Razor Pages 使以页面为中心的场景编码变得更轻松、更高效”。 BlackTigerX 应该是一个可接受的答案。
  • 好答案@page "/some/path"
  • @AntonLyhin:链接失效了。

标签: c# asp.net-core asp.net-core-identity


【解决方案1】:

看起来这还不可能。看源码,很明显Area名称是hardcoded in IdentityDefaultUIConfigureOptions<TUser>

private const string IdentityUIDefaultAreaName = "Identity";

这在少数地方使用,包括 configuring Razor Pages 时。例如:

options.Conventions.AuthorizeAreaFolder(IdentityUIDefaultAreaName, "/Account/Manage");

还有configuring the Cookies authentication。例如:

options.LoginPath = $"/{IdentityUIDefaultAreaName}/Account/Login";

值得注意的是,IdentityDefaultUIConfigureOptions<TUser> 本身是受保护的,因此似乎不存在覆盖选项的能力。

我已经打开了Github issue,看看我们是否可以从项目本身的参与者那里获得反馈。


2018-06-12 更新

来自 ASP.NET Core Identity 团队的 Javier Calvarro Nelson 在我提出的Github issue 中提供了一些有价值的反馈,可以总结如下:

Identity UI 位于一个区域的主要原因是尽量减少对您的应用的影响,并在您的应用代码和 Identity 代码之间提供清晰的分隔。

当想要自定义 URL 时,Javier 建议使用以下选项之一:

  • 使用默认 UI 的脚手架元素并自行进行所有必要的自定义。
  • 使用将旧路由指向新路由的重定向规则。
  • 根本不要使用默认用户界面。

尽管不支持且不推荐,Javier 还指出可能使用自定义IPageApplicationModelConvention 来覆盖网址。但是,如果您错过了,这是不支持且不推荐


2018-06-27 更新

official documentation 现已更新,以更好地解释上述 URL 更改。

【讨论】:

  • AFAIK,脚手架本质上只是视图,而不是控制器,因此就行为/路由而言,脚手架 Identity 并没有真正打开任何新选项,而不是 .AddDefaultUi。仍然使用 IdentityUi 的唯一选项是添加映射规则来解决此问题;见UnknownQuestion's response here
  • 拥有两个内容相同的域会对您的 SEO 产生负面影响。指示爬虫不要索引 /identity/ User-agent: * Disallow: /identity/ 并使用带有永久重定向到新 url 的重写中间件。
【解决方案2】:

最简单的做法是将Pages文件夹从Areas/Identity拖出到主项目中 请记住,@page 指令(在 .cshtml 中)使视图可以直接访问“页面”下的任何内容(页面被转换为操作) 如果您想更改默认值,您还可以将 Account 文件夹重命名为其他名称 /帐户/登录等页面

@page 指令也可用于指定自定义路径,例如: @page "/登录"

通过导航到 /Login 直接访问登录页面

【讨论】:

    【解决方案3】:

    在你的 startup.cs 中你可以改变:

    services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1);
    

    与:

        services.AddMvc().AddRazorPagesOptions(o => o.Conventions.AddAreaFolderRouteModelConvention("Identity", "/Account/", model =>
        {
            foreach (var selector in model.Selectors)
            {
                var attributeRouteModel = selector.AttributeRouteModel;
                attributeRouteModel.Order = -1;
                attributeRouteModel.Template = attributeRouteModel.Template.Remove(0, "Identity".Length);
            }
        })
    ).SetCompatibilityVersion(CompatibilityVersion.Version_2_1);
    

    它将路由:

    /Identity/Account/Login/Account/Login

    /Identity/Account/Register/Account/Register

    等等……

    要处理 ReturnUrl,您可以创建一个新的 Action:

        [Route("Identity/Account/Login")]
        public IActionResult LoginRedirect(string ReturnUrl)
        {
            return Redirect("/Account/Login?ReturnUrl=" + ReturnUrl);
        }
    

    【讨论】:

      【解决方案4】:

      根据David 的回答,我能够摆脱登录页面路径中的“身份/帐户”。我正在开发一个 Asp.net 3.1 应用程序并使用脚手架的身份页面。

      我已经更改了 login.cshtml 页面中的@page 指令,如下所示,并更改了 startup.cs 文件,如下所示。

      login.cshtml

      @page "/Login"
      

      startup.cs

      services.ConfigureApplicationCookie(options =>
              {
                  // httponly cookie
                  options.Cookie.HttpOnly = true;
                  options.Cookie.Name = "application.Identity";
                  ***options.LoginPath = "/Login";*** // earlier it was options.LoginPath = "/Identity/Account/Login";
                  options.AccessDeniedPath = "/Error/Index/403";
                  options.ExpireTimeSpan = TimeSpan.FromMinutes(20);
                  options.SlidingExpiration = true;
              });
      

      另外请注意,如果您在应用程序的任何位置使用“/Identity/Account/Login”,您可能还需要更改它们。此外,如果您有相同的 MVC 路由,则必须更加小心并相应地处理。

      【讨论】:

        【解决方案5】:

        URL Rewriting Middleware 可能是一个解决方案:

        var options = new RewriteOptions()
                .AddRewrite(@"^Account/(.*)", "Identity/Account/$1", skipRemainingRules: true);
                app.UseRewriter(options);
        

        【讨论】:

          【解决方案6】:

          就路由而言,它在 Web 框架中的标准是固定身份验证 URL,Django 做同样的事情。以下是如何根据自己的喜好自定义视图,因此我们不会从路由中删除 /Identity/,而是告诉 Identity 不要包含他们的视图并提供到我们的路由。

          转到Startup.cs

          // USE METHOD WITH LESS DEFAULTS
          //
          // services.AddDefaultIdentity<IdentityUser>()
          //    .AddEntityFrameworkStores<ApplicationDbContext>();
          services.AddIdentity<IdentityUser, IdentityRole>(options => options.Stores.MaxLengthForKeys = 128)
              .AddEntityFrameworkStores<ApplicationDbContext>()
              .AddDefaultTokenProviders();
          //
          // ADD A ROUTE BELOW THE DEFAULT ROUTE
          //
          routes.MapRoute(
                      name: "identity",
                      template: "Identity/{controller=Account}/{action=Register}/{id?}");
          

          现在我们已经设置好了除了视图之外的所有东西,所以我们需要像通常在 mvc 中那样做一个路由到它。做一个帐户控制器。将 Index() 更改为 Register()。在名为 Account 的视图中创建一个文件夹。添加文件Register.cshtml,这里是原始html,根据你的需要定制:

          <div class="container body-content">
          
          
          <h2>Register</h2>
          
          <div class="row">
              <div class="col-md-4">
                  <form method="post" action="/Identity/Account/Register" novalidate="novalidate">
                      <h4>Create a new account.</h4>
                      <hr>
                      <div class="text-danger validation-summary-valid" data-valmsg-summary="true"><ul><li style="display:none"></li>
          </ul></div>
                      <div class="form-group">
                          <label for="Input_Email">Email</label>
                          <input class="form-control" type="email" data-val="true" data-val-email="The Email field is not a valid e-mail address." data-val-required="The Email field is required." id="Input_Email" name="Input.Email" value="">
                          <span class="text-danger field-validation-valid" data-valmsg-for="Input.Email" data-valmsg-replace="true"></span>
                      </div>
                      <div class="form-group">
                          <label for="Input_Password">Password</label>
                          <input class="form-control" type="password" data-val="true" data-val-length="The Password must be at least 6 and at max 100 characters long." data-val-length-max="100" data-val-length-min="6" data-val-required="The Password field is required." id="Input_Password" name="Input.Password">
                          <span class="text-danger field-validation-valid" data-valmsg-for="Input.Password" data-valmsg-replace="true"></span>
                      </div>
                      <div class="form-group">
                          <label for="Input_ConfirmPassword">Confirm password</label>
                          <input class="form-control" type="password" data-val="true" data-val-equalto="The password and confirmation password do not match." data-val-equalto-other="*.Password" id="Input_ConfirmPassword" name="Input.ConfirmPassword">
                          <span class="text-danger field-validation-valid" data-valmsg-for="Input.ConfirmPassword" data-valmsg-replace="true"></span>
                      </div>
                      <button type="submit" class="btn btn-default">Register</button>
                  <input name="__RequestVerificationToken" type="hidden" value="CfDJ8IWbPHM_NTJDv_7HGewWzbbRveP09yQOznYdTWL2aN5X_4_eVbNE1w8D_qz7zegloVtdAhuVOJbJLQo0ja73FB3PgYycyGpn-DfX3fJqv4Cx8ns6Ygh6M7nMxV0eozO7hoDxUfPwrIJb2RcFtyzhPpMevZ4P0M8aVyBP55SP-5C4l23dCtDXXUOAY_YLwt67dw"></form>
              </div>
          </div>
          
          
                  <hr>
                  <footer>
                      <p>© 2018 - SqlServerApp</p>
                  </footer>
              </div> 
          

          【讨论】:

            【解决方案7】:

            从 .net core 3.1 和 2021 开始(我知道有 .net 5,有罪),虽然它通常不会删除路径的“身份”部分,但您可以一一映射生成的剃须刀页面到所需的路线:

            在页眉中,默认只有@page,所以把它改成你想要的路由@page "/login"

            请注意,如果某些 MVC 路由匹配路由 /login,它将使用相应的控制器操作。如果您不希望 MVC 路由覆盖剃刀页面路由,我建议将 endpoints.MapRazorPages(); 移动到 Startup.csConfigure 方法中,首先是所有(或至少一些)MVC 路由。

            【讨论】:

              猜你喜欢
              • 2016-10-22
              • 1970-01-01
              • 2017-01-08
              • 2021-08-21
              • 2018-01-30
              • 2019-05-01
              • 2020-03-23
              • 2019-05-27
              • 1970-01-01
              相关资源
              最近更新 更多