如何将 returnUrl 传递到 Blazor Server 应用程序中的登录页面?

Posted

技术标签:

【中文标题】如何将 returnUrl 传递到 Blazor Server 应用程序中的登录页面?【英文标题】:How do I pass returnUrl to Login page in Blazor Server application? 【发布时间】:2020-04-30 20:07:18 【问题描述】:

我有一个简单的 Blazor 服务器应用程序,其身份使用个人身份验证。我从 VS 2019 标准 dotnet new 模板创建了应用程序。

在应用程序的某些部分,我想将用户引导到登录页面,同时传递returnUrl 参数。我尝试了以下代码变体来传递此参数(counter 是我要返回的页面):

NavigationManager.NavigateTo("Identity/Account/Login?returnUrl=counter", forceLoad: true);
NavigationManager.NavigateTo("Identity/Account/Login?returnUrl='/counter'", forceLoad: true);
NavigationManager.NavigateTo("Identity/Account/Login?returnUrl='./counter'", forceLoad: true);
NavigationManager.NavigateTo("Identity/Account/Login?returnUrl='~/counter'", forceLoad: true);

但是,通过所有这些,我收到一条错误消息,指出“URI 不是本地的”。错误信息是:

"InvalidOperationException: 提供的 URL 不是本地的。带有 如果绝对路径没有 主机/权限部分。使用虚拟路径 ('~/') 的 URL 也是本地的。”

在这种情况下,谁能建议 returnUrl 参数的正确格式?有关更多背景信息,我正在遵循 @iambacon 的建议(感谢 Colin!),在他的 blog post 中关于重定向到 Blazor 应用程序的登录页面。这是一篇很棒的文章,完成了我想要的部分内容:当用户未通过身份验证时重定向到登录。我只想添加额外的功能,即在身份验证完成后返回该 URL。

【问题讨论】:

错误是在 NavigateTo() 上还是在您再次离开登录页面时出现? 【参考方案1】:

“URI 不是本地的”。

要解决这个问题...

执行以下操作:

    在 Pages 文件夹中创建一个名为 RedirectToLogin 的组件,代码如下:

RedirectToLogin.razor

@inject NavigationManager NavigationManager

@code
  [Parameter]
  public string ReturnUrl get; set;
  protected override  void OnInitialized()
  
        ReturnUrl = "~/" + ReturnUrl;
        NavigationManager.NavigateTo($"Identity/Account/Login?returnUrl=ReturnUrl", 
           forceLoad:true);
  

打开 App.razor 并将以下代码添加到 AuthorizeRouteView.NotAuthorized

<NotAuthorized>
@
    var returnUrl = 
    NavigationManager.ToBaseRelativePath(NavigationManager.Uri);
    <RedirectToLogin ReturnUrl="@returnUrl"/>
    
 
</NotAuthorized>

同样在 App 组件的顶部注入 NavigationManager,如下所示:

@inject NavigationManager NavigationManager

为了测试这一点,在 Fetchdata(或 Counter,如果你喜欢)组件页面的顶部添加 Authorize 属性的 @attribute 指令,如下所示:@attribute [Authorize] 当未经身份验证的用户尝试访问 Fetchdata 页面时,执行 AuthorizeRouteView.NotAuthorized 委托属性,并渲染 RedirectToLogin 组件,并将其参数属性设置为当前 url。

更新

以下添加是为你的App添加登录和注销按钮...

    在 Shared 文件夹中创建一个名为 LoginDisplay.razor 的组件,并在其中添加以下代码:
     <AuthorizeView>
      <Authorized>
        <a href="Identity/Account/Manage">Hello, 
        @context.User.Identity.Name!</a>
        <form method="post" action="Identity/Account/LogOut">
            <button type="submit" class="nav-link btn btn-link">Log 
        out</button>
        </form>
      </Authorized>
         <NotAuthorized>
            <a href="Identity/Account/Register">Register</a>
            <a href="Identity/Account/Login">Log in</a>
         </NotAuthorized>
      </AuthorizeView>

在 MainLayout 组件中添加 LoginDisplay 元素,如下所示:

<div class="top-row px-4 auth">
    <LoginDisplay />
    <a href="https://docs.microsoft.com/aspnet/" 
         target="_blank">About</a>
</div>

运行您的应用并测试登录和注销按钮...

【讨论】:

感谢您的建议。我曾计划过类似的设计。我实现了你所有的代码,现在我得到了同样的错误。在 Login.cshtml.cs 代码的断点处,我可以看到 returnUrl 设置为“fetchData”。我不明白为什么它认为这是一条非本地路径。 更新:我发现如果我单击应用程序中的 fetchData 链接,我会收到“URI 不是本地”错误。但是,如果我改为将 url 编辑为 /fetchData 路径,则会出现不同的错误。断点位于 RedirectToLogin 组件内部的 .NavigateTo 方法处。错误消息是“Microsoft.AspNetCore.Authorization.DefaultAuthorizationService:信息:授权失败。抛出的异常:Microsoft.AspNetCore.Components.Server.dll 中的'Microsoft.AspNetCore.Components.NavigationException'”没有更多详细信息。 对不起,我很困惑。你是说 url 不是本地的,但你也说它可以这样做。如果 returnUrl ("fetchData") 不是本地的,为什么您的解决方案会起作用? 复制:dotnet new blazor --auth 个人。将@attribute [Authorize] 添加到/fetchdata 页面,并将您推荐的代码添加到App.razor。我没有对默认的 VS 2019 模板进行其他更改。运行app,注册账号,进入首页,点击FetchData,登录,会看到“URL is not local error”。 "输入登录凭据后" 这是您未能提供的关键信息...

以上是关于如何将 returnUrl 传递到 Blazor Server 应用程序中的登录页面?的主要内容,如果未能解决你的问题,请参考以下文章

如何将可操作的控制字符从 JSON 文本元素传递到 razor 组件 Blazor 变量

如何将 URL 输入参数值传递给 Blazor 页面?

Blazor 将数据 @typeparam 传递给参数?

在 Blazor 中将值从子组件传递到父页面的良好做法?

登录重定向后如何传递用户名?

Blazor oauth2 被 CORS 阻止