我目前正在开发基于 WCF4 的 REST Web 服务。大多数调用不需要授权,但有些调用需要授权,因此我的计划是实现一个 RequireAuthorization 属性来处理某些调用的 API 密钥授权。
阅读完实现 WCF Web API 的授权属性后,我实现了一个
HttpOperationHandler
,它在 OnHandle
方法中处理 API 密钥验证,并将其添加到服务配置中的 RequestHandlers
。
基本上这工作正常,但我需要将我在
AuthOperationHandler
中提取的用户信息传递给服务,但我找不到任何相关信息。
有人可以帮忙吗?
public class ServiceConfiguration : WebApiConfiguration
{
public ServiceConfiguration()
{
RequestHandlers = (c, e, od) => {
var authorizeAttribute = od.Attributes.OfType<RequireAuthorizationAttribute>().FirstOrDefault();
if (authorizeAttribute != null)
{
c.Add(new AuthOperationHandler(authorizeAttribute));
}
};
CreateInstance = (serviceType, context, request) => RepositoryFactory.GetInstance(serviceType);
}
}
public class AuthOperationHandler : HttpOperationHandler<HttpRequestMessage, HttpRequestMessage>
{
protected override HttpRequestMessage OnHandle(HttpRequestMessage input)
{
// API Key validation here
var user = RetrieveUserByApiKey(input);
return input;
}
}
我找到了解决方案,但它确实有一个警告。
我这样做的方式是让我的操作处理程序返回某种形式的自定义身份验证状态类,而不是 HttpResponsemessage - 在我的例子中,我使用了 AuthenticationTicket。
public class AuthOperationHandler : HttpOperationHandler<HttpRequestMessage, AuthenticationTicket>
{
protected override AuthenticationTicket OnHandle(HttpRequestMessage input)
{
var ticket = RetrieveAuthenticationTicket(input);
return ticket;
}
}
AuthenticationTicket 类仅存储帐户 ID。
public class AuthenticationTicket
{
public AuthenticationTicket(int accountId)
{
AccountId = accountId;
}
public int AccountId { get; set; }
}
然后在您的服务方法中添加 AuthenticationTicket 作为参数,操作处理程序将为您填充该参数。
[OperationContract]
[WebInvoke(UriTemplate = "people", Method = "GET")]
HttpResponseMessage<IList<Person>> LoadPeople(AuthenticationTicket ticket);
然后您可以在方法实现中使用该票证。
但是,如果您需要使用附加参数,那么对于 POST、PUT 和 DELETE 操作,这会有点有趣,如下所示:
[OperationContract]
[WebInvoke(UriTemplate = "people", Method = "PUT")]
HttpResponseMessage AddPerson(AuthenticationTicket ticket, Person person);
您将得到如下异常:
HttpOperationHandlerFactory 无法确定输入 与请求消息内容关联的参数 用于服务操作“AddPerson”。如果操作不符合预期 请求消息中的内容使用 HTTP GET 方法, 手术。否则,请确保一个输入参数具有它的 IsContentParameter 属性设置为“True”或者是以下类型 可分配给以下内容之一:HttpContent、ObjectContent
1.1, HttpRequestMessage or HttpRequestMessage
我找到的解决方案(不确定是否正确)是将资源包装在 HttpRequestMessage 中,如下所示:
[OperationContract]
[WebInvoke(UriTemplate = "people", Method = "PUT")]
HttpResponseMessage UpdatePerson(AuthenticationTicket ticket, HttpRequestMessage<Person> request);
然后在您的方法中使用以下内容来检索人员:
var person = request.Content.ReadAsAsync<Person>().Result;
希望这有帮助,它对我有用。 但我仍在学习如何诚实,所以可能有更好的方法。