ASP.NET Web API身份验证

122

我想在使用ASP.NET Web API时,从客户端应用程序对用户进行身份验证。我已经查看了该网站上的所有视频并阅读了此论坛帖子

正确地放置[Authorize]属性会返回401 Unauthorized状态。然而,我需要知道如何允许用户登录到API。

我想要从Android应用程序向API提供用户凭据,使用户登录并且所有后续API调用都经过预验证。


嗨,Mujtaba。你能实现这个吗? - Vivek Chandraprakash
首先使用CORS防止来自其他域的不必要的访问。然后随请求发送有效的Forms身份验证cookie,最后通过令牌授权请求。这种组合始终使您的Web API安全且优化。 - Majedur
4个回答

137

允许用户登录API。

您需要在请求中发送有效的Forms身份验证cookie。通常,当服务器通过调用[FormsAuthentication.SetAuthCookie]方法(请参见MSDN)进行身份验证(LogOn操作)时,会将此cookie发送。

因此,客户端需要执行两个步骤:

  1. 通过发送用户名和密码向LogOn操作发送HTTP请求。这个操作将调用FormsAuthentication.SetAuthCookie方法(如果凭据有效),该方法随后将在响应中设置表单身份验证cookie。
  2. 通过发送第一个请求中检索到的Forms身份验证cookie,向受[Authorize]保护的操作发送HTTP请求。

让我们举个例子。假设您的Web应用程序中定义了2个API控制器:

第一个控制器负责处理身份验证:

public class AccountController : ApiController
{
    public bool Post(LogOnModel model)
    {
        if (model.Username == "john" && model.Password == "secret")
        {
            FormsAuthentication.SetAuthCookie(model.Username, false);
            return true;
        }

        return false;
    }
}

还有第二个包含只有授权用户才能看到的受保护操作:

[Authorize]
public class UsersController : ApiController
{
    public string Get()
    {
        return "This is a top secret material that only authorized users can see";
    }
}

现在我们可以编写一个客户端应用程序来调用这个 API。以下是一个简单的控制台应用程序示例(确保已经安装了 Microsoft.AspNet.WebApi.ClientMicrosoft.Net.Http NuGet 包):

using System;
using System.Net.Http;
using System.Threading;

class Program
{
    static void Main()
    {
        using (var httpClient = new HttpClient())
        {
            var response = httpClient.PostAsJsonAsync(
                "http://localhost:26845/api/account", 
                new { username = "john", password = "secret" }, 
                CancellationToken.None
            ).Result;
            response.EnsureSuccessStatusCode();

            bool success = response.Content.ReadAsAsync<bool>().Result;
            if (success)
            {
                var secret = httpClient.GetStringAsync("http://localhost:26845/api/users");
                Console.WriteLine(secret.Result);
            }
            else
            {
                Console.WriteLine("Sorry you provided wrong credentials");
            }
        }
    }
}

以下是两个HTTP请求在网络上传输的样子:

身份验证请求:

POST /api/account HTTP/1.1
Content-Type: application/json; charset=utf-8
Host: localhost:26845
Content-Length: 39
Connection: Keep-Alive

{"username":"john","password":"secret"}

身份验证响应:

HTTP/1.1 200 OK
Server: ASP.NET Development Server/10.0.0.0
Date: Wed, 13 Jun 2012 13:24:41 GMT
X-AspNet-Version: 4.0.30319
Set-Cookie: .ASPXAUTH=REMOVED FOR BREVITY; path=/; HttpOnly
Cache-Control: no-cache
Pragma: no-cache
Expires: -1
Content-Type: application/json; charset=utf-8
Content-Length: 4
Connection: Close

true

请求保护数据:

GET /api/users HTTP/1.1
Host: localhost:26845
Cookie: .ASPXAUTH=REMOVED FOR BREVITY

受保护数据的响应:

HTTP/1.1 200 OK
Server: ASP.NET Development Server/10.0.0.0
Date: Wed, 13 Jun 2012 13:24:41 GMT
X-AspNet-Version: 4.0.30319
Cache-Control: no-cache
Pragma: no-cache
Expires: -1
Content-Type: application/json; charset=utf-8
Content-Length: 66
Connection: Close

"This is a top secret material that only authorized users can see"

