如何确保ASP。净Web API

时间:2021-09-16 17:48:41

I want to build a RESTful web service using ASP.NET Web API that third-party developers will use to access my application's data.

我想使用ASP构建一个RESTful web服务。第三方开发人员用来访问我的应用程序数据的NET Web API。

I've read quite a lot about OAuth and it seems to be the standard, but finding a good sample with documentation explaining how it works (and that actually does work!) seems to be incredibly difficult (especially for a newbie to OAuth).

我读过很多关于OAuth的文章,它似乎是标准的,但是找到一个很好的例子来说明它是如何工作的(实际上它确实有效!)

Is there a sample that actually builds and works and shows how to implement this?

是否有一个实际构建和工作的示例并展示如何实现它?

I've downloaded numerous samples:

我已经下载了很多样品:

  • DotNetOAuth - documentation is hopeless from a newbie perspective
  • 从新手的角度来看,文档是没有希望的
  • Thinktecture - can't get it to build
  • 无法让它构建

I've also looked at blogs suggesting a simple token-based scheme (like this) - this seems like re-inventing the wheel but it does have the advantage of being conceptually fairly simple.

我也看过一些博客,建议一个简单的基于记号的方案(像这样)——这看起来像是在重新发明*,但它确实有概念上相当简单的优势。

It seems there are many questions like this on SO but no good answers.

好像有很多这样的问题,但是没有好的答案。

What is everybody doing in this space?

在这个空间里每个人都在做什么?

6 个解决方案

#1


260  

Update:

更新:

I have put my another answer how to use JWT authentication for Web API in here for anyone interested in JWT:

对于任何对JWT感兴趣的人,我在这里给出了另一个关于如何对Web API使用JWT身份验证的答案:

JWT Authentication for Asp.Net Web Api

JWT认证为Asp。净Web Api


We have managed to apply HMAC authentication to secure Web API, and it worked okay. HMAC authentication uses a secret key for each consumer which both consumer and server both know to hmac hash a message, HMAC256 should be used. Most of the cases, hashed password of the consumer is used as a secret key.

我们已经成功地应用HMAC身份验证来保护Web API,并且运行良好。HMAC身份验证对每个使用者和服务器都知道的每个使用者使用一个秘密密钥来哈希消息,应该使用HMAC256。大多数情况下,用户的散列密码被用作密钥。

The message normally is built from data in the HTTP request, or even customized data which is added to HTTP header, the message might include:

消息通常是由HTTP请求中的数据构建的,甚至是添加到HTTP报头中的定制数据,消息可能包括:

  1. Timestamp: time that request is sent (UTC or GMT)
  2. 时间戳:发送请求的时间(UTC或GMT)
  3. HTTP verb: GET, POST, PUT, DELETE.
  4. HTTP动词:GET、POST、PUT、DELETE。
  5. post data and query string,
  6. 发布数据和查询字符串,
  7. URL
  8. URL

Under the hood, HMAC authentication would be:

在准则下,HMAC认证将是:

Consumer sends a HTTP request to web server, after building the signature (output of hmac hash), the template of HTTP request:

消费者在构建了HTTP请求的模板(hmac哈希的输出)之后,向web服务器发送一个HTTP请求:

User-Agent: {agent}   
Host: {host}   
Timestamp: {timestamp}
Authentication: {username}:{signature}

Example for GET request:

GET请求的示例:

GET /webapi.hmac/api/values

User-Agent: Fiddler    
Host: localhost    
Timestamp: Thursday, August 02, 2012 3:30:32 PM 
Authentication: cuongle:LohrhqqoDy6PhLrHAXi7dUVACyJZilQtlDzNbLqzXlw=

The message to hash to get signature:

要得到签名的哈希消息:

GET\n
Thursday, August 02, 2012 3:30:32 PM\n
/webapi.hmac/api/values\n

Example for POST request with query string (signature below is not correct, just an example)

使用查询字符串的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

The message to hash to get signature

哈希的消息以获取签名

GET\n
Thursday, August 02, 2012 3:30:32 PM\n
/webapi.hmac/api/values\n
key1=value1&key2=value2&key3=value3

Please note that form data and query string should be in order, so the code on the server get query string and form data to build the correct message.

