如何在 gRPC 中将 System.Security.Claims.ClaimsPrincipal 定义为请求参数?
How to define a System.Security.Claims.ClaimsPrincipal as a request argument in gRPC?
我想在 .Net 代码下使用 gRPC 构建授权服务。为此,我需要将 System.Security.Claims.ClaimsPrincipal 对象作为请求参数从调用方传递到服务器,以便服务器可以使用它来授权调用方。但我不知道该怎么做——如何为标准库的 class 定义 .proto。我该怎么办?
我也在做同样的事情,使用 protobuf-net grpc 库。
由于许多 Identity/Security classes(如果您正在使用它们)来自 Microsoft,您需要公开它们的成员以进行序列化;你可以使用:
RuntimeTypeModel.Default.Add(typeof(SignInResult), false).Add(
nameof(SignInResult.Succeeded),
nameof(SignInResult.IsLockedOut),
nameof(SignInResult.IsNotAllowed),
nameof(SignInResult.RequiresTwoFactor)
);
并列出需要通过 gRpc 公开的成员。
至于 ClaimsPrincipal,具体而言,这就是我目前正在尝试实现的。对于索赔,我正在使用代理 class:
RuntimeTypeModel.Default.Add(typeof(Claim), true).SetSurrogate(typeof(ClaimSurrogate));
public class ClaimSurrogate
{
[DataMember, ProtoMember(1)]
public string Type { get; set; }
[DataMember, ProtoMember(2)]
public ClaimsIdentity Subject { get; set; }
[DataMember, ProtoMember(3)]
public IDictionary<string, string> Properties { get; set; }
[DataMember, ProtoMember(4)]
public string OriginalIssuer { get; set; }
[DataMember, ProtoMember(5)]
public string Issuer { get; set; }
[DataMember, ProtoMember(6)]
public string ValueType { get; set; }
[DataMember, ProtoMember(7)]
public string Value { get; set; }
public static implicit operator ClaimSurrogate(Claim claim)
{
if (claim == null)
return null;
return new ClaimSurrogate()
{
Type = claim.Type,
Subject = claim.Subject,
Properties = claim.Properties,
OriginalIssuer = claim.OriginalIssuer,
Issuer = claim.Issuer,
ValueType = claim.ValueType,
Value = claim.Value
};
}
public static implicit operator Claim(ClaimSurrogate surrogate)
{
if (surrogate == null)
return null;
return new Claim(surrogate.Type, surrogate.Value, surrogate.ValueType, surrogate.Issuer, surrogate.OriginalIssuer, surrogate.Subject);
}
}
而且我假设 ClaimsPrincipal 可以用同样的方式完成,但是,我遇到了麻烦。这就是我遇到你的问题的方式......
实际上,通过尝试提供答案......从字面上看,我刚刚意识到我忽略了什么,我还需要为 ClaimsIdentity
设置一个代理
到目前为止,我需要 'third' 派对 classes 的代理人;只有属性。 ClaimsPrincipal 具有这些类型的属性,ClaimsIdentity 也是如此(Claim 也是如此)。如果 ClaimsIdentitySurrogate 能解决问题,我会 update/comment
更新:
是的,可以做到。 ClaimsIdentity 和 IIdentity 将需要代理项,如上面的示例。这些 classes 在 ClaimsPrincipal 中用作 members/properties。
ClaimsIdentity:您可以混合使用 SetSurrogate 和 Add(nameof(...)),因为它只有 get onlies 和 get/sets(get/sets 进入 Add 部分)。不要在 ClaimsIdentity 代理项中包含 Actor,因为它会在您的服务启动时创建一个永无止境的循环。如果确实包含它,请确保它不是 DataMember/Protomember。并且(私有)在代理运算符中设置它。与声明相同。
本质上,任何具有引用父类型 class 成员的代理项,或具有引用该父类型的代理项的另一种类型的代理项,都会创建循环引用并在启动时使您的服务出错。
IIdentity:这是一个简单的,只是
RuntimeTypeModel.Default.Add(typeof(IIdentity), false).
最后(当我认为我有更新时我发布了这个更新,但是,在所有 UT 测试和更改等中,我发布得有点早;在对 ClaimPrincipal 代理项进行重大更改后 class )...
您需要一个将在您的 ClaimPrincipal 代理中使用的 IIdentity 虚拟对象 class,而不是 IIdentity 身份 {get;set;}。这个虚拟 class 应该继承自 IIdentity,例如
[DataContract]
public class IIdentityFraud : System.Security.Principal.IIdentity
并且在您代理人的隐式运算符中:
IIdentityFraud identityfraud = null;
if (claimPrincipal.Identity != null)
{
identityfraud = new IIdentityFraud(claimPrincipal.Identity.AuthenticationType, claimPrincipal.Identity.Name, claimPrincipal.Identity.IsAuthenticated);
}
更新 (11/05/2021):
[DataContract]
public class ClaimsPrincipalSurrogate
{
[DataMember, ProtoMember(1)]
public IIdentityFraud Identity { get; set; }
[DataMember, ProtoMember(2)]
public IEnumerable<ClaimsIdentity> Identities { get; set; }
[DataMember, ProtoMember(3)]
public IEnumerable<Claim> Claims { get; set; }
public static implicit operator ClaimsPrincipalSurrogate(ClaimsPrincipal claimPrincipal)
{
if (claimPrincipal == null)
{
return null;
}
else
{
IIdentityFraud identityfraud = null;
if (claimPrincipal.Identity != null)
{
identityfraud = new IIdentityFraud(claimPrincipal.Identity.AuthenticationType, claimPrincipal.Identity.Name, claimPrincipal.Identity.IsAuthenticated);
}
return new ClaimsPrincipalSurrogate()
{
Identity = identityfraud, // (System.Security.Principal.IIdentity)identityfraud,
Identities = claimPrincipal.Identities,
Claims = claimPrincipal.Claims
};
}
}
public static implicit operator ClaimsPrincipal(ClaimsPrincipalSurrogate surrogate)
{
if (surrogate == null)
return null;
if (surrogate.Identities != null && surrogate.Identities.Any() == true)
{
return new ClaimsPrincipal(surrogate.Identities);
}
else if (surrogate.Identity != null)
{
return new ClaimsPrincipal(surrogate.Identity);
}
return new ClaimsPrincipal();
}
}
[DataContract]
public class ClaimsIdentitySurrogate
{
[DataMember, ProtoMember(1)]
public string AuthenticationType { get; set; }
[DataMember, ProtoMember(2)]
public string Name { get; set; }
//[DataMember, ProtoMember(3)]
//public string Label { get; set; }
[DataMember, ProtoMember(4)]
public bool IsAuthenticated { get; set; }
[DataMember, ProtoMember(5)]
public IEnumerable<Claim> Claims { get; private set; }
//[DataMember, ProtoMember(6)]
//public object BootstrapContext { get; set; }
//[DataMember, ProtoMember(7)]
public ClaimsIdentity Actor { get; private set; }
[DataMember, ProtoMember(8)]
public string RoleClaimType { get; set; }
[DataMember, ProtoMember(9)]
public string NameClaimType { get; set; }
public static implicit operator ClaimsIdentitySurrogate(ClaimsIdentity claimIdentity)
{
if (claimIdentity == null)
return null;
return new ClaimsIdentitySurrogate()
{
AuthenticationType = claimIdentity.AuthenticationType,
Name = claimIdentity.Name,
//Label = claimIdentity.Label,
IsAuthenticated = claimIdentity.IsAuthenticated,
Claims = claimIdentity.Claims,
//BootstrapContext = claimIdentity.AuthenticationType,
Actor = claimIdentity.Actor,
RoleClaimType = claimIdentity.RoleClaimType,
NameClaimType = claimIdentity.NameClaimType
};
}
public static implicit operator ClaimsIdentity(ClaimsIdentitySurrogate surrogate)
{
if (surrogate == null)
{
return null;
}
if (surrogate.Claims?.Any() == true)
{
return new ClaimsIdentity(surrogate.Claims, surrogate.AuthenticationType);
}
else
{
return new ClaimsIdentity(surrogate.AuthenticationType, surrogate.NameClaimType, surrogate.RoleClaimType);
}
}
}
[DataContract]
public class IIdentityFraud : System.Security.Principal.IIdentity
{
[DataMember, ProtoMember(1)]
public string AuthenticationType { get; private set; }
[DataMember, ProtoMember(2)]
public string Name { get; private set; }
[DataMember, ProtoMember(3)]
public bool IsAuthenticated { get; private set; }
public IIdentityFraud() { }
public IIdentityFraud(string authenticationType, string name, bool isAuthenticated)
{
this.AuthenticationType = authenticationType;
this.Name = name;
this.IsAuthenticated = isAuthenticated;
}
}
[DataContract] //don't know if this is really needed. Too involved in testing out the rest of it and have yet to come back to this.
public class IIdentitySurrogate : System.Security.Principal.IIdentity
{
[DataMember, ProtoMember(1)]
public string AuthenticationType { get; set; }
[DataMember, ProtoMember(2)]
public string Name { get; set; }
[DataMember, ProtoMember(3)]
public bool IsAuthenticated { get; set; }
public static implicit operator IIdentitySurrogate(IIdentityFraud iidentity)
{
if (iidentity == null)
return null;
return new IIdentitySurrogate()
{
AuthenticationType = iidentity.AuthenticationType,
Name = iidentity.Name,
IsAuthenticated = iidentity.IsAuthenticated
};
}
public static implicit operator IIdentityFraud(IIdentitySurrogate surrogate)
{
if (surrogate == null)
return null;
return new IIdentityFraud(surrogate.AuthenticationType, surrogate.Name, surrogate.IsAuthenticated);
}
}
在初创公司执行的更多内容:
#region ClaimsIdentity
RuntimeTypeModel.Default.Add(typeof(ClaimsIdentity), true).Add(
nameof(ClaimsIdentity.Label),
nameof(ClaimsIdentity.BootstrapContext),
nameof(ClaimsIdentity.Actor)
).SetSurrogate(typeof(ClaimsIdentitySurrogate));
#endregion ClaimsIdentity
#region ClaimsPrincipal
RuntimeTypeModel.Default.Add(typeof(ClaimsPrincipal), true).SetSurrogate(typeof(ClaimsPrincipalSurrogate));
#endregion ClaimsPrincipal
#region IIdentity
RuntimeTypeModel.Default.Add(typeof(IIdentity), true);
#endregion IIdentity
我想在 .Net 代码下使用 gRPC 构建授权服务。为此,我需要将 System.Security.Claims.ClaimsPrincipal 对象作为请求参数从调用方传递到服务器,以便服务器可以使用它来授权调用方。但我不知道该怎么做——如何为标准库的 class 定义 .proto。我该怎么办?
我也在做同样的事情,使用 protobuf-net grpc 库。 由于许多 Identity/Security classes(如果您正在使用它们)来自 Microsoft,您需要公开它们的成员以进行序列化;你可以使用:
RuntimeTypeModel.Default.Add(typeof(SignInResult), false).Add(
nameof(SignInResult.Succeeded),
nameof(SignInResult.IsLockedOut),
nameof(SignInResult.IsNotAllowed),
nameof(SignInResult.RequiresTwoFactor)
);
并列出需要通过 gRpc 公开的成员。 至于 ClaimsPrincipal,具体而言,这就是我目前正在尝试实现的。对于索赔,我正在使用代理 class:
RuntimeTypeModel.Default.Add(typeof(Claim), true).SetSurrogate(typeof(ClaimSurrogate));
public class ClaimSurrogate
{
[DataMember, ProtoMember(1)]
public string Type { get; set; }
[DataMember, ProtoMember(2)]
public ClaimsIdentity Subject { get; set; }
[DataMember, ProtoMember(3)]
public IDictionary<string, string> Properties { get; set; }
[DataMember, ProtoMember(4)]
public string OriginalIssuer { get; set; }
[DataMember, ProtoMember(5)]
public string Issuer { get; set; }
[DataMember, ProtoMember(6)]
public string ValueType { get; set; }
[DataMember, ProtoMember(7)]
public string Value { get; set; }
public static implicit operator ClaimSurrogate(Claim claim)
{
if (claim == null)
return null;
return new ClaimSurrogate()
{
Type = claim.Type,
Subject = claim.Subject,
Properties = claim.Properties,
OriginalIssuer = claim.OriginalIssuer,
Issuer = claim.Issuer,
ValueType = claim.ValueType,
Value = claim.Value
};
}
public static implicit operator Claim(ClaimSurrogate surrogate)
{
if (surrogate == null)
return null;
return new Claim(surrogate.Type, surrogate.Value, surrogate.ValueType, surrogate.Issuer, surrogate.OriginalIssuer, surrogate.Subject);
}
}
而且我假设 ClaimsPrincipal 可以用同样的方式完成,但是,我遇到了麻烦。这就是我遇到你的问题的方式...... 实际上,通过尝试提供答案......从字面上看,我刚刚意识到我忽略了什么,我还需要为 ClaimsIdentity
设置一个代理到目前为止,我需要 'third' 派对 classes 的代理人;只有属性。 ClaimsPrincipal 具有这些类型的属性,ClaimsIdentity 也是如此(Claim 也是如此)。如果 ClaimsIdentitySurrogate 能解决问题,我会 update/comment
更新:
是的,可以做到。 ClaimsIdentity 和 IIdentity 将需要代理项,如上面的示例。这些 classes 在 ClaimsPrincipal 中用作 members/properties。 ClaimsIdentity:您可以混合使用 SetSurrogate 和 Add(nameof(...)),因为它只有 get onlies 和 get/sets(get/sets 进入 Add 部分)。不要在 ClaimsIdentity 代理项中包含 Actor,因为它会在您的服务启动时创建一个永无止境的循环。如果确实包含它,请确保它不是 DataMember/Protomember。并且(私有)在代理运算符中设置它。与声明相同。
本质上,任何具有引用父类型 class 成员的代理项,或具有引用该父类型的代理项的另一种类型的代理项,都会创建循环引用并在启动时使您的服务出错。
IIdentity:这是一个简单的,只是 RuntimeTypeModel.Default.Add(typeof(IIdentity), false).
最后(当我认为我有更新时我发布了这个更新,但是,在所有 UT 测试和更改等中,我发布得有点早;在对 ClaimPrincipal 代理项进行重大更改后 class )...
您需要一个将在您的 ClaimPrincipal 代理中使用的 IIdentity 虚拟对象 class,而不是 IIdentity 身份 {get;set;}。这个虚拟 class 应该继承自 IIdentity,例如
[DataContract]
public class IIdentityFraud : System.Security.Principal.IIdentity
并且在您代理人的隐式运算符中:
IIdentityFraud identityfraud = null;
if (claimPrincipal.Identity != null)
{
identityfraud = new IIdentityFraud(claimPrincipal.Identity.AuthenticationType, claimPrincipal.Identity.Name, claimPrincipal.Identity.IsAuthenticated);
}
更新 (11/05/2021):
[DataContract]
public class ClaimsPrincipalSurrogate
{
[DataMember, ProtoMember(1)]
public IIdentityFraud Identity { get; set; }
[DataMember, ProtoMember(2)]
public IEnumerable<ClaimsIdentity> Identities { get; set; }
[DataMember, ProtoMember(3)]
public IEnumerable<Claim> Claims { get; set; }
public static implicit operator ClaimsPrincipalSurrogate(ClaimsPrincipal claimPrincipal)
{
if (claimPrincipal == null)
{
return null;
}
else
{
IIdentityFraud identityfraud = null;
if (claimPrincipal.Identity != null)
{
identityfraud = new IIdentityFraud(claimPrincipal.Identity.AuthenticationType, claimPrincipal.Identity.Name, claimPrincipal.Identity.IsAuthenticated);
}
return new ClaimsPrincipalSurrogate()
{
Identity = identityfraud, // (System.Security.Principal.IIdentity)identityfraud,
Identities = claimPrincipal.Identities,
Claims = claimPrincipal.Claims
};
}
}
public static implicit operator ClaimsPrincipal(ClaimsPrincipalSurrogate surrogate)
{
if (surrogate == null)
return null;
if (surrogate.Identities != null && surrogate.Identities.Any() == true)
{
return new ClaimsPrincipal(surrogate.Identities);
}
else if (surrogate.Identity != null)
{
return new ClaimsPrincipal(surrogate.Identity);
}
return new ClaimsPrincipal();
}
}
[DataContract]
public class ClaimsIdentitySurrogate
{
[DataMember, ProtoMember(1)]
public string AuthenticationType { get; set; }
[DataMember, ProtoMember(2)]
public string Name { get; set; }
//[DataMember, ProtoMember(3)]
//public string Label { get; set; }
[DataMember, ProtoMember(4)]
public bool IsAuthenticated { get; set; }
[DataMember, ProtoMember(5)]
public IEnumerable<Claim> Claims { get; private set; }
//[DataMember, ProtoMember(6)]
//public object BootstrapContext { get; set; }
//[DataMember, ProtoMember(7)]
public ClaimsIdentity Actor { get; private set; }
[DataMember, ProtoMember(8)]
public string RoleClaimType { get; set; }
[DataMember, ProtoMember(9)]
public string NameClaimType { get; set; }
public static implicit operator ClaimsIdentitySurrogate(ClaimsIdentity claimIdentity)
{
if (claimIdentity == null)
return null;
return new ClaimsIdentitySurrogate()
{
AuthenticationType = claimIdentity.AuthenticationType,
Name = claimIdentity.Name,
//Label = claimIdentity.Label,
IsAuthenticated = claimIdentity.IsAuthenticated,
Claims = claimIdentity.Claims,
//BootstrapContext = claimIdentity.AuthenticationType,
Actor = claimIdentity.Actor,
RoleClaimType = claimIdentity.RoleClaimType,
NameClaimType = claimIdentity.NameClaimType
};
}
public static implicit operator ClaimsIdentity(ClaimsIdentitySurrogate surrogate)
{
if (surrogate == null)
{
return null;
}
if (surrogate.Claims?.Any() == true)
{
return new ClaimsIdentity(surrogate.Claims, surrogate.AuthenticationType);
}
else
{
return new ClaimsIdentity(surrogate.AuthenticationType, surrogate.NameClaimType, surrogate.RoleClaimType);
}
}
}
[DataContract]
public class IIdentityFraud : System.Security.Principal.IIdentity
{
[DataMember, ProtoMember(1)]
public string AuthenticationType { get; private set; }
[DataMember, ProtoMember(2)]
public string Name { get; private set; }
[DataMember, ProtoMember(3)]
public bool IsAuthenticated { get; private set; }
public IIdentityFraud() { }
public IIdentityFraud(string authenticationType, string name, bool isAuthenticated)
{
this.AuthenticationType = authenticationType;
this.Name = name;
this.IsAuthenticated = isAuthenticated;
}
}
[DataContract] //don't know if this is really needed. Too involved in testing out the rest of it and have yet to come back to this.
public class IIdentitySurrogate : System.Security.Principal.IIdentity
{
[DataMember, ProtoMember(1)]
public string AuthenticationType { get; set; }
[DataMember, ProtoMember(2)]
public string Name { get; set; }
[DataMember, ProtoMember(3)]
public bool IsAuthenticated { get; set; }
public static implicit operator IIdentitySurrogate(IIdentityFraud iidentity)
{
if (iidentity == null)
return null;
return new IIdentitySurrogate()
{
AuthenticationType = iidentity.AuthenticationType,
Name = iidentity.Name,
IsAuthenticated = iidentity.IsAuthenticated
};
}
public static implicit operator IIdentityFraud(IIdentitySurrogate surrogate)
{
if (surrogate == null)
return null;
return new IIdentityFraud(surrogate.AuthenticationType, surrogate.Name, surrogate.IsAuthenticated);
}
}
在初创公司执行的更多内容:
#region ClaimsIdentity
RuntimeTypeModel.Default.Add(typeof(ClaimsIdentity), true).Add(
nameof(ClaimsIdentity.Label),
nameof(ClaimsIdentity.BootstrapContext),
nameof(ClaimsIdentity.Actor)
).SetSurrogate(typeof(ClaimsIdentitySurrogate));
#endregion ClaimsIdentity
#region ClaimsPrincipal
RuntimeTypeModel.Default.Add(typeof(ClaimsPrincipal), true).SetSurrogate(typeof(ClaimsPrincipalSurrogate));
#endregion ClaimsPrincipal
#region IIdentity
RuntimeTypeModel.Default.Add(typeof(IIdentity), true);
#endregion IIdentity