我目前有一对基于OWIN的服务,每个服务都对同一组用户使用OAuth身份验证。我打算隔离授权服务器(即令牌端点),并以某种方式配置我的两个服务以接受此令牌。我假设这将涉及我的所有服务的一些配置,以允许在所有相关服务上解密该令牌。这可能吗?
答案 0 :(得分:20)
在对原帖的评论中与Brock Allen交谈之后,我无法保证这是一个好的/安全的解决方案,但这是我最终使用的代码。 (注意:此代码的版本以a nuget package提供。)
我创建了一个使用AES的IDataProtector实现:
internal class AesDataProtectorProvider : IDataProtector
{
// Fields
private byte[] key;
// Constructors
public AesDataProtectorProvider(string key)
{
using (var sha1 = new SHA256Managed())
{
this.key = sha1.ComputeHash(Encoding.UTF8.GetBytes(key));
}
}
// IDataProtector Methods
public byte[] Protect(byte[] data)
{
byte[] dataHash;
using (var sha = new SHA256Managed())
{
dataHash = sha.ComputeHash(data);
}
using (AesManaged aesAlg = new AesManaged())
{
aesAlg.Key = this.key;
aesAlg.GenerateIV();
using (var encryptor = aesAlg.CreateEncryptor(aesAlg.Key, aesAlg.IV))
using (var msEncrypt = new MemoryStream())
{
msEncrypt.Write(aesAlg.IV, 0, 16);
using (var csEncrypt = new CryptoStream(msEncrypt, encryptor, CryptoStreamMode.Write))
using (var bwEncrypt = new BinaryWriter(csEncrypt))
{
bwEncrypt.Write(dataHash);
bwEncrypt.Write(data.Length);
bwEncrypt.Write(data);
}
var protectedData = msEncrypt.ToArray();
return protectedData;
}
}
}
public byte[] Unprotect(byte[] protectedData)
{
using (AesManaged aesAlg = new AesManaged())
{
aesAlg.Key = this.key;
using (var msDecrypt = new MemoryStream(protectedData))
{
byte[] iv = new byte[16];
msDecrypt.Read(iv, 0, 16);
aesAlg.IV = iv;
using (var decryptor = aesAlg.CreateDecryptor(aesAlg.Key, aesAlg.IV))
using (var csDecrypt = new CryptoStream(msDecrypt, decryptor, CryptoStreamMode.Read))
using (var brDecrypt = new BinaryReader(csDecrypt))
{
var signature = brDecrypt.ReadBytes(32);
var len = brDecrypt.ReadInt32();
var data = brDecrypt.ReadBytes(len);
byte[] dataHash;
using (var sha = new SHA256Managed())
{
dataHash = sha.ComputeHash(data);
}
if (!dataHash.SequenceEqual(signature))
throw new SecurityException("Signature does not match the computed hash");
return data;
}
}
}
}
}
然后在ISecureDataFormat实现中使用它,如下所示:
public class SecureTokenFormatter : ISecureDataFormat<AuthenticationTicket>
{
// Fields
private TicketSerializer serializer;
private IDataProtector protector;
private ITextEncoder encoder;
// Constructors
public SecureTokenFormatter(string key)
{
this.serializer = new TicketSerializer();
this.protector = new AesDataProtectorProvider(key);
this.encoder = TextEncodings.Base64Url;
}
// ISecureDataFormat<AuthenticationTicket> Members
public string Protect(AuthenticationTicket ticket)
{
var ticketData = this.serializer.Serialize(ticket);
var protectedData = this.protector.Protect(ticketData);
var protectedString = this.encoder.Encode(protectedData);
return protectedString;
}
public AuthenticationTicket Unprotect(string text)
{
var protectedData = this.encoder.Decode(text);
var ticketData = this.protector.Unprotect(protectedData);
var ticket = this.serializer.Deserialize(ticketData);
return ticket;
}
}
然后,构造函数上的'key'参数可以在许多服务上设置为相同的值,并且它们都能够解密('unprotect')并使用该票证。
答案 1 :(得分:9)
Katana OAuth2授权服务器中间件并非真正针对此方案设计(主要是因为它依赖于机器密钥进行令牌验证)。
如果您希望集中标记生成,那么您应该查看专为此设计的OAuth2授权服务器。 Thinktecture AuthorizationServer是一个开源服务器,它执行此操作:http://thinktecture.github.io/Thinktecture.AuthorizationServer/
答案 2 :(得分:0)
我知道这是一个老问题,但我有一个类似的用例。根据文档,OWIN OAuth使用机器密钥来保护数据。由于您控制所有实例,我认为只需在Web配置中设置machinekey即可。
答案 3 :(得分:0)
您可以使用此nuget包https://www.nuget.org/packages/Owin.Security.AesDataProtectorProvider/
它包含IAppBuilder的扩展方法,允许您设置自己的密钥
appBuilder.UseAesDataProtectorProvider(key);