OWIN自托管CookieAuthentication&安培;传统的.NET 4.0应用程序/的FormsAuthenticationTicket [英] OWIN Self-Host CookieAuthentication & Legacy .NET 4.0 Application / FormsAuthenticationTicket

查看:345
本文介绍了OWIN自托管CookieAuthentication&安培;传统的.NET 4.0应用程序/的FormsAuthenticationTicket的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有两个限界上下文的:


  1. ASP.NET 4.0 MVC / WebForms的应用

  2. OWIN自托管瓦特/的ASP.NET Web API 2

前者是现有成熟的产品,但是,它的缺乏架构(SmartUI)已导致一个难以维持codeBase的与可扩展性和可扩展性的担忧现在更离谱可见。

The former is an existing well-established product, however, its lack of architecture (SmartUI) has led to an difficult-to-maintain codebase with concerns of extensibility and scalability now more glaringly visible.

我们正在反复通过引入新的后端应用程序解决这一问题 - 通过OWIN /服务的WebAPI可曝光

We are iteratively addressing this issue by introducing a new backend application - exposable via OWIN/WebAPI services.

目前我们只希望利用新的应用Cookie身份验证。本来,我认为这将是使用基于现有的FormsAuthenticationTicket cookie认证/验证变得轻而易举。显然,这是不正确的。

Currently we're only looking to leverage cookie authentication in the new application. Originally, I thought it would be a breeze to use existing cookie auth/validation based upon FormsAuthenticationTicket. Evidently this is not true.

在我们的WebForms应用程序,我们使用的machineKey的指定我们decryptionKey和validationKey的支持我们的Web农场。在.NET4,默认的算法是AES,如果我没有记错。我以为这将是简单的利用这些信息来建立我们自己的TicketDataFormat如果默认是不够的。

In our WebForms application, we make use of MachineKey to designate our decryptionKey and validationKey to support our web farm. In .NET4, the default algorithm is AES if I'm not mistaken. I assumed it would be simple to leverage this information to build our own TicketDataFormat if the default wouldn't suffice.

第一件事学到:


  • 如果您自主机OWIN,默认TicketDataFormat使用DPAPI和不可以 ASP.NET IIS的machineKey。

  • 在.NET 4.5中,微软取得了MVC / WebForms的管道的machineKey更可扩展性。你可以用自己的实现来替代它,而不是只是改变算法。

  • If you self-host with OWIN, the default TicketDataFormat uses DPAPI and not ASP.NET IIS MachineKey.
  • In .NET 4.5, Microsoft has made the MVC/WebForms MachineKey pipeline more extensible. You can replace it with your own implementation and not just change the algorithm.

在理想情况下,我们不打算更新我们的主要应用到.NET 4.5更换Cookie加密。有谁知道一个办法OWIN的CookieAuthentication与现有的FormsAuthenticationTicket整合?

Ideally, we're not looking to update our main application to .NET 4.5 to replace cookie encryption. Does anyone know of a way to integrate OWIN's CookieAuthentication with an existing FormsAuthenticationTicket?

我们试图创建自定义的:
IDataProtector SecureDataFormat< AuthenticationTicket> IDataSerializer< AuthenticationTicket> 实现。
该IDataSerializer将负责的FormsAuthenticationTicket和AuthenticationTicket之间的转换。

We tried creating custom: IDataProtector, SecureDataFormat<AuthenticationTicket>, IDataSerializer<AuthenticationTicket> implementations. The IDataSerializer would be responsible for translation between FormsAuthenticationTicket and AuthenticationTicket.

不幸的是,我无法找到有关微软的票encrpytion准确的信息。下面是我们为IDataProtector例如思路:

Unfortunately, I can't find accurate information regarding Microsoft's ticket encrpytion. Here is our example idea for IDataProtector:

