C# 如何通过属性(AuthorizeAttribute)使其他数据可用于ApicController方法

C# 如何通过属性(AuthorizeAttribute)使其他数据可用于ApicController方法,c#,asp.net-mvc,asp.net-web-api,C#,Asp.net Mvc,Asp.net Web Api,我们的Web API将要求API的使用者提供我们分配给他们的API密钥。API密钥将用于授权,并将用于添加数据(在某处,以某种方式),以便ApiController的方法可以访问这些数据 我正在考虑创建一个AuthorizationAttribute 检查API密钥是否存在 验证提供的API密钥对传入请求(referer)有效 如果API键存在且有效,则它将用于获取ClientId和ClientName等数据,并将其添加到传入请求的属性集合中,供ApiController中的方法使用。我们可以

我们的Web API将要求API的使用者提供我们分配给他们的API密钥。API密钥将用于授权,并将用于添加数据(在某处,以某种方式),以便ApiController的方法可以访问这些数据

我正在考虑创建一个AuthorizationAttribute

  • 检查API密钥是否存在
  • 验证提供的API密钥对传入请求(referer)有效
  • 如果API键存在且有效,则它将用于获取ClientId和ClientName等数据,并将其添加到传入请求的属性集合中,供ApiController中的方法使用。我们可以将ClientId等编码到API密钥中,并在服务器端对其进行解码或从数据库中检索它
在我的模拟自定义AuthorizationAttribute中,如果授权成功,我将通过执行以下操作将clientId和clientName添加到当前请求中:

actionContext.Request.Properties.add("clientId", 1234);
actionContext.Request.Properties.add("clientName", "Super Client");
然后,在ApicController中的一个方法中,我使用以下方法获取数据:

int clientId = (int)Request.Properties["clientId"];
string clientName = (string)Request.Properties["clientName"];
这是可行的,但它假定在
Request.Properties
中存在“clientId”和“clientName”。我们可以使用
Request.Properties.ContainsKey
进行检查,但我不想在Web API的每个方法中重复此检查代码。我想我还可以使用另一个属性来进行检查,如果它在
Request.Properties
中找不到它们,则返回500个内部服务器错误(错误请求400?)

或者,我们可以让AuthorizationAttribute执行授权,然后在每个ApicController方法中进行一次调用,以返回一个客户端对象,其中包含给定JSON负载中提供的API密钥所需的数据。此时,我们知道API密钥是有效的,因此我们将获得控制器处理请求所需的数据

通过ApicController的方法向访问请求添加数据的推荐方法是什么?需要但基于提供的有效API密钥的数据(我们将从数据库中获取数据,或者将其编码为公共API密钥并在服务器上解码)。这将:

  • 最好不要违反DRY(检查ApiController所需的数据是否已添加,以及它们各自的值是否为正确的类型)
  • 确保值存在,并且方法可以在不引发异常的情况下执行
  • 是否应将其分为两个属性?一个进行授权,另一个根据提供的API密钥获取所需数据
我们正在运行VisualStudio2010、MVC4、.NET4。API密钥将作为JSON有效负载的一部分提供给web API


神奇的琴弦会消失;-)

一种方法是给客户端一个公共共享密钥和一个私钥。对于每个请求,客户机都需要将其公钥作为一个参数包含在过期日期中。过期日期的原因是,每个请求的授权令牌值都会有所不同。由于客户端将知道他们试图访问的资源,并且手头有公钥,因此他们只需要确保他们发送的过期日期在服务器认为的utc时间的允许阈值内。服务器和客户端都可以使用这些值及其假定的私钥创建安全哈希。然后,您可以通过使用私钥解密消息来验证发出请求-->公钥的客户机是否是他们所说的人

每个传入消息都需要签名。如果在查询字符串上,理论上它可能类似于以下注释:您也可以使用http头:

Signature=<UrlEncode(Base64(HMAC-MD5(LowerCase( AbsolutePath(ResourceURL)) + UTCDate(ExpirationDate,“yyyyMMddHHmmss”)))> &Expires=<UTCDate(ExpirationDate ,“yyyyMMddHHmmss”)>&AccessKey=<PublicAccessKey>
Signature=&Expires=&AccessKey=

对于您定义的每个需要授权的安全方法,如果哈希有效,您可以让调用通过,否则返回未经授权的http状态码。

我建议使用MessageHandler,而不是使用ActionFilters。MessageHandler可以查看请求,提取ClientId和ClientName(如果存在),并将它们添加到属性中。然后在需要提取该信息的控制器中,可以使用ApicController扩展方法访问controller.Request.Properties。这将封装您所有的魔法字符串


我还建议将APIKey放在Authorization报头中,而不是放在JSON有效负载中,因为这正是Authorization报头的设计目的。

我不认为OP在问如何创建API密钥。他们在询问应该以可管理的方式从密钥中提取标识信息的位置。@DarrellMiller我发现了一个作者提到授权头的位置。这是否符合你的建议?@DarrellMiller我发现我的一个观点措词不当(我在问题中修改并用斜体字表示)。ClientId和ClientName不会是请求的一部分,它们将根据传入的Api密钥进行检索。要么编码到我们提供给客户机的API密钥中,要么从数据库中检索它们。因此,您建议创建一个扩展方法来检查它们是否存在于Request.Properties中并已成功转换(string->int for ClientId)?@emgee Yes。您还可以使用某种属性和操作过滤器来检查请求属性。然而,我倾向于使用消息处理程序来处理API密钥,因为它将为每个请求提供。下面有一个简单的API密钥示例,大约是3/4。