我有一个登录页面,当用户单击“取消”按钮以将他重定向到客户端应用程序上的拒绝访问页面时,我需要。
内部登录操作:
if (button != "login")
{
// the user clicked the "cancel" button
var context = await interaction.GetAuthorizationContextAsync(model.ReturnUrl);
if (context != null)
{
// if the user cancels, send a result back into IdentityServer as if they
// denied the consent (even if this client does not require consent).
// this will send back an access denied OIDC error response to the client.
await interaction.GrantConsentAsync(context, ConsentResponse.Denied);
// we can trust model.ReturnUrl since GetAuthorizationContextAsync returned non-null
return Redirect(model.ReturnUrl);
}
}
在客户端(MVC)上,我配置了以下事件:
options.Events = new OpenIdConnectEvents
{
OnRemoteFailure = context =>
{
// here it's returned as 200 ok in case I denied
// consent should'nt be 401 access denined??
var statusCode=context.Response.StatusCode;
context.Response.Redirect("/");
context.HandleResponse();
return Task.FromResult(0);
}
};
但是我的问题是:我怎么知道IdentityServer4因用户单击“取消”按钮(access_denied)而失败,或者是否有其他问题导致该失败?
答案 0 :(得分:1)
使用IdentityServer4时如何检查客户端上的access_denied?
经过检查,事件的context.Failure.Data
是ListDictionaryInternal
的一种,其中包含您可能正在寻找的条目:
error
error_description
error_uri
。 因此,通过使用context.Failure.Data["error"]
,您可以获得所需的“ access_denied”值。
以Identity Server 4的演示代码为例,如果我们转到Login Post Account Controller操作,那么您感兴趣的部分就是处理按下取消按钮的部分:
// check if we are in the context of an authorization request
var context = await _interaction.GetAuthorizationContextAsync(model.ReturnUrl);
// the user clicked the "cancel" button
if (button != "login")
{
if (context != null)
{
// RATHER THAN USING THE ORIGINAL STRATEGY:
//await _interaction.GrantConsentAsync(context, ConsentResponse.Denied);
// ...MANUALLY BUILD THE RETURN URL YOURSELF
// THEN REDIRECT TO THAT:
model.ReturnUrl = BuildCancelReturnUrl(context);
if (await _clientStore.IsPkceClientAsync(context.ClientId))
{
return View("Redirect", new RedirectViewModel { RedirectUrl = model.ReturnUrl });
}
return Redirect(model.ReturnUrl);
}
else
{
// since we don't have a valid context, then we just go back to the home page
return Redirect("~/");
}
}
如您所见,与其使用对GrantConsentAsync
的调用来响应access_denied
代码(其中不包含任何error_description
或error_uri
值),您可以简单地将return url替换为redirect_uri,自己添加error参数。这里的技巧是,由于error_description和error_uri参数是完全可选的,因此您可以利用它并传递有意义的信息,以便每个客户端都知道由于用户取消了表单而拒绝了该访问。然后,在重定向中使用该返回URL。
这是一个有关如何“重建”返回URL的示例。您可能具有以下功能:
private string BuildCancelReturnUrl(AuthorizationRequest context)
{
var RedirectUri = new UriBuilder(context.RedirectUri);
var Query = HttpUtility.ParseQueryString(string.Empty);
Query.Add("error", "access_denied");
Query.Add("error_description", "some_meaningful_code_here");
// The state IS MEGA IMPORTANT:
Query.Add("state", context.Parameters["state"]);
RedirectUri.Query = Query.ToString();
return RedirectUri.ToString();
}
// Use like: model.ReturnUrl = BuildCancelReturnUrl(context);
// See above extract from Identity Server's demo code
因此,在客户端,您可以创建如下扩展名:
public static class OpenIdConnectOptionsExtensions {
public static OpenIdConnectOptions UseRedirectionOnLoginCancel(
this OpenIdConnectOptions options
, string RedirectTo = "/")
{
options.Events.OnAccessDenied = context =>
{
NameValueCollection RequestQuery = HttpUtility.ParseQueryString(context.Request.QueryString.Value);
string descriptionField = "error_description";
string cancelledCode = "your_meaningful_description_code_here";
bool descriptionIncluded = RequestQuery.AllKeys.Contains(descriptionField);
if (descriptionIncluded && RequestQuery[errorDescriptionField].Equals(cancelledCode))
{
context.Response.Redirect(RedirectTo);
context.HandleResponse();
}
return Task.CompletedTask;
};
return options;
}
}
最后,可以将每个客户端配置为重定向到您在Startup.cs
中指定的位置:
services.AddOpenIdConnect(<challenge_name>, config =>
{
// ...
config.UseRedirectionOnLoginCancel(<final path to redirect to>);
});
答案 1 :(得分:0)
基本表单具有2个按钮:login
和cancel
。如果未按下login
;这是cancel
。
否则,它是一个验证错误,您可以显示它。在cancel
上,您应该重定向回到有意义的页面。
您可以使用其他参数进行重定向。这些可以被获取并用于显示错误。请记住,很多错误处理(例如无效的用户名/密码)都位于IdentityServer端。