如何将用户重定向到外部登录页面并将 return 重定向到应用程序并获取访问令牌?

How to redirect a user to an external login page and return to app and get the access token?

我一直在尝试让 razor 页面和组件协同工作以实现简单的重定向。我遇到这个问题的原因是组件无法访问 HttpContext。还必须说我是Blazor的新手。

基本上,这就是我要实现的目标:

  1. 用户访问应用。他没有被授权,所以他被自动重定向到外部授权服务器。该应用包含 return url(例如 LoginCallback)

  2. auth 服务器对用户进行身份验证并将用户重定向回 LoginCallback。

  3. 在 LoginCallback 中,我需要获取令牌。必须注意,我使用的是 OpenIdConnect 并且 SaveTokens 是正确的。所以令牌应该存储在cookie中。在 page/component 我需要做额外的登录相关的事情。

  4. 完成额外的登录相关内容后,page/component 将自动重定向到主应用程序组件,(例如仪表板)

所以我现在有以下内容:

_Host.cshtml 没有动过。我更改了 app.razor 如下(为简洁起见被删减):

@inject NavigationManager navigationManager

<CascadingAuthenticationState>
    <Router AppAssembly="@typeof(Program).Assembly">
        <Found Context="routeData">
            <AuthorizeRouteView RouteData="@routeData" DefaultLayout="@typeof(MainLayout)">
                <NotAuthorized>
                    @{
                        var returnUrl = navigationManager.ToBaseRelativePath(navigationManager.Uri);
                        navigationManager.NavigateTo($"Login?redirectUri={returnUrl}", forceLoad: true);
                    }
                </NotAuthorized>
            </AuthorizeRouteView>
        </Found>
    </Router>
</CascadingAuthenticationState>

我有一个 login.cshtml,代码如下:

public class LoginModel : PageModel
{
    public async Task OnGet(string redirectUri)
    {
        await HttpContext.ChallengeAsync(OpenIdConnectDefaults.AuthenticationScheme, new AuthenticationProperties 
        { 
            RedirectUri = redirectUri,
            IsPersistent = true,
            ExpiresUtc = DateTimeOffset.UtcNow.AddHours(15)
        });
    }
}

我有一个 LoginCallback.razor,代码如下:

@layout LoginLayout
@page "/LoginCallback"

@inject NavigationManager navigationManager

@{
    navigationManager.NavigateTo("Dashboard", forceLoad: true);
}

@code {

}

我还有主登陆页面 Home.razor,它应该会自动重定向到登录页面,代码是:

@layout LoginLayout
@page "/"

@inject NavigationManager navigationManager
@inject IOptions<AppOptions> appOptions

<AuthorizeView>
    <Authorized>
        @{
            navigationManager.NavigateTo("Dashboard", forceLoad: true);
        }
    </Authorized>
    <NotAuthorized>
        @{
            var baseUri = navigationManager.BaseUri;
            var returnUrl = $"Login?redirectUri={baseUri}{appOptions.Value.LoginCallback}";

            navigationManager.NavigateTo($"Login?redirectUri={returnUrl}", forceLoad: true);
        }
    </NotAuthorized>
 </AuthorizeView>

最后我得到了 Dashboard.razor 以下内容(已删除标记):

@page "/Dashboard"
@attribute [Authorize]

通过上述,重定向 from/to 应用程序按预期运行。我只需要以下内容:

  1. 在 LoginCallback 中获取令牌(访问、ID 和刷新)。我宁愿有一个(范围?)服务,我可以在页面和组件中注入,这样我就可以轻松地检索令牌。

  2. 有时会发生在重定向发生之前短暂加载仪表板的情况。这必须解决。必须进行额外的测试。

  3. [Authorize]移动到_imports.razor并将[AllowAnonymous]添加到HomeLogin.

那么我将如何解决 (1)?

归结为您可以访问 HttpContext 的唯一位置,因此令牌位于 _Hosts.cshtml

Microsoft has docs how to go about this。但为了完整起见,我将包括主要步骤。


  • _Hosts.cshtml 中,检索令牌并将它们传递到组件世界,通过参数传递给 App.razor:
@{
    var tokens = new InitialTokenState
    {
        AccessToken = await HttpContext.GetTokenAsync("access_token"),
        RefreshToken = await HttpContext.GetTokenAsync("refresh_token")
    };
}
<app>
    <component type="typeof(App)" param-Tokens="tokens" />
</app>
  • App.razor 中,获取传递的令牌并将它们存储在预先注册(并注入)的 DI 服务中,现在可以注入并在整个应用程序中使用。
@inject MyTokenProvider TokenProvider
...
@code{
    [Parameter] public InitialTokenState Tokens { get; set; }

    protected override Task OnInitializedAsync()
    {
        TokenProvider.AccessToken = Tokens.AccessToken;
        TokenProvider.RefreshToken = Tokens.RefreshToken;
        return base.OnInitializedAsync();
    }
}
  • 为此,services.AddHttpClient(); 也必须在启动时注册。

您可以通过 HttpContextAccessor 访问 HttpContext

在 StartUp.cs 中的 HTTPClient 之后添加范围服务。

services.AddHttpClient();
services.AddHttpContextAccessor();

接下来,您需要做的就是在要重定向到的任何组件中注入 HttpContextAccessor。唯一的问题是重定向页面应该是匿名页面,您可以在其中设置默认身份验证。

HttpContextAccessor.HttpContext.User 将为您提供授权用户的用户声明。

Ivan-Mark Debono,我已经回答了你的问题...我的代码应该可以工作。

这是我的应用程序在身份验证之前的快照

及认证后

.