ASP.NET MVC 5 中的基本身份验证
Posted
技术标签:
【中文标题】ASP.NET MVC 5 中的基本身份验证【英文标题】:Basic authentication in ASP.NET MVC 5 【发布时间】:2013-12-07 07:17:44 【问题描述】:在ASP.NET MVC5 中实现基本认证必须做哪些步骤?
我了解到 OWIN 不支持无 cookie 身份验证,那么基本身份验证一般可以吗?
这里需要自定义属性吗?我不确定这些属性是如何工作的。
【问题讨论】:
有时解决方案是在另一个问题上,有人已经在***上做过了,有完整的代码:***.com/questions/9043831/… Cookie 和身份验证不相关。一个可以使用另一个,但两者都不依赖于另一个。 【参考方案1】:您可以使用自定义 ActionFilter 属性来使用这种简单而有效的机制:
public class BasicAuthenticationAttribute : ActionFilterAttribute
public string BasicRealm get; set;
protected string Username get; set;
protected string Password get; set;
public BasicAuthenticationAttribute(string username, string password)
this.Username = username;
this.Password = password;
public override void OnActionExecuting(ActionExecutingContext filterContext)
var req = filterContext.HttpContext.Request;
var auth = req.Headers["Authorization"];
if (!String.IsNullOrEmpty(auth))
var cred = System.Text.ASCIIEncoding.ASCII.GetString(Convert.FromBase64String(auth.Substring(6))).Split(':');
var user = new Name = cred[0], Pass = cred[1] ;
if (user.Name == Username && user.Pass == Password) return;
filterContext.HttpContext.Response.AddHeader("WWW-Authenticate", String.Format("Basic realm=\"0\"", BasicRealm ?? "Ryadel"));
/// thanks to eismanpat for this line: http://www.ryadel.com/en/http-basic-authentication-asp-net-mvc-using-custom-actionfilter/#comment-2507605761
filterContext.Result = new HttpUnauthorizedResult();
它可用于将整个控制器置于基本身份验证之下:
[BasicAuthenticationAttribute("your-username", "your-password",
BasicRealm = "your-realm")]
public class HomeController : BaseController
...
或特定的 ActionResult:
public class HomeController : BaseController
[BasicAuthenticationAttribute("your-username", "your-password",
BasicRealm = "your-realm")]
public ActionResult Index()
...
如果您需要更多信息,请查看我在该主题上写的 this blog post。
【讨论】:
这种技术对我有用,即使对于混合身份验证,例如同一网站中的基本和表单身份验证。 请注意,此属性不适用于 Web API - 最好使用过滤器 - weblog.west-wind.com/posts/2013/Apr/18/… 太棒了。这正是我所需要的! @MacakM :所有发出质询的身份验证方案都需要领域属性(不区分大小写)。领域值(区分大小写)与被访问服务器的规范根 URL 相结合,定义了保护空间。这些领域允许将服务器上的受保护资源划分为一组保护空间,每个保护空间都有自己的身份验证方案和/或授权数据库。 [来自 RFC 1945 (HTTP/1.0) 和 RFC 2617] 将此与表单身份验证相结合会导致问题:基本身份验证的 401 重定向到表单身份验证登录页面。为避免这种情况,只需在filterContext.Result
行之前添加行:filterContext.HttpContext.Response.SuppressFormsAuthenticationRedirect = true;
。您需要 .NET 4.5 或更高版本。【参考方案2】:
您可以使用自定义属性来做到这一点。在开源项目SimpleSecurity 中有一个支持基础认证的自定义属性的实现,你可以download here。有一个参考应用程序来演示它是如何使用的。它最初是为与 MVC 4 中的 SimpleMembership 一起工作而开发的,最近是ported to use ASP.NET Identity in MVC 5。
【讨论】:
【参考方案3】:我想修改 Darkseal 分享的答案,因为该代码存在重大安全漏洞。如前所述,当调用 res.End() 时,该操作过滤器实际上并没有终止请求。提示用户输入凭据,如果凭据不匹配,则返回 401 响应,但控制器操作仍在服务器端执行。您需要将 filterContext.Result 属性设置为某个值,以使请求正确终止而不继续执行操作方法。
这对我的情况尤其不利,因为我试图保护从第三方接收数据馈送的 Web 服务端点。正如所写,这个动作过滤器没有保护任何东西,因为数据仍在通过我的动作方法推送。
我的“快速修复”如下:
public class BasicAuthenticationAttribute : ActionFilterAttribute
public string BasicRealm get; set;
protected string Username get; set;
protected string Password get; set;
public BasicAuthenticationAttribute(string username, string password)
this.Username = username;
this.Password = password;
public override void OnActionExecuting(ActionExecutingContext filterContext)
var req = filterContext.HttpContext.Request;
var auth = req.Headers["Authorization"];
if (!String.IsNullOrEmpty(auth))
var cred = System.Text.ASCIIEncoding.ASCII.GetString(Convert.FromBase64String(auth.Substring(6))).Split(':');
var user = new Name = cred[0], Pass = cred[1] ;
if (user.Name == Username && user.Pass == Password) return;
var res = filterContext.HttpContext.Response;
res.AddHeader("WWW-Authenticate", String.Format("Basic realm=\"0\"", BasicRealm ?? "Ryadel"));
filterContext.Result = new HttpUnauthorizedResult();
【讨论】:
@Darkseal 已经在主要答案中应用了“快速修复”,res.end()
的问题已被删除,替换为HttpUnauthorizedResult()
似乎添加 filterContext.Result = new HttpUnauthorizedResult();
会导致 asp 将用户重定向到默认登录页面,而不是让身份验证弹出窗口出现。【参考方案4】:
HTTP 基本身份验证不需要 cookie。它基于 HTTP 请求中的 HEADER。标头名为Authorization,其值应该是用户名和密码组合成一个字符串“username:password”(全部采用base64编码)。
真诚地,我从未对 ASP.NET MVC 使用基本身份验证,但我使用 Web API 创建自定义属性(对于 WebAPI,您可以从 here 开始,对于 MVC,您可以从 here 开始)。
【讨论】:
但是对于 Mvc 应用程序,您需要存储在 Cookie 中。例如,每个请求都不会自动附加标头。客户端浏览器需要添加授权标头,但不会。 WebApi 不同,我们可以控制 HttpClient。 @harsimranb 自 90 年代中期以来,没有一个主流浏览器不继续添加授权标头。您可能在服务器端有错误。 @harsimranb WebApi 没有什么不同;客户端浏览器总是添加授权头,存储在cookie中与MVC无关,是一个选择【参考方案5】:来自@Darkseal 的精彩回答。这是重新用于 ASP.NET Web API 的相同代码(MVC 的近亲)。相同的想法,命名空间和上下文类略有不同。以完全相同的方式将其添加到您的类和方法中。
using System.Web.Http.Controllers;
using System.Web.Http.Filters;
public class BasicAuthenticationAttribute : ActionFilterAttribute
public string BasicRealm get; set;
protected string Username get; set;
protected string Password get; set;
public BasicAuthenticationAttribute(string username, string password)
Username = username;
Password = password;
public override void OnActionExecuting(HttpActionContext filterContext)
var req = filterContext.Request;
var auth = req.Headers.Authorization;
if (auth?.Scheme == "Basic")
var cred = Encoding.ASCII.GetString(Convert.FromBase64String(auth.Parameter)).Split(':');
var user = new Name = cred[0], Pass = cred[1] ;
if (user.Name == Username && user.Pass == Password) return;
filterContext.Response = new HttpResponseMessage(HttpStatusCode.Unauthorized);
filterContext.Response.Headers.Add("WWW-Authenticate", string.Format("Basic realm=\"0\"", BasicRealm ?? "YourRealmName"));
【讨论】:
在***.com/questions/23336204/…查看类似的答案【参考方案6】:你可以在Nuget (AuthPackage) 上试用这个包 它使您能够轻松地将身份验证添加到您的 asp.net mvc。
使用包管理器控制台安装包:
Install-Package AuthPackage
在 (appSettings) 中将连接字符串添加到您的 Web.config:
<add key="connectionString" value="connectionStringHere" />
您已准备好注册用户、登录、注销
示例:
public async Task<ActionResult> SignIn()
var context = System.Web.HttpContext.Current;
AuthUser authUser = new AuthUser(context);
await authUser.SignIn("waleedchayeb2@gmail.com", "123456");
return RedirectToAction("Index", "Home");
您可以阅读文档here
【讨论】:
你应该提到你是包的作者【参考方案7】:由于 Web.config 中的以下代码,我们的一个应用程序“意外”使用了基本身份验证:
<system.webServer>
<modules>
<remove name="FormsAuthentication" />
</modules>
... other stuff
</system.webServer>
应用程序被配置为使用表单身份验证。 只要使用普通表单身份验证,就会弹出浏览器身份验证窗口。
【讨论】:
【参考方案8】:Darkseal’s answer
[BasicAuthenticationAttribute("your-username", "your-password",
BasicRealm = "your-realm")]
有两个缺点: 名称和密码是硬编码的,它们只支持单个用户。
更灵活的解决方案应该支持存储在配置中的多个用户名/密码对。
Microsoft 描述了一个示例 https://gm/aspnet/samples/tree/main/samples/aspnet/WebApi/BasicAuthentication。
public abstract class BasicAuthenticationAttribute : Attribute, IAuthenticationFilter
在重载中
abstract Task<IPrincipal> AuthenticateAsync(string userName, string password,
CancellationToken cancellationToken);
您可以执行检查以查找标头中的用户名/密码是否存在于用户名/密码对的配置/秘密列表中
还可以创建执行基本身份验证的 HTTP 模块。您可以通过替换 CheckPassword 方法轻松插入 ASP.NET 成员资格提供程序。 https://docs.microsoft.com/en-us/aspnet/web-api/overview/security/basic-authentication#basic-authentication-with-custom-membership
OWIN 实现示例https://github.com/scottbrady91/Blog-Example-Classes/tree/master/OwinBasicAuthentication/WebApi
.Net 核心中的可能实现在 https://github.com/mihirdilip/aspnetcore-authentication-basic
【讨论】:
以上是关于ASP.NET MVC 5 中的基本身份验证的主要内容,如果未能解决你的问题,请参考以下文章
使用 ASP.NET 5 MVC 6 Web API 进行 Cookie 身份验证
将特定域的 ASP.NET 模拟用户添加到 windows 身份验证
IIS 上 asp.net mvc Intranet Web 应用程序的基本身份验证与 Windows 身份验证
表单身份验证、ASP.NET MVC 和 WCF RESTful 服务