我在服务器端(托管在 IIS 中)和 Android 客户端上有一个 WCF 4.0 REST 服务。 Android 客户端在自定义 HTTP header 中发送加密的安全 token ,以对用户进行身份验证。我已经实现了一个自定义 ServiceAuthorizationManager
,它从 header 中提取安全 token 。 token 包含我可以从 token 中读取的用户名:
public class MyAuthorizationManager : ServiceAuthorizationManager
{
protected override bool CheckAccessCore(OperationContext operationContext)
{
var requestMessage = operationContext.RequestContext.RequestMessage;
var requestProperty = (HttpRequestMessageProperty)requestMessage
.Properties[HttpRequestMessageProperty.Name];
var token = requestProperty.Headers["X-MyCustomHeader"];
if (!string.IsNullOrEmpty(token))
{
var userName = GetUserNameFromToken(token);
if (!string.IsNullOrEmpty(userName))
{
// How to save userName now so that I can
// retrieve it in the service operations?
return true;
}
}
return false;
}
}
现在,我的问题是在各种服务操作(主要是访问用户配置文件数据)中我还需要经过身份验证的用户的名称,我正计划以这种方式检索它:
public void MyServiceOperation()
{
string userName = OperationContext.Current
.ServiceSecurityContext.PrimaryIdentity.Name;
// check profile store for that userName and do something depending on
// profile settings
}
如何在 CheckAccessCore
中设置此用户名?
像这样一个非常天真的试验......
operationContext.ServiceSecurityContext.PrimaryIdentity.Name = userName;
...不起作用,因为 PrimaryIdentity.Name
是只读的。我假设需要更复杂的代码。
最佳答案
经过一些研究,我没有找到在 ServiceAuthorizationManager.CheckAccessCore
中设置身份的方法。当用户身份已设置(可能为“匿名”(IsAuthenticated
为 false
))且无法再更改时,此方法似乎在处理管道中被调用得太迟. ServiceAuthorizationManager
用于授权,而不是身份验证,因此它不是实现自定义身份验证的错误位置。
我终于找到了三种可能的方法来解决我的问题:
如@TheCodeKing 的回答中链接的文章中所述,使用 WCF REST 初学者工具包提供了编写自定义
RequestInterceptor
的选项,它足够早地挂接到管道中,允许访问传入请求并允许根据自定义 HTTP header 等设置用户身份。不幸的是,WCF REST Starter Kit 很旧(基于 WCF 3.5)并且开发显然已被放弃。它的一些特性已经被合并到 WCF 4.0 中,但有些还没有,RequestInterceptor
就是其中之一。尽管如此,我现在已经使用了这个解决方案并将初学者工具包中的Microsoft.ServiceModel.Web
程序集混合到我的 WCF 4.0 解决方案中。经过一些简单的测试,它似乎到目前为止有效。如果身份不是真正必需的,而只是用户名,那么将用户名写入新请求 header 的简单“技巧”/“hack”就可以了(也在
CheckAccessCore
中) ):// ... var userName = GetUserNameFromToken(token); if (!string.IsNullOrEmpty(userName)) { requestProperty.Headers["X-UserName"] = userName; return true; } // ...
然后在服务方法中:
public void MyServiceOperation() { string userName = WebOperationContext.Current.IncomingRequest .Headers["X-UserName"]; // ... }
另一个更底层的选项是编写一个自定义
HttpModule
,它拦截传入的请求并设置身份。这看起来像的一个例子是 here来自 Microsoft Pattern & Practices 团队(参见文章中间的“HTTP 模块代码”示例)。
关于c# - 如何在 ServiceAuthorizationManager 中设置身份/用户名?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/7299922/