请注意,表单数据和查询字符串应该是有序的,因此服务器上的代码将获得查询字符串和表单数据以构建正确的消息。

When HTTP request comes to the server, an authentication action filter is implemented to parse the request to get information: HTTP verb, timestamp, uri, form data and query string, then based on these to build signature (use hmac hash) with the secret key (hashed password) on the server.

当HTTP请求到达服务器时,将实现一个身份验证操作过滤器来解析请求以获取信息:HTTP谓词、时间戳、uri、表单数据和查询字符串,然后基于这些构建签名(使用hmac散列)和服务器上的密钥(散列密码)。

The secret key is got from the database with the username on the request.

密钥从数据库中获取,其中包含请求的用户名。

Then server code compares the signature on the request with the signature built; if equal, authentication is passed, otherwise, it failed.

然后服务器代码将请求上的签名与所构建的签名进行比较;如果相等,则传递身份验证,否则失败。

The code to build signature:

构建签名的代码:

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;
}

So, how to prevent replay attack?

那么,如何防止重播攻击呢?

Add constraint for the timestamp, something like:

为时间戳添加约束,如下所示:

servertime - X minutes|seconds  <= timestamp <= servertime + X minutes|seconds 

(servertime: time of request coming to server)

(服务器时间:请求到达服务器的时间)

And, cache the signature of the request in memory (use MemoryCache, should keep in the limit of time). If the next request comes with the same signature with the previous request, it will be rejected.

并且,将请求的签名缓存到内存中(使用MemoryCache,应该在限定的时间内保存)。如果下一个请求与前一个请求具有相同的签名,那么它将被拒绝。

The demo code is put as here: https://github.com/cuongle/Hmac.WebApi

演示代码如下:https://github.com/cuongle/Hmac.WebApi

#2


30  

I would suggest starting with the most straightforward solutions first - maybe simple HTTP Basic Authentication + HTTPS is enough in your scenario.

我建议先从最简单的解决方案开始——在您的场景中,简单的HTTP基本身份验证+ HTTPS就足够了。

If not (for example you cannot use https, or need more complex key management), you may have a look at HMAC-based solutions as suggested by others. A good example of such API would be Amazon S3 (http://s3.amazonaws.com/doc/s3-developer-guide/RESTAuthentication.html)

如果没有(例如,您不能使用https,或者需要更复杂的密钥管理),您可以按照其他人的建议查看基于hmac的解决方案。这种API的一个很好的例子是Amazon S3 (http://s3.amazonaws.com/doc/s3-developer-guide/RESTAuthentication.html)

I wrote a blog post about HMAC based authentication in ASP.NET Web API. It discusses both Web API service and Web API client and the code is available on bitbucket. http://www.piotrwalat.net/hmac-authentication-in-asp-net-web-api/

我写了一篇关于基于HMAC的ASP认证的博文。净Web API。它讨论了Web API服务和Web API客户端,代码在bitbucket上是可用的。http://www.piotrwalat.net/hmac-authentication-in-asp-net-web-api/

Here is a post about Basic Authentication in Web API: http://www.piotrwalat.net/basic-http-authentication-in-asp-net-web-api-using-message-handlers/

下面是一篇关于Web API中基本身份验证的文章:http://www.piotrwalat.net/basic-http- Authentication -in-asp-net- Web - API - use -message-handlers/

Remember that if you are going to provide an API to 3rd parties, you will also most likely be responsible for delivering client libraries. Basic authentication has a significant advantage here as it is supported on most programming platforms out of the box. HMAC, on the other hand, is not that standardized and will require custom implementation. These should be relatively straightforward but still require work.

请记住,如果您要向第三方提供API,那么您也很可能要负责交付客户端库。在这里,基本身份验证有一个显著的优势,因为它在大多数编程平台上都是开箱即用的。另一方面,HMAC并没有那么标准化,需要自定义实现。这些应该相对简单,但仍然需要工作。

PS. There is also an option to use HTTPS + certificates. http://www.piotrwalat.net/client-certificate-authentication-in-asp-net-web-api-and-windows-store-apps/

还有一个使用HTTPS +证书的选项。http://www.piotrwalat.net/client-certificate-authentication-in-asp-net-web-api-and-windows-store-apps/

#3


21  

Have you tried DevDefined.OAuth?

你有试过DevDefined.OAuth吗?

I have used it to secure my WebApi with 2-Legged OAuth. I have also successfully tested it with PHP clients.

我用它来保护我的WebApi和两条腿的OAuth。我还成功地用PHP客户端测试了它。

It's quite easy to add support for OAuth using this library. Here's how you can implement the provider for ASP.NET MVC Web API:

使用这个库很容易添加对OAuth的支持。以下是如何实现ASP的提供者。NET MVC Web API:

1) Get the source code of DevDefined.OAuth: https://github.com/bittercoder/DevDefined.OAuth - the newest version allows for OAuthContextBuilder extensibility.

1)获取DevDefined的源代码。最新版本允许OAuthContextBuilder的可扩展性。

