ASP.NET Web API中的用户身份验证


150

这个话题使我感到困惑。我是HTTP应用程序的新手,但需要开发一个iPhone客户端,该客户端从某个地方使用JSON数据。我之所以选择MS的Web API,是因为它看起来很简单,但是在进行用户身份验证时,事情变得非常令人沮丧。

在经过数小时的谷歌搜索后Authorize,我无法找到一个清晰的示例来说明如何对用户进行身份验证,这从登录屏幕一直到在我的ApiController方法上使用属性令我感到惊讶。

这不是问题,而是要求提供有关如何精确执行此操作的示例的请求。我看了以下几页:

即使这些内容解释了如何处理未经授权的请求,但这些内容都没有清楚地显示出诸如a LoginController或类似的东西来询问用户凭据并对其进行验证。

有人愿意写一个简单的例子或指出正确的方向吗?

谢谢。


1
:我有一种对这个回答同一个问题的 stackoverflow.com/questions/11775594/...
cuongle

对于带有asp.net的Web Api,您可以像使用mvc应用程序一样使用cookie和formsauthentication模块(如果需要)。因此,例如,您可以在Web api代码中检查主体以查看用户是否已登录(与以前相同)。
Elliot 2013年


我强烈建议许多人阅读asp.net/web-api/overview/security/…文章。
Youngjae 2014年

Answers:


176

在几个小时的谷歌搜索之后,我无法找到一个清晰的示例来说明如何对用户进行身份验证,这从登录屏幕一直到在ApiController方法上使用Authorize属性,我感到惊讶。

这是因为您对这两个概念感到困惑:

  • 认证是系统可以安全地标识其用户的机制。身份验证系统为以下问题提供了答案:

    • 用户是谁?
    • 用户真的是他/她自己代表的人吗?
  • 授权是一种机制,系统通过该机制确定特定的经过身份验证的用户对系统控制的安全资源应具有的访问级别。例如,可以设计数据库管理系统,以便为某些特定的个人提供从数据库中检索信息的能力,而不是为更改存储在数据库中的数据的能力,同时为其他个人提供更改数据的能力。授权系统提供以下问题的答案:

    • 用户X是否有权访问资源R?
    • 用户X是否有权执行操作P?
    • 用户X是否被授权对资源R执行操作P?

AuthorizeMVC中的属性用于应用访问规则,例如:

 [System.Web.Http.Authorize(Roles = "Admin, Super User")]
 public ActionResult AdministratorsOnly()
 {
     return View();
 }

上面的规则将仅允许具有AdminSuper User角色的用户访问该方法

也可以使用location元素在web.config文件中设置这些规则。例:

  <location path="Home/AdministratorsOnly">
    <system.web>
      <authorization>
        <allow roles="Administrators"/>
        <deny users="*"/>
      </authorization>
    </system.web>
  </location>

但是,在执行这些授权规则之前,必须先对当前网站进行身份验证

即使这些解释了如何处理未经授权的请求,也没有清楚地演示诸如LoginController之类的内容或要求用户凭据并对其进行验证的内容。

从这里,我们可以将问题分成两部分:

  • 在同一Web应用程序中使用Web API服务时对用户进行身份验证

    这将是最简单的方法,因为您将依赖ASP.Net中身份验证

    这是一个简单的示例:

    Web.config

    <authentication mode="Forms">
      <forms
        protection="All"
        slidingExpiration="true"
        loginUrl="account/login"
        cookieless="UseCookies"
        enableCrossAppRedirects="false"
        name="cookieName"
      />
    </authentication>
    

    用户将被重定向到帐户/登录路线,在那里您将呈现自定义控件以询问用户凭据,然后使用以下命令设置身份验证cookie:

        if (ModelState.IsValid)
        {
            if (Membership.ValidateUser(model.UserName, model.Password))
            {
                FormsAuthentication.SetAuthCookie(model.UserName, model.RememberMe);
                return RedirectToAction("Index", "Home");
            }
            else
            {
                ModelState.AddModelError("", "The user name or password provided is incorrect.");
            }
        }
    
        // If we got this far, something failed, redisplay form
        return View(model);
    
  • 跨平台认证

    这种情况是在您仅在Web应用程序中公开Web API服务时,因此,您将有另一个客户端使用该服务,该客户端可以是另一个Web应用程序或任何.Net应用程序(Win Forms,WPF,控制台,Windows服务,等等)

    例如,假定您将使用同一网络域(在Intranet内)中另一个Web应用程序提供的Web API服务,在这种情况下,您可以依赖ASP.Net提供的Windows身份验证。

    <authentication mode="Windows" />

    如果您的服务在Internet上公开,则需要将经过身份验证的令牌传递给每个Web API服务。

    有关更多信息,请掠夺以下文章:


