Cra*_*rer 389 c# asp.net-mvc oauth asp.net-web-api
我想使用ASP.NET Web API 构建RESTful Web服务,第三方开发人员将使用它来访问我的应用程序的数据.
我已经阅读了很多关于OAuth的内容,它似乎是标准的,但找到一个很好的样本,文档解释它是如何工作的(实际上确实有效!)似乎非常困难(特别是对于OAuth的新手).
是否有实际构建和工作的示例,并说明如何实现它?
我已经下载了很多样本:
我还看过一些博客,建议一个简单的基于令牌的方案(像这样) - 这似乎重新发明了轮子,但它确实具有概念上相当简单的优势.
似乎在SO上有很多这样的问题,但没有好的答案.
每个人在这个领域做什么?
cuo*_*gle 287
更新:
对于任何对JWT感兴趣的人,我已经在这里再次回答了如何对Web API使用JWT身份验证:
我们已经设法将HMAC身份验证应用于安全的Web API,并且它运行正常.HMAC身份验证为每个使用者使用一个密钥,消费者和服务器都知道hmac哈希消息,应该使用HMAC256.大多数情况下,消费者的散列密码被用作密钥.
消息通常是根据HTTP请求中的数据构建的,甚至是添加到HTTP头的自定义数据,消息可能包括:
在引擎盖下,HMAC身份验证将是:
在构建签名(hmac哈希的输出)之后,消费者向Web服务器发送HTTP请求,HTTP请求的模板:
User-Agent: {agent}
Host: {host}
Timestamp: {timestamp}
Authentication: {username}:{signature}
Run Code Online (Sandbox Code Playgroud)
GET请求示例:
GET /webapi.hmac/api/values
User-Agent: Fiddler
Host: localhost
Timestamp: Thursday, August 02, 2012 3:30:32 PM
Authentication: cuongle:LohrhqqoDy6PhLrHAXi7dUVACyJZilQtlDzNbLqzXlw=
Run Code Online (Sandbox Code Playgroud)
哈希获取签名的消息:
GET\n
Thursday, August 02, 2012 3:30:32 PM\n
/webapi.hmac/api/values\n
Run Code Online (Sandbox Code Playgroud)
带有查询字符串的POST请求示例(下面的签名不正确,只是一个示例)
POST /webapi.hmac/api/values?key2=value2
User-Agent: Fiddler
Host: localhost
Content-Type: application/x-www-form-urlencoded
Timestamp: Thursday, August 02, 2012 3:30:32 PM
Authentication: cuongle:LohrhqqoDy6PhLrHAXi7dUVACyJZilQtlDzNbLqzXlw=
key1=value1&key3=value3
Run Code Online (Sandbox Code Playgroud)
要哈希以获取签名的消息
GET\n
Thursday, August 02, 2012 3:30:32 PM\n
/webapi.hmac/api/values\n
key1=value1&key2=value2&key3=value3
Run Code Online (Sandbox Code Playgroud)
请注意,表单数据和查询字符串应该是有序的,因此服务器上的代码获取查询字符串和表单数据以构建正确的消息.
当HTTP请求到达服务器时,实现了一个身份验证操作过滤器来解析请求以获取信息:HTTP动词,时间戳,uri,表单数据和查询字符串,然后根据这些来构建签名(使用hmac哈希)和秘密密钥(散列密码)在服务器上.
使用请求上的用户名从数据库获取密钥.
然后,服务器代码将请求上的签名与构建的签名进行比较; 如果相等,则传递身份验证,否则失败.
构建签名的代码:
private static string ComputeHash(string hashedPassword, string message)
{
var key = Encoding.UTF8.GetBytes(hashedPassword.ToUpper());
string hashString;
using (var hmac = new HMACSHA256(key))
{
var hash = hmac.ComputeHash(Encoding.UTF8.GetBytes(message));
hashString = Convert.ToBase64String(hash);
}
return hashString;
}
Run Code Online (Sandbox Code Playgroud)
那么,如何防止重放攻击呢?
为时间戳添加约束,例如:
servertime - X minutes|seconds <= timestamp <= servertime + X minutes|seconds
Run Code Online (Sandbox Code Playgroud)
(servertime:请求到服务器的时间)
并且,将请求的签名缓存在内存中(使用MemoryCache,应该保持在时间限制内).如果下一个请求与前一个请求的签名相同,则会被拒绝.
演示代码如下:https: //github.com/cuongle/Hmac.WebApi
Pio*_*lat 31
我建议首先从最简单的解决方案开始 - 也许简单的HTTP基本身份验证+ HTTPS就足够了.
如果不是(例如,您不能使用https,或需要更复杂的密钥管理),您可能会看到其他人建议的基于HMAC的解决方案.这种API的一个很好的例子是Amazon S3(http://s3.amazonaws.com/doc/s3-developer-guide/RESTAuthentication.html)
我在ASP.NET Web API中写了一篇关于基于HMAC的身份验证的博客文章.它讨论了Web API服务和Web API客户端,代码在bitbucket上可用.http://www.piotrwalat.net/hmac-authentication-in-asp-net-web-api/
以下是关于Web API中基本身份验证的帖子:http://www.piotrwalat.net/basic-http-authentication-in-asp-net-web-api-using-message-handlers/
请记住,如果您要向第三方提供API,您也很可能负责提供客户端库.基本身份验证在这方面具有显着优势,因为它在大多数编程平台上都是开箱即用的.另一方面,HMAC不是标准化的,需要定制实施.这些应该相对简单但仍需要工作.
PS.还可以选择使用HTTPS +证书.http://www.piotrwalat.net/client-certificate-authentication-in-asp-net-web-api-and-windows-store-apps/
Mak*_*jer 23
你试过DevDefined.OAuth吗?
我使用它来保护我的WebApi与2-legged OAuth.我也成功地用PHP客户端测试了它.
使用此库添加对OAuth的支持非常容易.以下是如何实现ASP.NET MVC Web API的提供程序:
1)获取DevDefined.OAuth的源代码:https://github.com/bittercoder/DevDefined.OAuth - 最新版本允许OAuthContextBuilder可扩展性.
2)构建库并在Web API项目中引用它.
3)创建自定义上下文构建器以支持从HttpRequestMessage以下位置构建上下文:
using System;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Diagnostics.CodeAnalysis;
using System.Linq;
using System.Net.Http;
using System.Web;
using DevDefined.OAuth.Framework;
public class WebApiOAuthContextBuilder : OAuthContextBuilder
{
public WebApiOAuthContextBuilder()
: base(UriAdjuster)
{
}
public IOAuthContext FromHttpRequest(HttpRequestMessage request)
{
var context = new OAuthContext
{
RawUri = this.CleanUri(request.RequestUri),
Cookies = this.CollectCookies(request),
Headers = ExtractHeaders(request),
RequestMethod = request.Method.ToString(),
QueryParameters = request.GetQueryNameValuePairs()
.ToNameValueCollection(),
};
if (request.Content != null)
{
var contentResult = request.Content.ReadAsByteArrayAsync();
context.RawContent = contentResult.Result;
try
{
// the following line can result in a NullReferenceException
var contentType =
request.Content.Headers.ContentType.MediaType;
context.RawContentType = contentType;
if (contentType.ToLower()
.Contains("application/x-www-form-urlencoded"))
{
var stringContentResult = request.Content
.ReadAsStringAsync();
context.FormEncodedParameters =
HttpUtility.ParseQueryString(stringContentResult.Result);
}
}
catch (NullReferenceException)
{
}
}
this.ParseAuthorizationHeader(context.Headers, context);
return context;
}
protected static NameValueCollection ExtractHeaders(
HttpRequestMessage request)
{
var result = new NameValueCollection();
foreach (var header in request.Headers)
{
var values = header.Value.ToArray();
var value = string.Empty;
if (values.Length > 0)
{
value = values[0];
}
result.Add(header.Key, value);
}
return result;
}
protected NameValueCollection CollectCookies(
HttpRequestMessage request)
{
IEnumerable<string> values;
if (!request.Headers.TryGetValues("Set-Cookie", out values))
{
return new NameValueCollection();
}
var header = values.FirstOrDefault();
return this.CollectCookiesFromHeaderString(header);
}
/// <summary>
/// Adjust the URI to match the RFC specification (no query string!!).
/// </summary>
/// <param name="uri">
/// The original URI.
/// </param>
/// <returns>
/// The adjusted URI.
/// </returns>
private static Uri UriAdjuster(Uri uri)
{
return
new Uri(
string.Format(
"{0}://{1}{2}{3}",
uri.Scheme,
uri.Host,
uri.IsDefaultPort ?
string.Empty :
string.Format(":{0}", uri.Port),
uri.AbsolutePath));
}
}
Run Code Online (Sandbox Code Playgroud)
4)使用本教程创建OAuth提供程序:http://code.google.com/p/devdefined-tools/wiki/OAuthProvider.在最后一步(访问受保护资源示例)中,您可以在AuthorizationFilterAttribute属性中使用此代码:
public override void OnAuthorization(HttpActionContext actionContext)
{
// the only change I made is use the custom context builder from step 3:
OAuthContext context =
new WebApiOAuthContextBuilder().FromHttpRequest(actionContext.Request);
try
{
provider.AccessProtectedResourceRequest(context);
// do nothing here
}
catch (OAuthException authEx)
{
// the OAuthException's Report property is of the type "OAuthProblemReport", it's ToString()
// implementation is overloaded to return a problem report string as per
// the error reporting OAuth extension: http://wiki.oauth.net/ProblemReporting
actionContext.Response = new HttpResponseMessage(HttpStatusCode.Unauthorized)
{
RequestMessage = request, ReasonPhrase = authEx.Report.ToString()
};
}
}
Run Code Online (Sandbox Code Playgroud)
我已经实现了自己的提供程序,所以我没有测试上面的代码(当然除了WebApiOAuthContextBuilder我在我的提供程序中使用的代码 ),但它应该可以正常工作.
Dal*_*rzo 21
Web API引入了一个属性[Authorize]来提供安全性.这可以全局设置(global.asx)
public static void Register(HttpConfiguration config)
{
config.Filters.Add(new AuthorizeAttribute());
}
Run Code Online (Sandbox Code Playgroud)
或者每个控制器:
[Authorize]
public class ValuesController : ApiController{
...
Run Code Online (Sandbox Code Playgroud)
当然,您的身份验证类型可能会有所不同,您可能希望执行自己的身份验证,当发生这种情况时,您可能会发现从Authorizate Attribute继承并扩展它以满足您的要求:
public class DemoAuthorizeAttribute : AuthorizeAttribute
{
public override void OnAuthorization(System.Web.Http.Controllers.HttpActionContext actionContext)
{
if (Authorize(actionContext))
{
return;
}
HandleUnauthorizedRequest(actionContext);
}
protected override void HandleUnauthorizedRequest(System.Web.Http.Controllers.HttpActionContext actionContext)
{
var challengeMessage = new System.Net.Http.HttpResponseMessage(System.Net.HttpStatusCode.Unauthorized);
challengeMessage.Headers.Add("WWW-Authenticate", "Basic");
throw new HttpResponseException(challengeMessage);
}
private bool Authorize(System.Web.Http.Controllers.HttpActionContext actionContext)
{
try
{
var someCode = (from h in actionContext.Request.Headers where h.Key == "demo" select h.Value.First()).FirstOrDefault();
return someCode == "myCode";
}
catch (Exception)
{
return false;
}
}
}
Run Code Online (Sandbox Code Playgroud)
在你的控制器中:
[DemoAuthorize]
public class ValuesController : ApiController{
Run Code Online (Sandbox Code Playgroud)
以下是WebApi授权的其他自定义实现的链接:
http://www.piotrwalat.net/basic-http-authentication-in-asp-net-web-api-using-membership-provider/
如果您想以服务器到服务器的方式保护您的API(没有重定向到网站进行2腿认证).您可以查看OAuth2客户端凭据授予协议.
https://dev.twitter.com/docs/auth/application-only-auth
我开发了一个库,可以帮助您轻松地为WebAPI添加此类支持.您可以将其安装为NuGet包:
https://nuget.org/packages/OAuth2ClientCredentialsGrant/1.0.0.0
该库面向.NET Framework 4.5.
将包添加到项目后,它将在项目的根目录中创建自述文件.您可以查看该自述文件以了解如何配置/使用此程序包.
干杯!
| 归档时间: |
|
| 查看次数: |
261072 次 |
| 最近记录: |