博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
ASP.NET MVC 4 (十三) 基于表单的身份验证
阅读量:4639 次
发布时间:2019-06-09

本文共 9205 字,大约阅读时间需要 30 分钟。

在前面的章节中我们知道可以在MVC应用程序中使用[Authorize]特性来限制用户对某些网址(控制器/控制器方法)的访问,但这都是在对用户认证之后,而用户的认证则依然是使用ASP.NET平台的认证机制。

ASP.NET提供Windows和Forms两种身份验证,前者主要用于Intranet上域环境内,后者则更多的应用于Internet,这里我们只讨论后者。先从最简单的例子开始,我们在web.config中配置Forms认证方式:

... 
  
    
      
    
  
...

这里设置认证方式为Forms,用户登录的地址为~/Account/Login,我们用最简单的方式创建用户信息,在credentials节中直接设置用户名称/密码。在创建页面之前我们先创建收集用户名和密码Model类:

using System.ComponentModel.DataAnnotations;namespace SportsStore.WebUI.Models {    public class LoginViewModel {        [Required]        public string UserName { get; set; }        [Required]        [DataType(DataType.Password)]        public string Password { get; set; }    }}

创建一个视图来收集用户名和信息:

@model SportsStore.WebUI.Models.LoginViewModel@{    ViewBag.Title = "Admin: Log In";    Layout = "~/Views/Shared/_AdminLayout.cshtml";}

Log In

Please log in to access the administrative area:

@using(Html.BeginForm()) { @Html.ValidationSummary(true) @Html.EditorForModel()

}

最后还需要在Account控制器的Login action中处理用户提交的用户名和密码完成用户认证:

[HttpPost]        public ActionResult Login(LoginViewModel model)        {            if (ModelState.IsValid)            {                bool result = FormsAuthentication.Authenticate(model.UserName, model.Password);                if (result)                {                    FormsAuthentication.SetAuthCookie(model.UserName, false);                    return Redirect(Url.Action("Index", "Admin"));                }                else                {                    ModelState.AddModelError("", "Incorrect username or password");                    return View();                }            }            else            {                return View();            }        }

调用FormsAuthentication.Authenticate()对用户名和密码验证,如何验证成功,调用FormsAuthentication.SetAuthCookie()设置用户验证的cookie并在响应中返回,在cookie过期之前用户再次访问时不再要求登录。

以上就是最简单的Forms身份验证过程,但实际的Internet应用用户的信息一般存储在数据库中,通过Membership provider利用数据库中的信息对用户验证,MVC4中微软为我们提供SQL membership provider、Universal membership provider和Simple membership provider,下面来看看如何具体如何使用它们。

SQL membership provider

在.NET 2.0中SQL membership provider就已经存在了,在visual studio 2012中使用empty模板创建一个MVC4的工程,web.config你不会看到任何membership provider相关的信息,默认使用的是Windows认证。在VS的Project菜单下打开Asp.net configurtion工具(在打开配置工具前记得编译下工程,否则会提示“选定的数据存储区出现问题”),在“安全”标签页面点击“选择身份验证类型”,配置工具询问“用户如何访问您的站点?”,选择“通过Internet”,点击“完成”后配置工具将自动在web.config中添加“<authentication mode="Forms" />”。配置工具仍然没有在web.config添加任何membership provider的信息,但是我们转到配置工具的“提供程序页面”,可以看到看到默认选中的是AspNetSqlMembershipProvider,同时配置工具会在工程的app_data目录下创建一个名为ASPNETDB.MDF的数据库,这是一个sql express的数据库,visual studio 2012中不能直接打开(VS用的是localdb),可以在SQL管理工具中附加到SQL EXPRESS的服务实例来查看。打开数据库可以看到数据库中添加了很多“aspnet_”为前缀的表和存储过程,这些都是SqlMembershipProvider需要的。

如果我们要使用自建的数据库来保存用户信息改如何操作呢?我们在Solution exploer中点击App_Start目录,右键菜单中选择添加->添加项目->SQL数据库创建一个localdb的数据库,添加相应的Connection字符串到web.config:

我们还需要在web.config手工添加SqlMembershipProvider,让它使用上面的数据库连接:

