【问题标题】:Cannot sign out the OpenIdConnect authentication of identityserver4 on ASP.NET Core 2 application无法在 ASP.NET Core 2 应用程序上注销 identityserver4 的 OpenIdConnect 身份验证
【发布时间】:2018-05-09 10:53:54
【问题描述】:

我的 Identity Server 正在使用 identityserver4 框架 (http://localhost:9000)。我在 Identity Server 上注册了客户端,如下所示。

clients.Add(
     new Client
     {
         ClientId = "customer.api",
         ClientName = "Customer services",
         AllowedGrantTypes = GrantTypes.HybridAndClientCredentials,
         RequireConsent = false,
         AllowAccessTokensViaBrowser = true,

         RedirectUris = { "http://localhost:60001/signin-oidc" },
         PostLogoutRedirectUris = { "http://localhost:60001/signout-callback-oidc" },
         ClientSecrets = new List<Secret>
         {
             new Secret("testsecret".Sha256())
         },
         AllowedScopes = new List<string>
         {
             IdentityServerConstants.StandardScopes.OpenId,
             IdentityServerConstants.StandardScopes.Profile,
             IdentityServerConstants.StandardScopes.Email,
             IdentityServerConstants.StandardScopes.OfflineAccess,
             "customerprivatelinesvn.api",                        
         },
         AllowOfflineAccess = true,
         AlwaysIncludeUserClaimsInIdToken = true,
         AllowedCorsOrigins = { "http://localhost:60001" }
     });  

这是我的客户端应用程序 (http://localhost:60001) 上的身份验证。

private void AddAuthentication(IServiceCollection services)
{
    JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Clear();

    services.AddAuthentication(options =>
    {
        options.DefaultAuthenticateScheme = "Cookies";
        options.DefaultChallengeScheme = "oidc";       
    })
    .AddCookie()
    .AddOpenIdConnect("oidc", options =>
    {
        Configuration.GetSection("OpenIdConnect").Bind(options);        
    });    
}    

"OpenIdConnect": {
    "SignInScheme": "Cookies",
    "Authority": "http://localhost:9000/",
    "RequireHttpsMetadata": false,
    "ClientId": "customer.api",
    "ClientSecret": "testsecret",
    "Scope": [ "customerprivatelinesvn.api", "offline_access" ],
    "CallbackPath": "/signin-oidc",
    "ResponseType": "code id_token token",
    "GetClaimsFromUserInfoEndpoint": true,
    "SaveTokens": true
  }

客户端应用的 HomeController

[Authorize]
public class HomeController : Controller
{
    public IActionResult Index()
    {
        return View();
    }    
}

这是用户登录后客户端应用程序的 Cookie。

我尝试执行如下退出操作

public class AccountController : Controller
{
    public async Task<IActionResult> Signout()
    {
        await HttpContext.SignOutAsync("Cookies");
        await HttpContext.SignOutAsync("oidc");

        return RedirectToAction("Index", "Home");                  
    }
}

但是当用户退出时,它不会调用身份服务器的 endsession 端点。我看fiddler的流量,没有对身份服务器的请求。

我的期望是当用户注销时,它会调用身份服务器的 endsession 端点并重定向到身份服务器的注销链接,如下所示。

我们可以通过调用 OwinContext 注销在 MVC 应用程序上轻松完成此操作

private void LogoutOwin(IOwinContext context)
        {
            context.Authentication.SignOut();
        }

但是注销方法在 ASP.NET Core 2 上不再起作用。

注意:我从 AJAX 帖子调用注销操作,因为我的客户端应用程序是 Angular 5 应用程序。

有谁知道如何在 ASP.NET Core 2 上正确实现注销?

非常感谢。

问候,

凯文

【问题讨论】:

    标签: c# asp.net-core-2.0 identityserver4


    【解决方案1】:

    .Net Core 3.1,使用AuthenticationProperties设置重定向url。

        public async Task Logout()
        {
            await HttpContext.SignOutAsync(CookieAuthenticationDefaults.AuthenticationScheme);
            await HttpContext.SignOutAsync(OpenIdConnectDefaults.AuthenticationScheme, new AuthenticationProperties { RedirectUri = "/Home/Logout-Complete" });
        }
    

    【讨论】:

      【解决方案2】:

      要允许注销,请使用以下注销操作:

      public async Task Logout()
      {
          await HttpContext.SignOutAsync("Cookies");
          await HttpContext.SignOutAsync("oidc");
      }
      

      这正是快速入门所说的使用 (http://docs.identityserver.io/en/release/quickstarts/3_interactive_login.html)。 你(和我)太聪明了。我查看了教程中的操作并认为“这不完整,它不会返回操作结果,让我们重定向回我的页面”。

      实际上,HttpContext.SignOutAsync("oidc"); 设置了一个默认的 ActionResult(即重定向到 OpenIdConnect 提供程序以完成注销)。通过使用 return RedirectToAction("Index", "Home"); 指定您自己的,您将覆盖它,因此永远不会发生注销操作。

      注销后重定向

      来自this answer,在注销完成后指定重定向 URL 的方式是使用 AuthenticationProperties

      public async Task Logout()
      {
         await context.SignOutAsync("Cookies");
         var prop = new AuthenticationProperties
         {
             RedirectUri = "/logout-complete"
         };
         // after signout this will redirect to your provided target
         await context.SignOutAsync("oidc", prop);
      }
      

      【讨论】:

      • 调用controller.SignOut 会生成一个SignOutResult 对象,然后可以从IActionResult 控制器操作中返回该对象。然后SignOutResult 类调用HttpContextExtensions.SignOutAsync。直接从控制器操作中调用 HttpContextExtensions.SignOutAsync 不是一个好主意。
      【解决方案3】:

      在 Net Core 2.0 上更改您的代码以使用枚举 CookieAuthenticationDefaults 和 OpenIdConnectDefaults

          services.AddAuthentication(options =>
              {
                  options.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme;
                  options.DefaultChallengeScheme = OpenIdConnectDefaults.AuthenticationScheme;
              })
              .AddCookie()
              .AddOpenIdConnect(SetOpenIdConnectOptions);
      
      
      private static void SetOpenIdConnectOptions(OpenIdConnectOptions options)
      {
          options.ClientId = "auAuthApp_implicit";
          options.Authority = "http://localhost:55379/";
      
          options.SignInScheme = "Cookies";
          options.RequireHttpsMetadata = false;
      
          options.SaveTokens = true;
          options.ResponseType = "id_token token";
          options.GetClaimsFromUserInfoEndpoint = true;
      
      }
      

      还有……

      public async Task<IActionResult> Logout()
      {
          await HttpContext.SignOutAsync(CookieAuthenticationDefaults.AuthenticationScheme);
          await HttpContext.SignOutAsync(OpenIdConnectDefaults.AuthenticationScheme);
      
          return RedirectToAction("Index", "Home");
      }
      

      【讨论】:

      • 我试过这个(似乎只是更改了身份验证方案的显示名称),但仍然遇到同样的问题
      【解决方案4】:

      我现在可以解决我的问题了。

      1) 返回 SignOutResult 将调用 endsession 端点。

      2) 更改 AJAX 帖子以提交表单。

      public class AccountController : Controller
      {
          public IActionResult Signout()
          {
              return new SignOutResult(new[] { "oidc", "Cookies" });            
          }
      }
      
      
      <form action="/Account/Signout" id="signoutForm" method="post" novalidate="novalidate">
          <ul class="nav navbar-nav navbar-right">
              <li><a href="javascript:document.getElementById('signoutForm').submit()">Sign out</a></li>
          </ul>
      </form>
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2021-02-13
        • 2019-10-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2018-05-13
        • 2010-11-07
        相关资源
        最近更新 更多