我有一个方法GetColors
,它将GetColorIdsRQ
作为参数并返回GetColorIdsRS
。 GetColorIdsRQ
是SOAP请求,GetColorIdsRS
是SOAP Resposne。以下是每个实现细节:
GetColorIdsRQ:
[DataContract]
public class GetColorIdsRQ
{
[DataMember(Name="UserCredentials",Order=0,IsRequired=true)]
public UserCredentials UserCredentials { get; set; }
}
UserCredentials:
[DataContract(Name="UserCredentials")]
public class UserCredentials
{
[DataMember(Name="Username",Order=0,IsRequired=true)]
public string UserName { get; set; }
[DataMember(Name="Password",Order=1,IsRequired=true)]
public string Password { get; set; }
}
GetColorIdsRS:
[DataContract]
public class GetColorIdsRS
{
[DataMember(Name = "ColorsIds", IsRequired = true, Order = 0)]
public List<Color> ColorIds { get; set; }
}
颜色
[DataContract(Name="Color")]
public class Color
{
[DataMember(Name="Code",IsRequired=true,Order=0)]
public string Code { get; set; }
[DataMember(Name="Name",IsRequired=true,Order=1)]
public string Name { get; set; }
}
这是方法在界面中声明的方式:
[OperationContract(Name = "GetColorIds")]
GetColorIdsRS GetColorsIds(GetColorIdsRQ req);
这是GetColorIds的实现:
public GetColorIdsRS GetColors(GetColorIdsRQ req)
{
GetColorIdsRS getColorIdsRS = new GetColorIdsRS();
List<Color> colorIds = new List<Color>();
req.UserCredentials.UserName = "test";
req.UserCredentials.Password = "test";
//Validate Username and Password
DataTable dtColorIds = Data.GetDataTable("GetColors");
foreach (DataRow item in dtColorIds.Rows)
{
colorIds.Add(new Color { Name = item["Name"].ToString(),
Code = item["ColorId"].ToString() });
}
getColorIdsRS.ColorIds = colorIds;
return getColorIdsRS;
}
当我从WCF测试客户端调用GetColors时,请求正文是:
<s:Body>
<GetColors xmlns="http://test.com/2011/05">
<req xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
<UserCredentials>
<Username>test</Username>
<Password>test2</Password>
</UserCredentials>
</req>
</GetColors>
</s:Body>
上述问题是我想为Username
使用Password
和CustomUserNameValidator
个节点。我不确定如何让CustomUserNameValidator
识别GetColorIdsRQ
用户名和密码节点,以便它可以对此进行验证。如果您在GetColors
方法中注意到上述内容,我正在设置:
req.UserCredentials.UserName = "test";
req.UserCredentials.Password = "test";
但是这显然没有得到验证。以下是我的CustomUserNamePasswordValidator
:
public class CustomUserNameValidator : UserNamePasswordValidator
{
public override void Validate(string userName, string password)
{
// check if the user is not test
if (userName != "test" || password != "test")
throw new FaultException("Username and Password Failed");
}
}
基本上如果我通过:
req.UserCredentials.UserName = "test";
req.UserCredentials.Password = "test2";
CustomUserNameValidator应该抛出FaultException。
另请注意,在GetColors方法中,我有一条评论“//验证用户名和密码”,我知道我可以这样做:
CustomUserNameValidator val = new CustomUserNameValidator();
val.Validate(req.UserCredentials.UserName,req.UserCredentials.Password)
以上会调用Validate方法,但我知道它应该是自动的,然后我必须在每一种方法中都这样做。
调用CustomUserNameValidator的唯一方法是在代理代码中设置ClientCredentials,例如:
proxy.ClientCredentials.UserName.UserName = "test;
proxy.ClientCredentials.UserName.Password = "test;
以上会导致调用Validate方法,但如果我无法执行上述操作并将Username和Password设置为Request对象的属性,则不会调用Validate,因此我的其他选项是在每个需要它的操作中只有我自己的Validate方法。如果ClientCredentials失败,将不会调用操作,但在我的情况下,我需要一个操作来调用,然后它返回一个带有错误节点的SOAP响应,其中包含“无效的用户名和/或密码”而不是抛出一个FaultException。
基于以上所述,最好避免在我的情况下使用CustomUserNamePasswordValidator吗?
如果无法通过代理的客户端凭据设置用户名和密码,而是通过soap请求的主体发送,那么处理此问题的方法似乎是处理运行中的验证基础,这是否会影响安全设置(例如,有没有一个点有clientCredentialType =“用户名”)
答案 0 :(得分:0)
除非您深入了解WCF安全管道并实现自定义安全令牌(即使这样您可以发现它不可能)以及与此实现相关的所有内容 - 这是a lot of work,否则这是不可能的。 / p>
为什么不使用标准的UserName身份验证?
编辑:
如果要在邮件正文中的自定义元素中传递凭据(并且您不会更改安全管道),则验证由您决定 - 它不会路由到用户名验证程序。您必须在操作中执行此操作,或者您可以构建自定义消息检查器(实现IMessageInspector
)并使用自定义端点行为(IEndpointBehavior
)对其进行包装以使验证集中。