再次打开asp.net配置工具转到安全界面会提示错误“Could not find stored procedure 'dbo.aspnet_CheckSchemaVersion'”,配置工具试图调用相关的存储过程,但是数据库是我们手工创建的,不包含这些过程和数据表。我们可以使用aspnet_regsql.exe工具在我们的数据库中创建相关表和数据,C:\Windows\Microsoft.NET\Framework64\v4.0.30319和C:\Windows\Microsoft.NET\Framework64\v2.0.50727都有这个工具,没有细究两个版本的不同,这里使用.NET 4.0的版本。在aspnet_regsql工具选择服务器为“(localdb)\v11.0”,数据库列表中如果找不到新建的数据库,可以事先在sql manage studio中连接到服务引擎“(localdb)\v11.0”后附加该数据库(aspnet_reqsql也支持使用连接字符串作为参数,参见http://msdn.microsoft.com/en-us/library/ms229862(v=vs.100).aspx)。完成上述操作后,asp.net配置工具就可以在我们的数据库中创建管理用户了。

准备好Forms认证的配置,我们继续完善上面的例子,从控制器开始:

using System;using System.Web.Mvc;using System.Web.Security;using SportsStore.WebUI.Models;namespace SportsStore.WebUI.Controllers{    public class AccountController : Controller    {        public ViewResult Login(string returnUrl = null)        {            ViewBag.ReturnUrl = returnUrl;            return View();        }        [HttpPost]        public ActionResult Login(LoginViewModel model, string returnUrl)        {            if (!ModelState.IsValid) return View();            var result = Membership.ValidateUser(model.UserName, model.Password);            if (result)            {                FormsAuthentication.SetAuthCookie(model.UserName, false);                return Redirect(returnUrl ?? Url.Action("Index", "Home"));            }            ModelState.AddModelError("", "Incorrect username or password");            return View();        }        public ActionResult Logout(string returnUrl)        {            FormsAuthentication.SignOut();            return Redirect(returnUrl ?? Url.Action("Index", "Home"));        }                public ViewResult Register()        {            return View();        }        [HttpPost]        public ViewResult Register(LoginViewModel model)        {            if (!ModelState.IsValid) return View(model);            try            {                Membership.CreateUser(model.UserName, model.Password);                ViewBag.Registered = true;            }            catch (Exception exception)            {                ModelState.AddModelError("",exception.Message);            }            return View(model);        }    }}

在用户登录时不再使用FormsAuthentication.Authenticate()认证用户,它仅读取web.config中credentials节的内容,我们需要改用Membership.ValidateUser()对用户密码校验。调用FormsAuthentication.SignOut()登出用户,它清除认证相关的cookie。Register() action用于创建用户,它调用Membership.CreateUser()创建一个用户保存到数据库中,对应的Register视图:

@model SportsStore.WebUI.Models.LoginViewModel@{    ViewBag.Title = "User: Register";    Layout = "~/Views/Shared/_AdminLayout.cshtml";}

User register

@if (ViewBag.Registered != null && ViewBag.Registered){

User "@Model.UserName" has been created sucessfully!

}else{

Please input user name and password to register:

using (Html.BeginForm()) { @Html.ValidationSummary(true) @Html.EditorForModel()

}}

作为示例这里简单的收集用户名和密码,成功注册后给出提示,Html.ValidationSummary()显示发生的错误发生,比如用户名已经存在。我们可以在布局文件中创建一些链接关联到用户注册、登出:

...
@if (User.Identity.IsAuthenticated) {

Current user:@User.Identity.Name

@Html.RouteLink("Logout",new {Controller="Account",Action="Logout",returnUrl=Request.Url.PathAndQuery}) } else {
@Html.RouteLink("Login",new {Controller="Account",Action="Login",returnUrl=Request.Url.PathAndQuery})
@Html.ActionLink("Register","Register","Account") }
@if (User.IsInRole("Admin")) { @Html.ActionLink("Administrate", "Index", "Admin") }
...

 

Universal provider

SQL membership provider要求使用完整安装的SQL server,使用到很多表和存储过程,对SQL server azure、SQL server compact都不支持,于是Universal provider出现了,最早于 2011年发布。我们可以在VS2012中使用Basic模板创建MVC4工程,工程被配置为默认使用Universal provider。我们也可以在nuget包管理器搜索“universal”,找到“Microsoft ASP.NET universal provider”安装,安装工具修改web.config配置DefaultMembershipProvider作为默认的provider;配置EntityFramework,universal provider使用EntityFramework完成数据库的读写;创建一个SQL express的数据库和连接字符串供universal provider使用。下面是web.config的部分内容:

...
...
....
...

打开asp.net配置工具,可以看到成员资格提供程序有AspNetSqlMembershipProvider和DefaultMembershipProvider供选择,前者就是sql membership provider,我们我们这时选择它,配置工具会把membership改为:

defaultProvider特性被删除,不带任何的特性,这需要特别注意。

查看Universal provider生成的数据库,它只包含Users、Roles、Profiles、Memberships、UsersInRoles、Applications几个表,而且没有任何的存储过程,确实很多程度上简化了数据库模型,不再使用存储过程操作数据,因此支持的SQL服务类型也更多。nuget包安装工具为我们自动创建了一个数据库,如果我们要使用原有的数据库该怎么办呢?我们只需要改动相应的连接字符串,编译后启动asp.net配置工具,它会在我们原有的数据库中创建上面的几个表。

SQL membership provider一节示例的的控制器/视图我们不需要任何改动都可以在切换成universal provider后正常运行,对Membership方法的调用在MVC内部转由System.Web.Providers.DefaultProfileProvider,对我们写程序讲没有任何不同。这样讲似乎universal provider没有带来太多的好处,实际上随着数据库结构的简化,对我们扩展profile等有很大的便利,这里就不再深入讨论。

Simple provider

simple provider在VS 2010 SP1中随Webmatrix发布,和universal provider一样使用entrity framework操作用户信息数据库,但是数据库的结构更为简单也可以更为灵活的配置。在VS2012中我们使用Internet模板创建MVC4的工程,工程被配置为使用simple provider。web.config中只有<authentication mode="Forms">,不再包含membership provider的信息,membership的处理直接在控制器中使用WebMatrix.WebData.WebSecurity处理。Internet模板创建了具备完整用户功能的代码,这里不一一列出。

Internet模板创建一个名为InitializeSimpleMembershipAttribute的过滤器,它在每次应用程序启动时调用一次:

WebSecurity.InitializeDatabaseConnection("DefaultConnection", "UserProfile", "UserId", "UserName", autoCreateTables: true);

这个方法使初始化用户信息的数据库连接,DefaultConnection为数据库的连接字符串,Userpofile为表名称,UserId和UserName分别为用户ID和用户名称在表中的字段名称,也就是说我们只需要一个最简单的有用户ID和名称两个字段的表就可以了,这个表可以在任何数据库中,这是可以动态设置的,所以asp.net的配置工具不能用于配置simple provider。

Internet模板创建Account控制器,包含众多action方法用于提供用户注册、登录、登出、修改密码,基本上都是调用WebSecurity的相关方法来实现的,比如登录调用的是WebSecurity.Login()。在Internet模板的基础上,我们可以很方便的自定义profile、roles等,这里也不再深入,已经有一篇很好的文章讲解simple provider如何工作,可以参见。

 

MVC5已随VS2013在2013十月发布,相对于MVC4有了很多的变化,包括这里所讲的安全认证。就以本文结束MVC4,开始MVC5之旅。

转载于:https://www.cnblogs.com/GoogleGetZ/p/5835823.html

你可能感兴趣的文章
小试牛刀【龙哥翻译】
查看>>
利用python重启路由器
查看>>
oracle 闪回操作(flashback)
查看>>
简单的jsonp实现跨域原理
查看>>
setvlet基础知识
查看>>
Css动画形式弹出遮罩层,内容区上下左右居中于不定宽高的容器中
查看>>
延迟加载、分页显示等功能的增加
查看>>
在Objective-C中浅谈面向对象
查看>>
解决vs2013不能添加控制器的步骤
查看>>
JAVA基础-数组
查看>>
【区间DP】能量项链
查看>>
trove 开发者阅读翻译
查看>>
WinForm 弹框确认后执行
查看>>
CRM Home Grid StyleSet
查看>>
遍历checktree 选中的节点,就是前面打勾的
查看>>
基于TCP/IP的长连接和短连接
查看>>
SharePoint Framework解决方案管理参考(二)
查看>>
使用PowerShell在Windows 10中创建本地用户帐户
查看>>
让服务器可以下载apk和ipa文件
查看>>
[转发]如何在ASP.NET的web.config配置文件中添加MIME类型
查看>>