Web API中的基本身份验证

18

3个回答

34

你提供的链接包含了你所需的大部分细节,我希望这可以填补空白。

注意:如果使用 Web.API 2,Microsoft 建议使用 验证过滤器 采取不同的方法。

在服务器上设置 HTTPS

如果需要真正的安全性,这非常重要,否则密码可能会被窃听方获取。如何实现这一点完全取决于您的设置,但如果您正在处理 Azure WebRole,则可以从 Microsoft 获得相当不错的 逐步指南 来设置 SSL。

进行下一步操作不需要此操作,但应该在发布代码之前完成。我首先提到它是因为这部分通常涉及到其他人(系统管理员进行服务器配置,财务购买证书等),因此最好提前告知他们。

编写(或借鉴)自定义 IHttpModule 进行身份验证

这是你链接中的大块 C# 代码 - 它解析浏览器发送的值并将 HttpContext.Current.User 设置为经过身份验证的用户。只需将其复制并粘贴到您自己应用程序中的一个类中,稍后我们将回来修改它。您需要在代码中使用以下 using 语句。

using System; using System.Net.Http.Headers; using System.Security.Principal;
using System.Text; using System.Threading; using System.Web;

将该模块与您的应用程序关联

在您的web.config文件中添加一个新模块(请注意,system.webServer可能已存在)。

<system.webServer>
  <modules>
    <add name="BasicAuth" type="Full.ClassName.Path.BasicAuth, Assembly.Name"/>
  </modules>
</system.webServer>

限制访问您网站的相关部分

您可以通过在操作定义前添加[Authorize]属性来阻止特定操作。通过在控制器类之前添加它,可以阻止整个控制器。

[Authorize] // Restricts access to whole controller    
public class StockController : ApiController {
    [Authorize] // Restricts access to this action - not necessary if whole controller restricted.
    public IEnumerable<StockLevel> Get() {

你可以在 App_Start\WebApiConfig.cs 文件中添加 config.Filters.Add(new AuthorizeAttribute());,这将会锁定所有内容。

需要注意的是 - 还有一个System.Web.Mvc.AuthorizeAttribute,如果你已经引用了该命名空间,可能会导致混淆的结果。

现在你可以尝试它 - 用户名:"user",密码:"password"。

自定义用户验证

回到我们从链接中“偷来”的类,你会看到以下代码块:

// TODO: Here is where you would validate the username and password.
private static bool CheckPassword(string username, string password)

如果用户名和密码有效,请将其更改为返回true。如果您正在自行实现,您可能需要调查bcrypt(您信任从网络上下载的实现吗?)、PBKDF2Crypto类(简单但不是非常安全),但是因为有很多关于正确存储密码的问题,所以微软可能有更好的解决方案。


3
写得很好!这是我看过的最好的回复之一,真的帮助我更多地了解了BasicAuth以及如何按照我的需求设置它。谢谢! - Matt
Crypto类有什么不太安全的地方吗?看起来它正在使用PBKDF2,这正是您想要的:http://aspnetwebstack.codeplex.com/SourceControl/latest#src/System.Web.Helpers/Crypto.cs - Michael
2
Crypto 类仅执行了 1000 次迭代,这是在 2000 年发布的 RFC中建议的最小值,并且据我所知,它不允许您更改该值(您引用的代码将其作为常量)。阅读一下,您会发现自 2000 年以来每年都建议将其加倍 - 但它确实应该根据您的部署硬件进行调整,因为这是易于攻击和影响用户之间的权衡。有关更多详细信息,请参见此问题:http://security.stackexchange.com/questions/3959/recommended-of-iterations-when-using-pkbdf2-sha256 - Rob Church

1
我不得不在MSDN示例中添加几行代码才能使其正常工作。具体来说,在OnApplicationAuthenticateRequest()函数中,如果无法验证用户,则将响应状态码设置为401:
private static void OnApplicationAuthenticateRequest(object sender, EventArgs e)
        {
            var request = HttpContext.Current.Request;
            var authHeader = request.Headers["Authorization"];
            bool validated = false;
            if (authHeader != null)
            {
                var authHeaderVal = AuthenticationHeaderValue.Parse(authHeader);

                // RFC 2617 sec 1.2, "scheme" name is case-insensitive
                if (authHeaderVal.Scheme.Equals("basic",
                                                StringComparison.OrdinalIgnoreCase) &&
                    authHeaderVal.Parameter != null)
                {
                    validated = AuthenticateUser(authHeaderVal.Parameter);
                }
            }

            if (!validated)
            {
                HttpContext.Current.Response.StatusCode = 401;
            }
        }

我这样做之后,它就正常工作了。可能有更好的逻辑结构方式,但这是离示例最接近且能完成任务的最小更改。


通过您的修改,即使是那些不需要身份验证的请求也会被验证。当 authHeader 为空时,validate 将保持为 false,并返回 401。那么,不需要身份验证的页面/资源(即使用 [AllowAnonymous] 装饰的控制器/操作)将缺少 authHeader…对吗?或者我需要更多的咖啡 :) - zam6ak
你可能是对的。我还在学习这些东西。我已经从HttpModule更改为HttpHandler来实现,但是你的评论仍然适用 - 如果我有一个带有[AllowAnonymous]的页面,它仍然会尝试进行身份验证。如果你知道更好的方法,我非常愿意听取。 - Eric Pohl
链接中的代码可以直接使用,无需进行任何修改。您不需要 if (!validated) {...} 块 - 我相信 OnApplicationEndRequest() 方法已经“处理”了这个问题。 - zam6ak

1

要在每个控制器或方法的基础上选择性地启用基本身份验证,您可以从AuthorizeAttribute派生,如this question所述。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接