2) Build the library and reference it in your Web API project.

2)构建库并在Web API项目中引用它。

3) Create a custom context builder to support building a context from HttpRequestMessage:

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));
    }
}

4) Use this tutorial for creating an OAuth provider: http://code.google.com/p/devdefined-tools/wiki/OAuthProvider. In the last step (Accessing Protected Resource Example) you can use this code in your AuthorizationFilterAttribute attribute:

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()
            };
    }
}

I have implemented my own provider so I haven't tested the above code (except of course the WebApiOAuthContextBuilder which I'm using in my provider) but it should work fine.

我已经实现了我自己的提供程序,所以我还没有测试上面的代码(当然除了我在提供程序中使用的WebApiOAuthContextBuilder),但是它应该可以正常工作。

#4


19  

Web API introduced an Attribute [Authorize] to provide security. This can be set globally (global.asx)

Web API引入了一个属性[Authorize]来提供安全性。可以全局设置(global.asx)

public static void Register(HttpConfiguration config)
{
    config.Filters.Add(new AuthorizeAttribute());
}

Or per controller:

或每个控制器:

[Authorize]
public class ValuesController : ApiController{
...

Of course your type of authentication may vary and you may want to perform your own authentication, when this occurs you may find useful inheriting from Authorizate Attribute and extending it to meet your requirements:

当然,您的身份验证类型可能会有所不同,您可能想要执行您自己的身份验证,当发生这种情况时,您可能会从Authorizate属性中发现有用的继承,并扩展它以满足您的需求:

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;
        }
    }
}

And in your controller:

和在你的控制器:

[DemoAuthorize]
public class ValuesController : ApiController{

Here is a link on other custom implemenation for WebApi Authorizations:

下面是关于WebApi授权的其他自定义实现的链接:

http://www.piotrwalat.net/basic-http-authentication-in-asp-net-web-api-using-membership-provider/

http://www.piotrwalat.net/basic-http-authentication-in-asp-net-web-api-using-membership-provider/

#5


5  

If you want to secure your API in a server to server fashion (no redirection to website for 2 legged authentication). You can look at OAuth2 Client Credentials Grant protocol.

如果您想要在服务器中保护您的API,以服务器的方式(不需要重定向到网站进行两条腿的身份验证)。您可以查看OAuth2客户端凭证授予协议。

https://dev.twitter.com/docs/auth/application-only-auth

https://dev.twitter.com/docs/auth/application-only-auth

I have developed a library that can help you easily add this kind of support to your WebAPI. You can install it as a NuGet package:

我已经开发了一个库,可以帮助您轻松地将这种支持添加到您的WebAPI中。您可以将其安装为NuGet包:

https://nuget.org/packages/OAuth2ClientCredentialsGrant/1.0.0.0

https://nuget.org/packages/OAuth2ClientCredentialsGrant/1.0.0.0

The library targets .NET Framework 4.5.

库的目标是。net Framework 4.5。

Once you add the package to your project, it will create a readme file in the root of your project. You can look at that readme file to see how to configure/use this package.

一旦将包添加到项目中,它将在项目的根目录中创建一个readme文件。您可以查看该readme文件,了解如何配置/使用此包。

Cheers!

干杯!

#6


2  

in continuation to @ Cuong Le's answer , my approach to prevent replay attack would be

继续@ Cuong Le的回答,我防止重播攻击的方法是

// Encrypt the Unix Time at Client side using the shared private key(or user's password)

//使用共享私钥(或用户密码)在客户端加密Unix时间

// Send it as part of request header to server(WEB API)

//作为请求头的一部分发送给服务器(WEB API)

// Decrypt the Unix Time at Server(WEB API) using the shared private key(or user's password)

//使用共享私钥(或用户密码)在服务器(WEB API)解密Unix时间

// Check the time difference between the Client's Unix Time and Server's Unix Time, should not be greater than x sec

//检查客户的Unix时间和服务器的Unix时间之间的时间差,不应该大于x秒。

// if User ID/Hash Password are correct and the decrypted UnixTime is within x sec of server time then it is a valid request

//如果用户ID/散列密码是正确的,并且解密的UnixTime在服务器时间的x秒内,那么它就是一个有效的请求

#1


260  

Update:

更新:

I have put my another answer how to use JWT authentication for Web API in here for anyone interested in JWT:

对于任何对JWT感兴趣的人,我在这里给出了另一个关于如何对Web API使用JWT身份验证的答案:

JWT Authentication for Asp.Net Web Api

JWT认证为Asp。净Web Api


We have managed to apply HMAC authentication to secure Web API, and it worked okay. HMAC authentication uses a secret key for each consumer which both consumer and server both know to hmac hash a message, HMAC256 should be used. Most of the cases, hashed password of the consumer is used as a secret key.

我们已经成功地应用HMAC身份验证来保护Web API,并且运行良好。HMAC身份验证对每个使用者和服务器都知道的每个使用者使用一个秘密密钥来哈希消息,应该使用HMAC256。大多数情况下,用户的散列密码被用作密钥。

The message normally is built from data in the HTTP request, or even customized data which is added to HTTP header, the message might include:

消息通常是由HTTP请求中的数据构建的,甚至是添加到HTTP报头中的定制数据,消息可能包括:

