Asp.net core mvc 使用OpenIDConnect时如何注销ClaimsEntity用户

Asp.net core mvc 使用OpenIDConnect时如何注销ClaimsEntity用户,asp.net-core-mvc,asp.net-core-2.0,identityserver4,openid-connect,identityserver3,Asp.net Core Mvc,Asp.net Core 2.0,Identityserver4,Openid Connect,Identityserver3,我有一个使用OpenIDConnect身份验证的ASP.NET核心应用程序。在OnTokenValidated事件中,我检查Authenticated用户是否存在于我的应用程序的数据库中,如果不存在,我将抛出UnauthorizedAccessException 请注意,在OnTokenValidated事件中,如果应用程序的数据库中存在用户,我将创建新身份,否则我将保留已验证用户的身份 public class Startup { private readonly ILogger<

我有一个使用OpenIDConnect身份验证的ASP.NET核心应用程序。在
OnTokenValidated
事件中,我检查
Authenticated
用户是否存在于我的应用程序的数据库中,如果不存在,我将抛出
UnauthorizedAccessException

请注意,在
OnTokenValidated
事件中,如果应用程序的数据库中存在用户,我将创建新身份,否则我将保留已验证用户的身份

public class Startup
{
    private readonly ILogger<Startup> _logger;
    public IConfiguration Configuration { get; }
    private IHostingEnvironment _environment { get; }

    public Startup(IConfiguration configuration, IHostingEnvironment env, ILogger<Startup> logger)
    {
        Configuration = configuration;
        _environment = env;
        _logger = logger;
    }

    
    public void ConfigureServices(IServiceCollection services)
    {
        services.AddAuthentication(options =>
        {
            options.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme;
            options.DefaultChallengeScheme = OpenIdConnectDefaults.AuthenticationScheme;
        })
         .AddCookie(CookieAuthenticationDefaults.AuthenticationScheme, options =>
         {
             options.LoginPath = "/Home";
             options.AccessDeniedPath = "/Account/Forbidden";
             options.Cookie = new CookieBuilder()
             {
                 Name = "myCookie",
                 HttpOnly = true,
             };
             options.SlidingExpiration = true;
         })
         .AddOpenIdConnect(OpenIdConnectDefaults.AuthenticationScheme, options =>
         {
             //options.ForwardChallenge                
             options.Authority = configuration["IdentityOptions:Authority"];
             options.ClientId = configuration["IdentityOptions:ClientID"];
             options.ResponseType = "id_token";
             options.CallbackPath = "/Home";
             options.SignInScheme = CookieAuthenticationDefaults.AuthenticationScheme; //tells cookies scheme to persist user's identity in cookie.
             options.SignOutScheme = CookieAuthenticationDefaults.AuthenticationScheme;//tells cookies scheme to remove persisted cookie
             options.Scope.Add(OpenIdConnectScope.Email);
             
             options.Events = new OpenIdConnectEvents()
             {
                 OnTokenValidated = async context =>
                 {
                     var emailClaim = context.Principal.Claims.SingleOrDefault(x => x.Type == ClaimTypes.Email);
                     
                    // check if user exists in client applications db
                     CompanyUser cu = null;
                     using (var serviceProvider = services.BuildServiceProvider())
                     {
                         using (var serviceScope = serviceProvider.CreateScope())
                         {
                             using (var accountService = serviceScope.ServiceProvider.GetService<IAccountService>())
                             {
                                 cu = await accountService.Authorize(emailClaim.Value);
                             }
                         }
                     }

                     if (cu == null)
                     {
                         // context.Principal.Identity.IsAuthenticated is true here
                         
                         throw new UnauthorizedAccessException(string.Format("Could not find user for login '{0}' ", emailClaim.Value));
                     }

                     //We will create new identity to store only required claims.
                     var newIdentity = new ClaimsIdentity(context.Principal.Identity.AuthenticationType);

                     // keep the id_token for logout 
                     newIdentity.AddClaim(new Claim(IdentityClaimTypes.IdToken, context.ProtocolMessage.IdToken));

                     // add email claim
                     newIdentity.AddClaim(emailClaim);                         
                     
                     context.Properties.IsPersistent = true;
                     context.Properties.ExpiresUtc = DateTime.UtcNow.AddHours(3);

                     // overwrite existing authentication ticket
                     context.Principal = new ClaimsPrincipal(newIdentity);
                 },                     
                 OnRedirectToIdentityProviderForSignOut = async context =>
                 {
                     var idTokenHint = context.HttpContext?.User?.FindFirst("id_token");
                     if (idTokenHint != null)
                         context.ProtocolMessage.IdTokenHint = idTokenHint.Value;
                     await Task.FromResult(0);
                 },
                 OnRemoteFailure = async context =>
                 {  
                     //WHY context.HttpContext.User.Identity.IsAuthenticated is false here??
                     if (context.Failure is UnauthorizedAccessException)
                     {
                         context.Response.Redirect("/Account/AccessDenied");
                     }
                     else
                     {
                         context.Response.Redirect("/Account/Error");
                     }
                     context.HandleResponse();
                     await Task.FromResult(0);
                 }
             };
         });
    }
    

但是,在
OnTokenValidated
事件
context.HttpContext.User.Identity.IsAuthenticated
中,它为false,因此不起作用。

一个常见错误是执行响应。在注销方法调用后重定向,这听起来很明显。但不幸的是,这不起作用。注销方法创建它们自己的重定向响应,当您执行重定向时,您将“覆盖”这些重定向

实现这一点的正确方法是不返回任何内容,并让Signout方法处理重定向:

    public async Task DoLogout()
    {
        await HttpContext.SignOutAsync(CookieAuthenticationDefaults.AuthenticationScheme);
        await HttpContext.SignOutAsync(OpenIdConnectDefaults.AuthenticationScheme);
    }
要重定向到其他Url,您可以尝试:

        await HttpContext.SignOutAsync(OpenIdConnectDefaults.AuthenticationScheme, new AuthenticationProperties( )
        {
            RedirectUri = "alternativeUrl"
        });

我尝试了这个,但这会将用户重定向到identity server的注销页面。我希望用户转到拒绝访问页面。我尝试了
public async Task AccessDenied(){wait-HttpContext.SignOutAsync(CookieAuthenticationDefaults.AuthenticationScheme);wait-HttpContext.SignOutAsync(OpenIdConnectDefaults.AuthenticationScheme);return View(“AccessDenied”);}
未工作,因此未被重定向。可能是我问错了问题。我开始了一条新的思路,澄清你的问题总是很好的。但是,为什么不在两个签出方法上设置AuthenticationProperties{redirectUri}?或者尝试更改它们的顺序?如果您无法使其正常工作,您可以作为黑客随时清除本地会话cookie以在本地注销用户。您对我的答案满意还是缺少什么?如果没有,请将我的答案标记为已接受。
        await HttpContext.SignOutAsync(OpenIdConnectDefaults.AuthenticationScheme, new AuthenticationProperties( )
        {
            RedirectUri = "alternativeUrl"
        });