它会为Android应用程序维护一个会话吗? - Mujtaba Hassan
2
编写Android HTTP客户端是另一个问题的主题。这与ASP.NET MVC和ASP.NET MVC Web API无关,这正是您所提出的问题。我建议您开始一个新线程,明确标记为Java和Android,在其中询问如何编写使用cookie发送请求的HTTP客户端。 - Darin Dimitrov
当然,我已经发布了一个例子。 - Darin Dimitrov
很高兴看到你发布了完整的代码,包括HTTP请求响应链; 我只能给+1。关于自定义标头,它是用于每个请求单独身份验证而不是提供令牌的,我认为。随着从WCF到Web API的转变,有些事情是新的。在WCF REST中,没有ASP.net基础设施来获取令牌,对吗?我相信每个调用都必须嵌入凭据? - Abhijit-K
2
还可以参考关于使用HTTP基本身份验证的问题(和答案):https://dev59.com/cGTWa4cB1Zd3GeqPHdol - Jim Harte
显示剩余8条评论

12

我以安卓为例。

public abstract class HttpHelper {

private final static String TAG = "HttpHelper";
private final static String API_URL = "http://your.url/api/";

private static CookieStore sCookieStore;

public static String invokePost(String action, List<NameValuePair> params) {
    try {
        String url = API_URL + action + "/";
        Log.d(TAG, "url is" + url);
        HttpPost httpPost = new HttpPost(url);
        if (params != null && params.size() > 0) {
            HttpEntity entity = new UrlEncodedFormEntity(params, "UTF-8");
            httpPost.setEntity(entity);
        }
        return invoke(httpPost);
    } catch (Exception e) {
        Log.e(TAG, e.toString());
    }

    return null;
}

public static String invokePost(String action) {
    return invokePost(action, null);
}

public static String invokeGet(String action, List<NameValuePair> params) {
    try {
        StringBuilder sb = new StringBuilder(API_URL);
        sb.append(action);
        if (params != null) {
            for (NameValuePair param : params) {
                sb.append("?");
                sb.append(param.getName());
                sb.append("=");
                sb.append(param.getValue());
            }
        }
        Log.d(TAG, "url is" + sb.toString());
        HttpGet httpGet = new HttpGet(sb.toString());
        return invoke(httpGet);
    } catch (Exception e) {
        Log.e(TAG, e.toString());
    }

    return null;
}

public static String invokeGet(String action) {
    return invokeGet(action, null);
}

private static String invoke(HttpUriRequest request)
        throws ClientProtocolException, IOException {
    String result = null;
    DefaultHttpClient httpClient = new DefaultHttpClient();

    // restore cookie
    if (sCookieStore != null) {
        httpClient.setCookieStore(sCookieStore);
    }

    HttpResponse response = httpClient.execute(request);

    StringBuilder builder = new StringBuilder();
    BufferedReader reader = new BufferedReader(new InputStreamReader(
            response.getEntity().getContent()));
    for (String s = reader.readLine(); s != null; s = reader.readLine()) {
        builder.append(s);
    }
    result = builder.toString();
    Log.d(TAG, "result is ( " + result + " )");

    // store cookie
    sCookieStore = ((AbstractHttpClient) httpClient).getCookieStore();
    return result;
}

请注意: i.不能使用localhost,Android设备将localhost视为其自身主机。 ii.如果在IIS中部署Web API,则必须开启表单身份验证。


0

使用这段代码并访问数据库

[HttpPost]
[Route("login")]
public IHttpActionResult Login(LoginRequest request)
{
       CheckModelState();
       ApiResponse<LoginApiResponse> response = new ApiResponse<LoginApiResponse>();
       LoginResponse user;
       var count = 0;
       RoleName roleName = new RoleName();
       using (var authManager = InspectorBusinessFacade.GetAuthManagerInstance())
       {
           user = authManager.Authenticate(request); 
       } reponse(ok) 
}

0
选择单用户身份验证 - 这将创建一个身份验证数据库,以在App_Data> *.mdf SQL文件中创建用户。 注册用户存储在dbo.AspNetUsers表中 - 请注意,密码以哈希格式存储在此表中。 使用此功能可用于登录网站,该网站带有[Autorize]属性 - 它将调用自动创建的页面函数 == > /api/account/register 注册页面脚本可以按如下方式使用 $(document).ready(function(){
        $('#lnkClose').click(function () {
             $('#divErrorText').hide('fade');
        });

        $('#btnRegister').click(function () {
            $.ajax({
                url: '/api/account/register',
                method: 'POST',
                data: {
                    Email: $('#txtEmail').val(),
                    Password: $('#txtPassword').val(),
                    ConfirmPassword: $('#txtConfirmPassword').val()

                },
                success: function () {
                    $('#successModel').modal('show');
                },
                error: function (jqXHR) {
                    $('#divErrorText').text(jqXHR.responseText);
                    $('#divError').show('fade');
                    $('#divErrorText').show('fade');
                }
            })



        });
    });

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