我有一个使用基本身份验证的ASP MVC3 restful服务。搜索堆栈溢出后,我创建了以下代码。
public class BasicAuthentication : ActionFilterAttribute
{
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
var req = filterContext.HttpContext.Request;
if (String.IsNullOrEmpty(req.Headers["Authorization"]))
{
filterContext.Result = new HttpNotFoundResult();
}
else
{
var credentials = System.Text.ASCIIEncoding.ASCII
.GetString(Convert.FromBase64String(req.Headers["Authorization"].Substring(6)))
.Split(':');
var user = new { Name = credentials[0], Password = credentials[1] };
if(!(user.Name == "username" && user.Password == "passwords"))
{
filterContext.Result = new HttpNotFoundResult();
}
}
}
}
1)ActionFilterAttribute是最好的方法吗?
2)设置filterContext.Result是否正确拒绝访问控制器方法?
3)我有什么问题吗?
感谢。
-Nick
答案 0 :(得分:12)
1) ActionFilterAttribute
这是最好的方法吗?
我认同。此方法反映了内置Authorize
属性的实现。
2)是否设置filterContext.Result
拒绝访问控制器方法的正确方法?
是。多数民众赞成在那里。 (1)
3)我有什么问题吗?
HttpUnauthorizedResult()
发送http
通过HttpNotFoundResult()
发送401错误而不是http 404错误。下面是我的代码实现(我肯定也有问题)。
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
try
{
if (String.IsNullOrEmpty(filterContext.HttpContext.Request.Headers["Authorization"]))
{
filterContext.Result = new HttpUnauthorizedResult();
}
else
{
if (filterContext.HttpContext.Request.Headers["Authorization"].StartsWith("Basic ", StringComparison.InvariantCultureIgnoreCase))
{
string[] credentials = ASCIIEncoding.ASCII.GetString(Convert.FromBase64String(filterContext.HttpContext.Request.Headers["Authorization"].Substring(6))).Split(':');
if (credentials.Length == 2)
{
if (String.IsNullOrEmpty(credentials[0]))
{
filterContext.Result = new HttpUnauthorizedResult();
}
else if (!(credentials[0] == "username" && credentials[1] == "passwords"))
{
filterContext.Result = new HttpUnauthorizedResult();
}
}
else
{
filterContext.Result = new HttpUnauthorizedResult();
}
}
else
{
filterContext.Result = new HttpUnauthorizedResult();
}
}
base.OnActionExecuting(filterContext);
}
catch
{
filterContext.Result = new HttpUnauthorizedResult();
}
}
备注强>
<强>参考强>
答案 1 :(得分:8)
Adrian的重构版本
public class BasicAuthenticationAttribute : ActionFilterAttribute
{
private static readonly string AuthorizationHeader = "Authorization";
private static readonly string BasicHeader = "Basic ";
private static readonly string Username = "username";
private static readonly string Password = "password";
private static readonly char[] Separator = ":".ToCharArray();
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
try
{
if (!Authenticated(filterContext.HttpContext.Request))
filterContext.Result = new HttpUnauthorizedResult();
base.OnActionExecuting(filterContext);
}
catch
{
filterContext.Result = new HttpUnauthorizedResult();
}
}
private bool Authenticated(HttpRequestBase httpRequestBase)
{
bool authenticated = false;
if (String.IsNullOrEmpty(httpRequestBase.Headers[AuthorizationHeader]) == false &&
httpRequestBase.Headers[AuthorizationHeader].StartsWith(BasicHeader, StringComparison.InvariantCultureIgnoreCase))
{
string[] credentials = Encoding.ASCII.GetString(Convert.FromBase64String(
httpRequestBase.Headers[AuthorizationHeader].Substring(BasicHeader.Length))).Split(Separator);
if (credentials.Length == 2 && credentials[0] == Username && credentials[1] == Password)
{
authenticated = true;
}
}
return authenticated;
}
}
答案 2 :(得分:-1)
以下是一种基本身份验证的官方示例:
http://www.asp.net/web-api/overview/security/authentication-filters
另一篇文章,现在使用OWIN:
答案 3 :(得分:-2)
1)不,ActionFilter属性不是验证用户身份的好方法。 (因为我们需要进行一次身份验证并设置身份验证cookie,因此HttpContext.User将保持身份验证,直到Cookie过期)
2)是的,设置filtercontext.Result是阻止访问的理想方法。 (但不是分配HttpNotFoundResult,而是使用RedirectResult重定向到登录页面)
3)我真的不明白为什么有这样的授权实现。 最好的方法是有一个接收表单发布数据(用户名和密码)的操作。并使用Authorize属性来防止取消授权访问。
以下是VS2010中默认MVC3示例应用程序的代码。
[HttpPost]
public ActionResult LogOn(LogOnModel model, string returnUrl)
{
if (ModelState.IsValid)
{
if (Membership.ValidateUser(model.UserName, model.Password))
{
FormsAuthentication.SetAuthCookie(model.UserName, model.RememberMe);
if (Url.IsLocalUrl(returnUrl) && returnUrl.Length > 1 && returnUrl.StartsWith("/")
&& !returnUrl.StartsWith("//") && !returnUrl.StartsWith("/\\"))
{
return Redirect(returnUrl);
}
else
{
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);
}