  1. Timestamp: time that request is sent (UTC or GMT)
  2. 时间戳:发送请求的时间(UTC或GMT)
  3. HTTP verb: GET, POST, PUT, DELETE.
  4. HTTP动词:GET、POST、PUT、DELETE。
  5. post data and query string,
  6. 发布数据和查询字符串,
  7. URL
  8. URL

Under the hood, HMAC authentication would be:

在准则下,HMAC认证将是:

Consumer sends a HTTP request to web server, after building the signature (output of hmac hash), the template of HTTP request:

消费者在构建了HTTP请求的模板(hmac哈希的输出)之后,向web服务器发送一个HTTP请求:

User-Agent: {agent}   
Host: {host}   
Timestamp: {timestamp}
Authentication: {username}:{signature}

Example for GET request:

GET请求的示例:

GET /webapi.hmac/api/values

User-Agent: Fiddler    
Host: localhost    
Timestamp: Thursday, August 02, 2012 3:30:32 PM 
Authentication: cuongle:LohrhqqoDy6PhLrHAXi7dUVACyJZilQtlDzNbLqzXlw=

The message to hash to get signature:

要得到签名的哈希消息:

GET\n
Thursday, August 02, 2012 3:30:32 PM\n
/webapi.hmac/api/values\n

Example for POST request with query string (signature below is not correct, just an example)

使用查询字符串的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

The message to hash to get signature

哈希的消息以获取签名

GET\n
Thursday, August 02, 2012 3:30:32 PM\n
/webapi.hmac/api/values\n
key1=value1&key2=value2&key3=value3

Please note that form data and query string should be in order, so the code on the server get query string and form data to build the correct message.

请注意,表单数据和查询字符串应该是有序的,因此服务器上的代码将获得查询字符串和表单数据以构建正确的消息。

When HTTP request comes to the server, an authentication action filter is implemented to parse the request to get information: HTTP verb, timestamp, uri, form data and query string, then based on these to build signature (use hmac hash) with the secret key (hashed password) on the server.

当HTTP请求到达服务器时,将实现一个身份验证操作过滤器来解析请求以获取信息:HTTP谓词、时间戳、uri、表单数据和查询字符串,然后基于这些构建签名(使用hmac散列)和服务器上的密钥(散列密码)。

The secret key is got from the database with the username on the request.

密钥从数据库中获取,其中包含请求的用户名。

Then server code compares the signature on the request with the signature built; if equal, authentication is passed, otherwise, it failed.

然后服务器代码将请求上的签名与所构建的签名进行比较;如果相等,则传递身份验证,否则失败。

The code to build signature:

构建签名的代码:

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;
}