public byte[] Unprotect(byte[] protectedData)
{
    using (var crypto = new AesCryptoServiceProvider())
    {
        byte[] result = null;
        const Int32 blockSize = 16;
        crypto.KeySize = 192;
        crypto.Key = "<MachineKey>".ToBytesFromHexadecimal();
        crypto.IV = protectedData.Take(blockSize).ToArray();
        crypto.Padding = PaddingMode.None; // This prevents a padding exception thrown.

        using (var decryptor = crypto.CreateDecryptor(crypto.Key, crypto.IV))
        using (var msDecrypt = new MemoryStream(protectedData.Skip(blockSize).Take(protectedData.Length - blockSize).ToArray()))
        {
            using (var csDecrypt = new CryptoStream(msDecrypt, decryptor, CryptoStreamMode.Read))
            {
                result = new byte[protectedData.Length - blockSize];
                csDecrypt.Read(result, 0, result.Length);
            }
        }

        return result;
    }
}

此假设微软prepends的四字节数组。这还假定将machineKey是所使用的AES密钥。不过,我已阅读,MS使用一个密钥导出函数的machineKey的 - 考虑到像AppIsolation,AppVirtualLocation,的AppId等账户其他设置基本上,这是一个在黑暗中拍摄,我需要一些轻

This assumes Microsoft prepends the IV to the byte array. This also assumes the MachineKey is the AES key used. However, I have read that MS uses the MachineKey for a key derivation function - taking into account other settings like AppIsolation, AppVirtualLocation, AppId, etc. Basically, this was a shot in the dark and I need some light!

我们当前的方法

我们目前正在原型使用辅助cookie来确定身份为沿着现有的.ASPXAUTH新的应用程序上下文。不幸的是,这意味着保持会话在两个AuthenticationTicket和的FormsAuthenticationTicket同步下滑。

We're currently prototyping using a secondary cookie to establish identity for the new application context alongside the existing .ASPXAUTH. Unfortunately, this means keeping session sliding in sync in both AuthenticationTicket and FormsAuthenticationTicket.

相关文章

<一个href=\"http://stackoverflow.com/questions/17421692/accepting-asp-net-forms-authentication-cookies-in-an-owin-hosted-signalr-impleme\">Accepting ASP.NET窗体身份验证cookie在OWIN托管的SignalR执行?

推荐答案

有我是否可以使用在&lt一些最初的混乱;内部的app.config的machineKey>元素。进一步的原型已经表明,我可以成功地共享一个单一的FormsAuthenticationTicket两者之间的界环境具有以下code。

There was some initial confusion on whether I could use the <machineKey> element within app.config. Further prototyping has shown that I can successfully share a single FormsAuthenticationTicket between both bounded contexts with the following code.

在理想情况下,我们将实现一个适当的授权服务器启用OpenID的连接,表单,WS-美联储等,并有两个应用程序来运转承载令牌。然而,这在短期内很好地工作。希望这有助于!

Ideally, we will implement a proper authorization server to enable OpenID Connect, Forms, WS-Fed, etc and have both applications operate off bearer tokens. However, this is working nicely in the short-term. Hope this helps!

我已经测试并验证成功的加密/解密两个应用程序,formsauthticket超时滑动。你应注意你的web.config formsAuthentication设置ticketCompatibilityMode的。

I have tested and verified successful encryption/decryption with both applications, sliding of formsauthticket timeout. You should be mindful of your web.config formsAuthentication setting for ticketCompatibilityMode.

appBuilder.UseCookieAuthentication(new CookieAuthenticationOptions
        {
            CookieName = FormsAuthentication.FormsCookieName,
            CookieDomain = FormsAuthentication.CookieDomain,
            CookiePath = FormsAuthentication.FormsCookiePath,
            CookieSecure = CookieSecureOption.SameAsRequest,
            AuthenticationMode = AuthenticationMode.Active,
            ExpireTimeSpan = FormsAuthentication.Timeout,
            SlidingExpiration = true,
            AuthenticationType = "Forms",
            TicketDataFormat = new SecureDataFormat<AuthenticationTicket>(
                new FormsAuthenticationTicketSerializer(), 
                new FormsAuthenticationTicketDataProtector(), 
                new HexEncoder())
        });


<!-- app.config for OWIN Host - Only used for compatibility with existing auth ticket. -->
<authentication mode="Forms">
  <forms domain=".hostname.com" protection="All" ... />
</authentication>
<machineKey validationKey="..." decryptionKey="..." validation="SHA1" />


public class HexEncoder : ITextEncoder
{
    public String Encode(Byte[] data)
    {
        return data.ToHexadecimal();
    }

