我目前正在开发基于WCF4的REST Web服务。大多数调用不需要授权,但有些调用需要授权,因此我的计划是实现一个 RequireAuthorization 属性,该属性处理某些调用的API密钥授权。
阅读Implementing an Authorization Attribute for 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;
}
}
答案 0 :(得分:3)
我找到了解决方法,但它确实有一个警告。
我这样做的方法是让我的操作处理程序返回某种形式的自定义身份验证状态类而不是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, HttpRequestMessage or HttpRequestMessage
1。
我找到的解决方案(不确定它是否正确)是将资源包装在HttpRequestMessage中,如下所示:
[OperationContract]
[WebInvoke(UriTemplate = "people", Method = "PUT")]
HttpResponseMessage UpdatePerson(AuthenticationTicket ticket, HttpRequestMessage<Person> request);
然后在您的方法中使用以下内容检索Person:
var person = request.Content.ReadAsAsync<Person>().Result;
希望这会有所帮助,它对我有用。但我仍然要学会诚实,所以可能有更好的方法。