So, how to prevent replay attack?

那么,如何防止重播攻击呢?

Add constraint for the timestamp, something like:

为时间戳添加约束,如下所示:

servertime - X minutes|seconds  <= timestamp <= servertime + X minutes|seconds 

(servertime: time of request coming to server)

(服务器时间:请求到达服务器的时间)

And, cache the signature of the request in memory (use MemoryCache, should keep in the limit of time). If the next request comes with the same signature with the previous request, it will be rejected.

并且,将请求的签名缓存到内存中(使用MemoryCache,应该在限定的时间内保存)。如果下一个请求与前一个请求具有相同的签名,那么它将被拒绝。

The demo code is put as here: https://github.com/cuongle/Hmac.WebApi

演示代码如下:https://github.com/cuongle/Hmac.WebApi

#2


30  

I would suggest starting with the most straightforward solutions first - maybe simple HTTP Basic Authentication + HTTPS is enough in your scenario.

我建议先从最简单的解决方案开始——在您的场景中,简单的HTTP基本身份验证+ HTTPS就足够了。

If not (for example you cannot use https, or need more complex key management), you may have a look at HMAC-based solutions as suggested by others. A good example of such API would be Amazon S3 (http://s3.amazonaws.com/doc/s3-developer-guide/RESTAuthentication.html)

如果没有(例如,您不能使用https,或者需要更复杂的密钥管理),您可以按照其他人的建议查看基于hmac的解决方案。这种API的一个很好的例子是Amazon S3 (http://s3.amazonaws.com/doc/s3-developer-guide/RESTAuthentication.html)

I wrote a blog post about HMAC based authentication in ASP.NET Web API. It discusses both Web API service and Web API client and the code is available on bitbucket. http://www.piotrwalat.net/hmac-authentication-in-asp-net-web-api/

我写了一篇关于基于HMAC的ASP认证的博文。净Web API。它讨论了Web API服务和Web API客户端,代码在bitbucket上是可用的。http://www.piotrwalat.net/hmac-authentication-in-asp-net-web-api/

Here is a post about Basic Authentication in Web API: http://www.piotrwalat.net/basic-http-authentication-in-asp-net-web-api-using-message-handlers/

下面是一篇关于Web API中基本身份验证的文章:http://www.piotrwalat.net/basic-http- Authentication -in-asp-net- Web - API - use -message-handlers/

Remember that if you are going to provide an API to 3rd parties, you will also most likely be responsible for delivering client libraries. Basic authentication has a significant advantage here as it is supported on most programming platforms out of the box. HMAC, on the other hand, is not that standardized and will require custom implementation. These should be relatively straightforward but still require work.

请记住,如果您要向第三方提供API,那么您也很可能要负责交付客户端库。在这里,基本身份验证有一个显著的优势,因为它在大多数编程平台上都是开箱即用的。另一方面,HMAC并没有那么标准化,需要自定义实现。这些应该相对简单,但仍然需要工作。

PS. There is also an option to use HTTPS + certificates. http://www.piotrwalat.net/client-certificate-authentication-in-asp-net-web-api-and-windows-store-apps/

还有一个使用HTTPS +证书的选项。http://www.piotrwalat.net/client-certificate-authentication-in-asp-net-web-api-and-windows-store-apps/

#3


21  

Have you tried DevDefined.OAuth?

你有试过DevDefined.OAuth吗?

I have used it to secure my WebApi with 2-Legged OAuth. I have also successfully tested it with PHP clients.

我用它来保护我的WebApi和两条腿的OAuth。我还成功地用PHP客户端测试了它。

It's quite easy to add support for OAuth using this library. Here's how you can implement the provider for ASP.NET MVC Web API:

使用这个库很容易添加对OAuth的支持。以下是如何实现ASP的提供者。NET MVC Web API:

1) Get the source code of DevDefined.OAuth: https://github.com/bittercoder/DevDefined.OAuth - the newest version allows for OAuthContextBuilder extensibility.

1)获取DevDefined的源代码。最新版本允许OAuthContextBuilder的可扩展性。

