在Asp.net Web API中对用户进行身份验证



我正在编写API,它将被移动设备使用,我想确保这个API端点的安全。

用户身份验证详细信息由另一个名为User Manger API的应用程序(另一个包含用户详细信息的项目)提供。

在从用户管理器API获取用户数据的同时,如何使用ASP.NET Identity framework Authorization和其他功能来保护我的API端点?

这个问题有点宽泛;基本上,你正在寻找一种策略,使用不同的现有api(api在你的控制范围内吗,如果需要,你能修改它吗?)

如果您可以同时修改这两个,id说可以通过StackOverflow和Google查找JWT令牌、OAuth和身份服务器。

1-您可以实现一个属性并装饰您的api控制器。

2-你可以在asp.net的app_start中实现并注册一个全局过滤器(并确保你在global.asax中注册过滤器)

3-您可以执行#Roel-Abspoel提到的在用户管理器API中实现Identity Server的操作,并让您的客户端与之交谈并获取令牌,然后您的API与之交谈以验证令牌。

还有其他方法,但我会保持简短和甜蜜。

下面是一个使用属性的示例:

using System;
using System.Net;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Security.Claims;
using System.Security.Principal;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Web.Http;
using System.Web.Http.Filters;
namespace myExample
{
public class ExternalAuthenticationAttribute : IAuthenticationFilter
{
public virtual bool AllowMultiple
{
get { return false; }
}
public Task AuthenticateAsync(HttpAuthenticationContext context, CancellationToken cancellationToken)
{
// get request + authorization headers
HttpRequestMessage request = context.Request;
AuthenticationHeaderValue authorization = request.Headers.Authorization;
// check for username and password (regardless if it was validated on the client, server should check)
// this will only accept Basic Authorization
if (String.IsNullOrEmpty(authorization.Parameter) || authorization.Scheme != "Basic")
{
// Authentication was attempted but failed. Set ErrorResult to indicate an error.
context.ErrorResult = new AuthenticationFailureResult("Missing credentials", request);
return null;
}
var userNameAndPasword = GetCredentials(authorization.Parameter);
if (userNameAndPasword == null)
{
// Authentication was attempted but failed. Set ErrorResult to indicate an error.
context.ErrorResult = new AuthenticationFailureResult("Could not get credentials", request);
return null;
}
// now that we have the username + password call User manager API
var client = new HttpClient();
// POST USERNAME + PASSWORD INSIDE BODY, not header, not query string. ALSO USE HTTPS to make sure it is sent encrypted
var response = AuthenticateAgainstUserMapagerApi1(userNameAndPasword, client);
// THIS WILL WORK IN .NET CORE 1.1. ALSO USE HTTPS to make sure it is sent encrypted
//var response = AuthenticateAgainstUserMapagerApi2(client, userNameAndPasword);
// parse response
if (!response.IsSuccessStatusCode)
{
context.ErrorResult = new AuthenticationFailureResult("Invalid username or password", request);
}
else
{
var readTask = response.Content.ReadAsStringAsync();
var content = readTask.Result;
context.Principal = GetPrincipal(content); // if User manager API returns a user principal as JSON we would 
}
return null;
}
//private static HttpResponseMessage AuthenticateAgainstUserMapagerApi2(HttpClient client, Tuple<string, string> userNameAndPasword)
//{
//    client.SetBasicAuthentication(userNameAndPasword.Item1, userNameAndPasword.Item2);
//    var responseTask = client.GetAsync("https://your_user_manager_api_URL/api/authenticate");
//    return responseTask.Result;
//}
private static HttpResponseMessage AuthenticateAgainstUserMapagerApi1(Tuple<string, string> userNameAndPasword, HttpClient client)
{
var credentials = new
{
Username = userNameAndPasword.Item1,
Password = userNameAndPasword.Item2
};
var responseTask = client.PostAsJsonAsync("https://your_user_manager_api_URL/api/authenticate", credentials);
var response = responseTask.Result;
return response;
}
public IPrincipal GetPrincipal(string principalStr)
{
// deserialize principalStr and return a proper Principal instead of ClaimsPrincipal below
return new ClaimsPrincipal();
}
private static Tuple<string, string> GetCredentials(string authorizationParameter)
{
byte[] credentialBytes;
try
{
credentialBytes = Convert.FromBase64String(authorizationParameter);
}
catch (FormatException)
{
return null;
}
try
{
// make sure you use the proper encoding which match client
var encoding = Encoding.ASCII;
string decodedCredentials;
decodedCredentials = encoding.GetString(credentialBytes);
int colonIndex = decodedCredentials.IndexOf(':');
string userName = decodedCredentials.Substring(0, colonIndex);
string password = decodedCredentials.Substring(colonIndex + 1);
return new Tuple<string, string>(userName, password);
}
catch (Exception ex)
{
return null;
}
}
public Task ChallengeAsync(HttpAuthenticationChallengeContext context, CancellationToken cancellationToken)
{
throw new NotImplementedException();
}
}
public class AuthenticationFailureResult : IHttpActionResult
{
public AuthenticationFailureResult(string reasonPhrase, HttpRequestMessage request)
{
ReasonPhrase = reasonPhrase;
Request = request;
}
public string ReasonPhrase { get; private set; }
public HttpRequestMessage Request { get; private set; }
public Task<HttpResponseMessage> ExecuteAsync(CancellationToken cancellationToken)
{
return Task.FromResult(Execute());
}
private HttpResponseMessage Execute()
{
HttpResponseMessage response = new HttpResponseMessage(HttpStatusCode.Unauthorized);
response.RequestMessage = Request;
response.ReasonPhrase = ReasonPhrase;
return response;
}
}
}

像这样使用API类的属性,每次访问PurchaseController时,它都会调用用户管理器API:

[ExternalAuthenticationAttribute]
public class PurchaseController : ApiController

相关内容

  • 没有找到相关文章

最新更新