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

User Authentication in ASP.NET Web API

这个话题让我非常困惑。我是HTTP应用程序的新手,但我需要开发一个iPhone客户端,它使用来自某个地方的JSON数据。我从MS中选择Web API是因为它看起来很简单,但是当涉及到认证用户时,事情变得非常令人沮丧。

我很惊讶,我没有找到一个清晰的例子来验证用户的权限,从登录屏幕一直到在我的ApiController方法上使用Authorize属性,经过几个小时的谷歌搜索。

这不是一个问题,而是一个如何准确做到这一点的例子的请求。我看了以下几页:

  • 使您的ASP.NET Web API安全
  • 使用ASP.NET Web API进行基本身份验证

尽管这些解释了如何处理未经授权的请求,但它们并不能清楚地显示出类似于LoginController或类似的东西来请求用户凭证并验证它们。

有人愿意写一个很好的简单的例子,或者给我指出正确的方向吗?

谢谢。


I am amazed how I've not been able to find a clear example of how to authenticate an user right from the login screen down to using the Authorize attribute over my ApiController methods after several hours of Googling.

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

  • 认证是系统安全地识别用户的机制。认证系统提供问题的答案:

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

    • 用户x有权访问资源r吗?
    • 用户x有权执行操作p吗?
    • 用户x有权在资源r上执行操作p吗?

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

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

上面的规则将只允许管理员和超级用户角色中的用户访问该方法。

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

1
2
3
4
5
6
7
8
  <location path="Home/AdministratorsOnly">
    <system.web>
     
       
        <deny users="*"/>
      </authorization>
    </system.web>
  </location>

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

Even though these explain how to handle unauthorized requests, these do not demonstrate clearly something like a LoginController or something like that to ask for user credentials and validate them.

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

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

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

    这是一个简单的例子:

    Web.CONFIG
    1
    2
    3
    4
    5
    6
    7
    8
    9
      <forms
        protection="All"
        slidingExpiration="true"
        loginUrl="account/login"
        cookieless="UseCookies"
        enableCrossAppRedirects="false"
        name="cookieName"
      />
    </authentication>

    用户将被重定向到帐户/登录路径,在该路径中,您将呈现自定义控件以请求用户凭据,然后使用以下方式设置身份验证cookie:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
        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、console、windows服务等)。

    例如,假设您将使用来自同一网络域(内部网)上其他Web应用程序的Web API服务,在这种情况下,您可以依赖ASP.NET提供的Windows身份验证。

    1
     

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

    有关详细信息,请在以下文章中获取战利品:

    • http://stevescodingblog.co.uk/basic-authentication-with-asp-net-webapi/

    • http://codebetter.com/johnvpetersen/2012/04/02/making-your-asp-net-web-apis-secure/


如果要根据用户名和密码进行身份验证,而不使用授权cookie,MVC4 authorize属性将无法正常工作。但是,可以向控制器添加以下helper方法以接受基本身份验证头。从控制器方法的开头调用它。

1
2
3
4
5
6
7
8
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,并将身份验证头放在适当的位置:

1
2
3
4
5
6
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;
}


我正在开发一个MVC5/WebAPI项目,需要能够获得WebAPI方法的授权。当我的索引视图第一次加载时,我会调用我认为是自动创建的"token"Web API方法。

获取令牌的客户端代码(coffeescript)是:

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

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

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

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

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