    public Byte[] Decode(String text)
    {
        return text.ToBytesFromHexadecimal();
    }
}


public class FormsAuthenticationTicketDataProtector : IDataProtector
{
    public Byte[] Protect(Byte[] userData)
    {
        FormsAuthenticationTicket ticket;
        using (var memoryStream = new MemoryStream(userData))
        {
            var binaryFormatter = new BinaryFormatter();
            ticket = binaryFormatter.Deserialize(memoryStream) as FormsAuthenticationTicket;
        }

        if (ticket == null)
        {
            return null;
        }

        try
        {
            var encryptedTicket = FormsAuthentication.Encrypt(ticket);

            return encryptedTicket.ToBytesFromHexadecimal();
        }
        catch
        {
            return null;
        }
    }

    public Byte[] Unprotect(Byte[] protectedData)
    {
        FormsAuthenticationTicket ticket;
        try
        {
            ticket = FormsAuthentication.Decrypt(protectedData.ToHexadecimal());
        }
        catch
        {
            return null;
        }

        if (ticket == null)
        {
            return null;
        }

        using (var memoryStream = new MemoryStream())
        {
            var binaryFormatter = new BinaryFormatter();
            binaryFormatter.Serialize(memoryStream, ticket);

            return memoryStream.ToArray();
        }
    }
}


public class FormsAuthenticationTicketSerializer : IDataSerializer<AuthenticationTicket>
{
    public Byte[] Serialize(AuthenticationTicket model)
    {
        var userTicket = new FormsAuthenticationTicket(
            2,
            model.Identity.GetClaimValue<String>(CustomClaim.UserName),
            new DateTime(model.Properties.IssuedUtc.Value.UtcDateTime.Ticks, DateTimeKind.Utc),
            new DateTime(model.Properties.ExpiresUtc.Value.UtcDateTime.Ticks, DateTimeKind.Utc),
            model.Properties.IsPersistent,
            String.Format(
                "AuthenticationType={0};SiteId={1};SiteKey={2};UserId={3}",
                model.Identity.AuthenticationType,
                model.Identity.GetClaimValue<String>(CustomClaim.SiteId),
                model.Identity.GetClaimValue<String>(CustomClaim.SiteKey),
                model.Identity.GetClaimValue<String>(CustomClaim.UserId)),
            FormsAuthentication.FormsCookiePath);

        using (var dataStream = new MemoryStream())
        {
            var binaryFormatter = new BinaryFormatter();
            binaryFormatter.Serialize(dataStream, userTicket);

            return dataStream.ToArray();
        }
    }

    public AuthenticationTicket Deserialize(Byte[] data)
    {
        using (var dataStream = new MemoryStream(data))
        {
            var binaryFormatter = new BinaryFormatter();
            var ticket = binaryFormatter.Deserialize(dataStream) as FormsAuthenticationTicket;
            if (ticket == null)
            {
                return null;
            }

            var userData = ticket.UserData.ToNameValueCollection(';', '=');
            var authenticationType = userData["AuthenticationType"];
            var siteId = userData["SiteId"];
            var siteKey = userData["SiteKey"];
            var userId = userData["UserId"];

            var claims = new[]
            {
                CreateClaim(CustomClaim.UserName, ticket.Name),
                CreateClaim(CustomClaim.UserId, userId),
                CreateClaim(CustomClaim.AuthenticationMethod, authenticationType),
                CreateClaim(CustomClaim.SiteId, siteId),
                CreateClaim(CustomClaim.SiteKey, siteKey)
            };

            var authTicket = new AuthenticationTicket(new UserIdentity(claims, authenticationType), new AuthenticationProperties());
            authTicket.Properties.IssuedUtc = new DateTimeOffset(ticket.IssueDate);
            authTicket.Properties.ExpiresUtc = new DateTimeOffset(ticket.Expiration);
            authTicket.Properties.IsPersistent = ticket.IsPersistent;

            return authTicket;
        }
    }

    private Claim CreateClaim(String type, String value)
    {
        return new Claim(type, value, ClaimValueTypes.String, CustomClaim.Issuer);
    }
}

这篇关于OWIN自托管CookieAuthentication&安培;传统的.NET 4.0应用程序/的FormsAuthenticationTicket的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