2) Build the library and reference it in your Web API project.

2)构建库并在Web API项目中引用它。

3) Create a custom context builder to support building a context from HttpRequestMessage:

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));
    }
}

4) Use this tutorial for creating an OAuth provider: http://code.google.com/p/devdefined-tools/wiki/OAuthProvider. In the last step (Accessing Protected Resource Example) you can use this code in your AuthorizationFilterAttribute attribute:

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()
            };
    }
}

I have implemented my own provider so I haven't tested the above code (except of course the WebApiOAuthContextBuilder which I'm using in my provider) but it should work fine.

我已经实现了我自己的提供程序,所以我还没有测试上面的代码(当然除了我在提供程序中使用的WebApiOAuthContextBuilder),但是它应该可以正常工作。

#4


19  

Web API introduced an Attribute [Authorize] to provide security. This can be set globally (global.asx)

Web API引入了一个属性[Authorize]来提供安全性。可以全局设置(global.asx)

public static void Register(HttpConfiguration config)
{
    config.Filters.Add(new AuthorizeAttribute());
}

Or per controller:

或每个控制器:

[Authorize]
public class ValuesController : ApiController{
...

Of course your type of authentication may vary and you may want to perform your own authentication, when this occurs you may find useful inheriting from Authorizate Attribute and extending it to meet your requirements:

当然,您的身份验证类型可能会有所不同,您可能想要执行您自己的身份验证,当发生这种情况时,您可能会从Authorizate属性中发现有用的继承,并扩展它以满足您的需求:

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;
        }
    }
}

And in your controller:

和在你的控制器:

[DemoAuthorize]
public class ValuesController : ApiController{

Here is a link on other custom implemenation for WebApi Authorizations:

下面是关于WebApi授权的其他自定义实现的链接:

http://www.piotrwalat.net/basic-http-authentication-in-asp-net-web-api-using-membership-provider/

http://www.piotrwalat.net/basic-http-authentication-in-asp-net-web-api-using-membership-provider/

#5


5  

If you want to secure your API in a server to server fashion (no redirection to website for 2 legged authentication). You can look at OAuth2 Client Credentials Grant protocol.

如果您想要在服务器中保护您的API,以服务器的方式(不需要重定向到网站进行两条腿的身份验证)。您可以查看OAuth2客户端凭证授予协议。

https://dev.twitter.com/docs/auth/application-only-auth

https://dev.twitter.com/docs/auth/application-only-auth

I have developed a library that can help you easily add this kind of support to your WebAPI. You can install it as a NuGet package:

我已经开发了一个库,可以帮助您轻松地将这种支持添加到您的WebAPI中。您可以将其安装为NuGet包:

https://nuget.org/packages/OAuth2ClientCredentialsGrant/1.0.0.0

https://nuget.org/packages/OAuth2ClientCredentialsGrant/1.0.0.0

The library targets .NET Framework 4.5.

库的目标是。net Framework 4.5。

Once you add the package to your project, it will create a readme file in the root of your project. You can look at that readme file to see how to configure/use this package.

一旦将包添加到项目中,它将在项目的根目录中创建一个readme文件。您可以查看该readme文件,了解如何配置/使用此包。

Cheers!

干杯!

#6


2  

in continuation to @ Cuong Le's answer , my approach to prevent replay attack would be

继续@ Cuong Le的回答,我防止重播攻击的方法是

// Encrypt the Unix Time at Client side using the shared private key(or user's password)

//使用共享私钥(或用户密码)在客户端加密Unix时间

// Send it as part of request header to server(WEB API)

//作为请求头的一部分发送给服务器(WEB API)

// Decrypt the Unix Time at Server(WEB API) using the shared private key(or user's password)

//使用共享私钥(或用户密码)在服务器(WEB API)解密Unix时间

// Check the time difference between the Client's Unix Time and Server's Unix Time, should not be greater than x sec

//检查客户的Unix时间和服务器的Unix时间之间的时间差,不应该大于x秒。

// if User ID/Hash Password are correct and the decrypted UnixTime is within x sec of server time then it is a valid request

//如果用户ID/散列密码是正确的,并且解密的UnixTime在服务器时间的x秒内,那么它就是一个有效的请求