如何将用户重定向到外部登录页面并将 return 重定向到应用程序并获取访问令牌?
How to redirect a user to an external login page and return to app and get the access token?
我一直在尝试让 razor 页面和组件协同工作以实现简单的重定向。我遇到这个问题的原因是组件无法访问 HttpContext
。还必须说我是Blazor的新手。
基本上,这就是我要实现的目标:
用户访问应用。他没有被授权,所以他被自动重定向到外部授权服务器。该应用包含 return url(例如 LoginCallback)
auth 服务器对用户进行身份验证并将用户重定向回 LoginCallback。
在 LoginCallback 中,我需要获取令牌。必须注意,我使用的是 OpenIdConnect
并且 SaveTokens
是正确的。所以令牌应该存储在cookie中。在 page/component 我需要做额外的登录相关的事情。
完成额外的登录相关内容后,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 应用程序按预期运行。我只需要以下内容:
在 LoginCallback 中获取令牌(访问、ID 和刷新)。我宁愿有一个(范围?)服务,我可以在页面和组件中注入,这样我就可以轻松地检索令牌。
有时会发生在重定向发生之前短暂加载仪表板的情况。这必须解决。必须进行额外的测试。
将[Authorize]
移动到_imports.razor
并将[AllowAnonymous]
添加到Home
和Login
.
那么我将如何解决 (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,我已经回答了你的问题...我的代码应该可以工作。
这是我的应用程序在身份验证之前的快照
及认证后
.
我一直在尝试让 razor 页面和组件协同工作以实现简单的重定向。我遇到这个问题的原因是组件无法访问 HttpContext
。还必须说我是Blazor的新手。
基本上,这就是我要实现的目标:
用户访问应用。他没有被授权,所以他被自动重定向到外部授权服务器。该应用包含 return url(例如 LoginCallback)
auth 服务器对用户进行身份验证并将用户重定向回 LoginCallback。
在 LoginCallback 中,我需要获取令牌。必须注意,我使用的是
OpenIdConnect
并且SaveTokens
是正确的。所以令牌应该存储在cookie中。在 page/component 我需要做额外的登录相关的事情。完成额外的登录相关内容后,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 应用程序按预期运行。我只需要以下内容:
在 LoginCallback 中获取令牌(访问、ID 和刷新)。我宁愿有一个(范围?)服务,我可以在页面和组件中注入,这样我就可以轻松地检索令牌。
有时会发生在重定向发生之前短暂加载仪表板的情况。这必须解决。必须进行额外的测试。
将
[Authorize]
移动到_imports.razor
并将[AllowAnonymous]
添加到Home
和Login
.
那么我将如何解决 (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,我已经回答了你的问题...我的代码应该可以工作。
这是我的应用程序在身份验证之前的快照
及认证后