我正在编写我的第一个Web API 2.我正在使用自定义HttpMessageHandler
执行授权。但是,我的控制器需要知道凭证中指定的用户名。
研究此问题时,ApiController
似乎没有Controller.HttpContext
property。我发现访问HttpContext.Current
存在潜在问题。因此,虽然我实际上能够将HttpContext.Current.Items
中的用户名存储在我的HttpMessageHandler
中,然后从我的控制器访问该信息,但我不确定它是否始终可靠。
我也看到了使用RequestContext.Principal
property的建议;但是,我无法在此数据中的任何位置找到当前请求的用户名。
我的控制器如何可靠地获取当前请求的用户名?
注意:我指的是用户名,但在这种情况下,实际用户是另一个调用API的软件。 "用户名"反映正在进行通话的软件。
答案 0 :(得分:2)
@Win:嗯,那部分是我正在开发的。但目前基本 认证似乎合适,用户名识别 联系我们的软件和密码是一个特殊的密钥
以下是 BasicAuthenticationMessageHandler 的示例代码,它使用消息处理程序来支持HTTP基本身份验证。
您可以在ASP.NET Web API 2: Building a REST Service from Start to Finish的第121页阅读更多内容。
public interface IBasicSecurityService
{
bool SetPrincipal(string username, string password);
}
public class BasicSecurityService : IBasicSecurityService
{
public bool SetPrincipal(string username, string password)
{
// Get user from database
var user = GetUser(username);
IPrincipal principal = null;
if (user == null || (principal = GetPrincipal(user)) == null)
{
// System could not validate user
return false;
}
Thread.CurrentPrincipal = principal;
if (HttpContext.Current != null)
{
HttpContext.Current.User = principal;
}
return true;
}
public virtual IPrincipal GetPrincipal(User user)
{
var identity = new GenericIdentity(user.Username, Constants.SchemeTypes.Basic);
identity.AddClaim(new Claim(ClaimTypes.GivenName, user.Firstname));
identity.AddClaim(new Claim(ClaimTypes.Surname, user.Lastname));
// Get authroized roles and add them as Role Claim.
identity.AddClaim(new Claim(ClaimTypes.Role, "Manager"));
return new ClaimsPrincipal(identity);
}
}
public class BasicAuthenticationMessageHandler : DelegatingHandler
{
public const char AuthorizationHeaderSeparator = ':';
private const int UsernameIndex = 0;
private const int PasswordIndex = 1;
private const int ExpectedCredentialCount = 2;
private readonly IBasicSecurityService _basicSecurityService;
public BasicAuthenticationMessageHandler(IBasicSecurityService basicSecurityService)
{
_basicSecurityService = basicSecurityService;
}
protected override async Task<HttpResponseMessage> SendAsync(
HttpRequestMessage request,
CancellationToken cancellationToken)
{
if (HttpContext.Current.User.Identity.IsAuthenticated)
{
// Already authenticated; passing on to next handler...
return await base.SendAsync(request, cancellationToken);
}
if (!CanHandleAuthentication(request))
{
// Not a basic auth request; passing on to next handler...
return await base.SendAsync(request, cancellationToken);
}
bool isAuthenticated;
try
{
isAuthenticated = Authenticate(request);
}
catch (Exception e)
{
// Failure in auth processing
return CreateUnauthorizedResponse();
}
if (isAuthenticated)
{
var response = await base.SendAsync(request, cancellationToken);
return response;
}
return CreateUnauthorizedResponse();
}
public bool CanHandleAuthentication(HttpRequestMessage request)
{
return (request.Headers != null
&& request.Headers.Authorization != null
&& request.Headers.Authorization.Scheme.ToLowerInvariant() == Constants.SchemeTypes.Basic);
}
public bool Authenticate(HttpRequestMessage request)
{
// Attempting to authenticate...
var authHeader = request.Headers.Authorization;
if (authHeader == null)
{
return false;
}
var credentialParts = GetCredentialParts(authHeader);
if (credentialParts.Length != ExpectedCredentialCount)
{
return false;
}
return _basicSecurityService.SetPrincipal(credentialParts[UsernameIndex], credentialParts[PasswordIndex]);
}
public string[] GetCredentialParts(AuthenticationHeaderValue authHeader)
{
var encodedCredentials = authHeader.Parameter;
var credentialBytes = Convert.FromBase64String(encodedCredentials);
var credentials = Encoding.ASCII.GetString(credentialBytes);
var credentialParts = credentials.Split(AuthorizationHeaderSeparator);
return credentialParts;
}
public HttpResponseMessage CreateUnauthorizedResponse()
{
var response = new HttpResponseMessage(HttpStatusCode.Unauthorized);
response.Headers.WwwAuthenticate.Add(new AuthenticationHeaderValue(Constants.SchemeTypes.Basic));
return response;
}
}