[英]How to check access_denied on client when using IdentityServer4?
我有一个登录页面,当用户单击“取消”按钮时我需要将他重定向到客户端应用程序上的拒绝页面。
内部登录操作:
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),或者是否有其他问题导致了该失败?
基本表单有 2 个按钮: login
和cancel
。 如果没有按下login
; 这是一个cancel
。
否则它是一个验证错误,您可以显示它。 在cancel
您应该重定向回有意义的页面。
您可以使用额外的参数重定向。 这些可以被获取并用于显示错误。 请记住,很多错误处理,例如无效的用户名/密码,都停留在 IdentityServer 端。
使用 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
值),而是可以简单地将返回 url 替换为 redirect_uri,自己添加错误参数。 这里的技巧是,由于 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>);
});
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.