OWIN - 清除无效的 WSFederation cookie

OWIN - clear invalid WSFederation cookies

我使用 ADFS cookie 身份验证实现了一个 ASP.Net Web API 2 项目,并将其托管在 IIS 上。一切正常。

但是,一些客户端已经获得了旧的 cookie,这些 cookie 由于配置更改而变得无效。此类 cookie 在调用我的 API:

时会导致以下错误
[CryptographicException: Key not valid for use in specified state.
]
   System.Security.Cryptography.ProtectedData.Unprotect(Byte[] encryptedData, Byte[] optionalEntropy, DataProtectionScope scope) +447
   System.IdentityModel.ProtectedDataCookieTransform.Decode(Byte[] encoded) +49

[InvalidOperationException: ID1073: A CryptographicException occurred when attempting to decrypt the cookie using the ProtectedData API (see inner exception for details). If you are using IIS 7.5, this could be due to the loadUserProfile setting on the Application Pool being set to false. ]
   System.IdentityModel.ProtectedDataCookieTransform.Decode(Byte[] encoded) +329
   System.IdentityModel.Tokens.SessionSecurityTokenHandler.ApplyTransforms(Byte[] cookie, Boolean outbound) +167
   System.IdentityModel.Tokens.SessionSecurityTokenHandler.ReadToken(XmlReader reader, SecurityTokenResolver tokenResolver) +826
   System.IdentityModel.Tokens.SessionSecurityTokenHandler.ReadToken(Byte[] token, SecurityTokenResolver tokenResolver) +92
   System.IdentityModel.Services.SessionAuthenticationModule.ReadSessionTokenFromCookie(Byte[] sessionCookie) +569
   System.IdentityModel.Services.SessionAuthenticationModule.TryReadSessionTokenFromCookie(SessionSecurityToken& sessionToken) +306
   System.IdentityModel.Services.SessionAuthenticationModule.OnAuthenticateRequest(Object sender, EventArgs eventArgs) +159
   System.Web.SyncEventExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute() +142
   System.Web.HttpApplication.ExecuteStep(IExecutionStep step, Boolean& completedSynchronously) +92

显而易见的解决方法是清除 cookie。但是,以后我可能会再次更改 cookies 配置,所以我想自动清除 API.

中所有无效的 cookies

我尝试添加自定义 OWIN 中间件并覆盖 IExceptionHandler

这是我的 WIF 配置:

<system.identityModel>
  <identityConfiguration>
    <audienceUris>
      <add value="https://my.web-api.com" />
    </audienceUris>
    <issuerNameRegistry type="System.IdentityModel.Tokens.ValidatingIssuerNameRegistry, System.IdentityModel.Tokens.ValidatingIssuerNameRegistry">
      <authority name="ADFS">
        <keys>
          <add thumbprint="--a thumbprint--" />
        </keys>
        <validIssuers>
          <add name="http://my.adfs.com/adfs/services/trust" />
        </validIssuers>
      </authority>
    </issuerNameRegistry>
  </identityConfiguration>
</system.identityModel>
<system.identityModel.services>
  <federationConfiguration>
    <wsFederation issuer="https://my.adfs.com/adfs/ls" realm="https://my.web-api.com" requireHttps="true" passiveRedirectEnabled="false"
                  persistentCookiesOnPassiveRedirects="true" />
    <cookieHandler name="my.cookie" path="/" persistentSessionLifetime="7.0:0:0" />
    <serviceCertificate>
      <certificateReference x509FindType="FindBySubjectName" findValue="my.web-api.com" storeLocation="LocalMachine" storeName="My" />
    </serviceCertificate>
  </federationConfiguration>
</system.identityModel.services>

这是我的 Startup class:

public class Startup
{
    public void Configuration(IAppBuilder appBuilder)
    {
        var config = new HttpConfiguration();

        config.Services.Replace(typeof(IExceptionHandler), new CryptographicExceptionHandler());
        WebApiConfig.Register(config);
        appBuilder.UseWebApi(config);
        appBuilder.Use<ClearInvalidCookiesMiddleware>();
    }
}

无论 CryptographicExceptionHandlerClearInvalidCookiesMiddleware 里面有什么,它们的代码都不会被调用,我收到 500 错误。我还尝试在 UseWebApi.

之前移动 ClearInvalidCookiesMiddleware

我的目标是添加 Set-Cookie 响应 header 以清除无效 cookie 和 return 401 或重定向。

在这种情况下,如何让 OWIN 自定义响应?

该解决方案似乎覆盖了 SessionAuthenticationModule.OnAuthenticateRequest 并在出现异常时调用 SignOut()

class ClearInvalidCookiesSessionAuthenticationModule : SessionAuthenticationModule
{
    protected override void OnAuthenticateRequest(object sender, EventArgs eventArgs)
    {
        try
        {
            base.OnAuthenticateRequest(sender, eventArgs);
        }
        catch(InvalidOperationException ex) when (ex.InnerException is CryptographicException) // Invalid cookie signing key
        {
            SignOut();
        }
        catch(System.Xml.XmlException) // Invalid cookie structure
        {
            SignOut();
        }
    }
}

要使用继承的 class 而不是默认的,应该在 Web.config 中插入以下行:

<system.webServer>
  <modules ...>
    <!-- Insert the line below or replace existing SessionAuthenticationModule -->
    <add name="SessionAuthenticationModule" preCondition="managedHandler"
         type="MyNamespace.ClearInvalidCookiesSessionAuthenticationModule, MyAssembly" />
    ...
  </modules>
...
</system.webServer>