我花了很长时间才找到这方面的东西,尽管我认为它非常简单......
我正在使用 .NET MVC 4.5 开发 API。我希望最终用户能够发送类似(PowerShell)的请求:
$webclient = new-object System.Net.WebClient
$webclient.Credentials = new-object System.Net.NetworkCredential($username,
$securePassword)
$doc = $webclient.DownloadString("http://localhost:60023/api/getData?id=200")
但我不知道如何从我的应用程序中的请求中提取凭据。
我的控制器看起来像:
namespace App.Controllers
{
public IEnumerable<MyStruct> Get(int id)
{
// TODO: get credentials from request
// validate credentials
// code to create IEnumerable<MyStruct>
return DataList;
}
}
到目前为止,如果我对凭据进行硬编码,一切都会正常,我需要弄清楚的是如何从最终用户的
$webclient.Credentials
获取凭据。
我确定以前已经讨论过这个问题,但我已经搜索了几个小时但找不到答案。
我还差吗?
这不是验证 API 请求的好方法吗?我知道有一个 [Authorize] 属性可以使用内置身份验证系统,但我的应用程序使用自定义登录验证,所以我认为这不起作用。是否有理由以我想要的方式在控制器方法中验证凭据是一个坏主意?
通常
MVC
不用于 API 工作。虽然 MVC
可以处理服务 API 调用,但 Microsoft 有一个类似 MVC
的产品,称为 WebApi
,它更适合为 API 提供服务,例如返回 JSON 或 XML 而不是视图。
在
MVC
和WebApi
中,不建议在方法内处理身份验证和授权。虽然它有效,但它会让您忘记保护 API 调用的安全。 因此微软制作了 AuthenticationFilter
和 AuthorizationFilter
属性。这些允许您通过方法、类或应用程序来标记要保护哪些 API 或视图。
要从
MVC
中的请求访问基本凭据,您将访问授权标头。这将是一个 Basic [Base64Encoded, colon delimited strings]
形式的字符串。
以下代码显示了如何读取凭据的粗略示例:
public ActionResult TestView()
{
bool isAuthenticated;
var base64Header = Request.Headers["Authorization"];
//The header is a string in the form of "Basic [base64 encoded username:password]"
if (base64Header != null)
{
var authHeader = AuthenticationHeaderValue.Parse(base64Header);
if (authHeader != null
&& authHeader.Scheme.Equals("basic", StringComparison.OrdinalIgnoreCase)
&& authHeader.Parameter != null)
{
//Decode the username:password pair
var credentialPair = Encoding.ASCII.GetString(Convert.FromBase64string(authHeader.Parameter));
//Split into pieces
var credentials = credentialPair.Split(new [] {":"}, StringSplitOptions.None);
var userName = credentials[0];
var plainTextPassword = credentials[1];
isAuthenticated = SomeAuthenticator.Authenticate(userName, password);
}
}
if (isAuthenticated)
return Foo();
else
RedirectResult("your login view");
}
但是最好将此代码插入到
AuthenticationFilter
中。这使您能够通过方法、类或应用程序打开/关闭授权。
public class CustomAuthFilter : IAuthenticationFilter
{
public void OnAuthentication(AuthenticationContext filterContext)
{
var header = filterContext.RequestContext.HttpContext.Request.Headers["Authorization"];
if (!Authenticate(header))
filterContext.Result = new HttpUnauthorizedResult();
}
public void OnAuthenticationChallenge(AuthenticationChallengeContext filterContext)
{
filterContext.Result = new RedirectResult(@"https:\\foo\YourLoginPage");
}
private bool Authenticate(string rawAuthorizationHeader)
{
try
{
if (rawAuthorizationHeader != null)
{
var authHeader = AuthenticationHeaderValue.Parse(rawAuthorizationHeader);
if (authHeader != null
&& authHeader.Scheme.Equals("basic", StringComparison.OrdinalIgnoreCase)
&& authHeader.Parameter != null)
{
var credentialPair = Encoding.ASCII.GetString(Convert.FromBase64String(authHeader.Parameter));
var credentials = credentialPair.Split(new[] { ":" }, StringSplitOptions.None);
var userName = credentials[0];
var plainTextPassword = credentials[1];
return SomeAuthenticator.Authenticate(userName, plainTextPassword);
}
}
return false;
}
catch (Exception)
{
return false;
}
}
}
然后被
消耗[CustomAuthFilter] //Secure all methods in the class
public class SecureApiController
{
public ActionResult SecuredApiCall()
{
return Foo();
}
public ActionResult AnotherSecuredCall()
{
return Bar();
}
[AllowAnonymous]
public ActionResult UnsecuredApiCall()
{
return UnsecureFoo();
}
}
请注意,在典型的 Microsoft 方式中,身份验证和授权是两个不同的东西。如果您想通过“此用户有一个帐户”以外的方式来保护 API,您将需要设置授权过滤器。