3
哇!这就是我所说的答案。因此,总结一下。我打算执行以下操作:1.使用Login方法创建一个帐户控制器,该方法通过HTTPS接收用户名和密码,并返回登录结果和令牌。2.客户端存储令牌,并在请求中将其作为标头(不再有HTTPS)发送,并由Web服务器验证。那是一个好方法吗?然后,我最后的疑问是如何控制令牌的篡改和到期。这可能吗?
Luis Aguilar

6
@Jupaol我想我是为许多Web API开发人员讲的,我不能使用Forms Authentication,因为我没有网站,而且客户端没有在使用浏览器,我也不能使用Integrated Authentication,因为用户可以在任何设备上位于世界任何地方(因此是Web API),那么我该怎么用?
markmnl 2014年

21
我不明白为什么这个答案会得到如此多的赞誉。它与ASP.NET Web API无关,而与ASP.NET MVC有关。
Bastien Vandamme 2014年

3
我想重申B413的评论,并指出此问题专门要求使用Web API
Julien

6
这是关于SO的最投票赞成的“错误”答案吗?答案实际上并没有谈论与MVC Web应用程序有很大不同的Web API!像@ B413一样,我感到非常震惊!
stt106

15

如果要通过用户名和密码进行身份验证并且没有授权cookie,则MVC4 Authorize属性将无法立即使用。但是,您可以将以下辅助方法添加到控制器中以接受基本身份验证标头。从控制器方法的开头调用它。

void EnsureAuthenticated(string role)
{
    string[] parts = UTF8Encoding.UTF8.GetString(Convert.FromBase64String(Request.Headers.Authorization.Parameter)).Split(':');
    if (parts.Length != 2 || !Membership.ValidateUser(parts[0], parts[1]))
        throw new HttpResponseException(Request.CreateErrorResponse(HttpStatusCode.Unauthorized, "No account with that username and password"));
    if (role != null && !Roles.IsUserInRole(parts[0], role))
        throw new HttpResponseException(Request.CreateErrorResponse(HttpStatusCode.Unauthorized, "An administrator account is required"));
}

在客户端,此帮助程序将创建一个HttpClient带有身份验证标头的:

static HttpClient CreateBasicAuthenticationHttpClient(string userName, string password)
{
    var client = new HttpClient();
    client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Basic", Convert.ToBase64String(UTF8Encoding.UTF8.GetBytes(userName + ':' + password)));
    return client;
}

只是想评论一下,我在寻找一种简单的方法来使用行业标准在标题中传递凭据。这个例子展示了服务器端和客户端的基础知识,而这正是我所需要的。
da_jokker

9

我正在从事MVC5 / Web API项目,需要能够获得Web Api方法的授权。首次加载索引视图时,我会调用“令牌” Web API方法,该方法相信会自动创建。

获取令牌的客户端代码(CoffeeScript)为:

getAuthenticationToken = (username, password) ->
    dataToSend = "username=" + username + "&password=" + password
    dataToSend += "&grant_type=password"
    $.post("/token", dataToSend).success saveAccessToken

如果成功,将调用以下命令,这会将身份验证令牌保存在本地:

saveAccessToken = (response) ->
    window.authenticationToken = response.access_token

然后,如果需要对具有[Authorize]标记的Web API方法进行Ajax调用,则只需将以下标头添加到我的Ajax调用中:

{ "Authorization": "Bearer " + window.authenticationToken }

从哪里不response.access_token来的。您是通过C#代码进行设置的吗?
shashwat 2014年

“响应”对象由“令牌”方法返回。
ProfNimrod

我还没有研究角色。这种方法只为您提供访问令牌,因此您可以调用装饰有[Authorize]标记的WebApi方法。大概,当您调用这些方法中的任何一个时,您都可以检查角色。 stackoverflow.com/questions/19689570/mvc-5-check-user-role可能会有所帮助。
ProfNimrod

在此解决方案中,您实际上在哪里对用户进行身份验证?
Craig Brett

/ token端点是为任何新的Web API项目自动创建的。在此后面的代码是对用户进行身份验证的地方。如果您将Web API控制器添加到现有的MVC项目中,则情况会有些复杂。
ProfNimrod '17
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.