OWIN自托管CookieAuthentication&安培;传统的.NET 4.0应用程序/的FormsAuthenticationTicket [英] OWIN Self-Host CookieAuthentication & Legacy .NET 4.0 Application / FormsAuthenticationTicket
问题描述
我有两个限界上下文的:
- ASP.NET 4.0 MVC / WebForms的应用
- 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屋!