ASP.NET MVC 4 (十三) 基于表单的身份验证
2020-12-13 02:17
标签:style blog class code java tar 在前面的章节中我们知道可以在MVC应用程序中使用[Authorize]特性来限制用户对某些网址(控制器/控制器方法)的访问,但这都是在对用户认证之后,而用户的认证则依然是使用ASP.NET平台的认证机制。 ASP.NET提供Windows和Forms两种身份验证,前者主要用于Intranet上域环境内,后者则更多的应用于Internet,这里我们只讨论后者。先从最简单的例子开始,我们在web.config中配置Forms认证方式: 这里设置认证方式为Forms,用户登录的地址为~/Account/Login,我们用最简单的方式创建用户信息,在credentials节中直接设置用户名称/密码。在创建页面之前我们先创建收集用户名和密码Model类: 创建一个视图来收集用户名和信息: 最后还需要在Account控制器的Login action中处理用户提交的用户名和密码完成用户认证: 调用FormsAuthentication.Authenticate()对用户名和密码验证,如何验证成功,调用FormsAuthentication.SetAuthCookie()设置用户验证的cookie并在响应中返回,在cookie过期之前用户再次访问时不再要求登录。 以上就是最简单的Forms身份验证过程,但实际的Internet应用用户的信息一般存储在数据库中,通过Membership
provider利用数据库中的信息对用户验证,MVC4中微软为我们提供SQL membership provider、Universal membership
provider和Simple 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中添加“”。配置工具仍然没有在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认证的配置,我们继续完善上面的例子,从控制器开始: 在用户登录时不再使用FormsAuthentication.Authenticate()认证用户,它仅读取web.config中credentials节的内容,我们需要改用Membership.ValidateUser()对用户密码校验。调用FormsAuthentication.SignOut()登出用户,它清除认证相关的cookie。Register()
action用于创建用户,它调用Membership.CreateUser()创建一个用户保存到数据库中,对应的Register视图: 作为示例这里简单的收集用户名和密码,成功注册后给出提示,Html.ValidationSummary()显示发生的错误发生,比如用户名已经存在。我们可以在布局文件中创建一些链接关联到用户注册、登出: 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在VS 2010 SP1中随Webmatrix发布,和universal provider一样使用entrity
framework操作用户信息数据库,但是数据库的结构更为简单也可以更为灵活的配置。在VS2012中我们使用Internet模板创建MVC4的工程,工程被配置为使用simple
provider。web.config中只有,不再包含membership
provider的信息,membership的处理直接在控制器中使用WebMatrix.WebData.WebSecurity处理。Internet模板创建了具备完整用户功能的代码,这里不一一列出。 Internet模板创建一个名为InitializeSimpleMembershipAttribute的过滤器,它在每次应用程序启动时调用一次: 这个方法使初始化用户信息的数据库连接,DefaultConnection为数据库的连接字符串,Userpofile为表名称,UserId和UserName分别为用户ID和用户名称在表中的字段名称,也就是说我们只需要一个最简单的有用户ID和名称两个字段的表就可以了,这个表可以在任何数据库中,这是可以动态设置的,所以asp.net的配置工具不能用于配置simple
provider。 Internet模板创建Account控制器,包含众多action方法用于提供用户注册、登录、登出、修改密码,基本上都是调用WebSecurity的相关方法来实现的,比如登录调用的是WebSecurity.Login()。在Internet模板的基础上,我们可以很方便的自定义profile、roles等,这里也不再深入,已经有一篇很好的文章讲解simple
provider如何工作,可以参见http://weblogs.asp.net/jgalloway/archive/2012/08/29/simplemembership-membership-providers-universal-providers-and-the-new-asp-net-4-5-web-forms-and-asp-net-mvc-4-templates.aspx。 MVC5已随VS2013在2013十月发布,相对于MVC4有了很多的变化,包括这里所讲的安全认证。就以本文结束MVC4,开始MVC5之旅。 ASP.NET MVC 4 (十三) 基于表单的身份验证,搜素材,soscw.com ASP.NET MVC 4 (十三) 基于表单的身份验证 标签:style blog class code java tar 原文地址:http://www.cnblogs.com/duanshuiliu/p/3715703.html...
authentication mode="Forms">
forms loginUrl="~/Account/Login" timeout="2880">
credentials passwordFormat="Clear">
user name="admin" password="secret" />
credentials>
forms>
authentication>
...
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";
}
h1>Log Inh1>
p>Please log in to access the administrative area:p>
@using(Html.BeginForm()) {
@Html.ValidationSummary(true)
@Html.EditorForModel()
p>input type="submit" value="Log in" />p>
}
[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();
}
}
SQL membership provider
connectionStrings>
add name="DefaultConnection" connectionString="Data Source=(localdb)\v11.0;AttachDbFileName=|DataDirectory|\mvc4empty.mdf;Initial Catalog=mvc4empty;Integrated Security=True"
providerName="System.Data.SqlClient"/>
connectionStrings>
membership defaultProvider="mySqlMembershipProvider">
providers>
clear />
add connectionStringName="DefaultConnection" enablePasswordRetrieval="false"
enablePasswordReset="true" requiresQuestionAndAnswer="false"
applicationName="/" requiresUniqueEmail="false" passwordFormat="Hashed"
passwordStrengthRegularExpression="" name="mySqlMembershipProvider"
type="System.Web.Security.SqlMembershipProvider" />
providers>
membership>
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);
}
}
}
@model SportsStore.WebUI.Models.LoginViewModel
@{
ViewBag.Title = "User: Register";
Layout = "~/Views/Shared/_AdminLayout.cshtml";
}
h1>User registerh1>
@if (ViewBag.Registered != null && ViewBag.Registered)
{
p>User "@Model.UserName" has been created sucessfully!p>
}
else
{
p>Please input user name and password to register:p>
using (Html.BeginForm())
{
@Html.ValidationSummary(true)
@Html.EditorForModel()
p>
input type="submit" value="Register" />p>
}
}
...
div>
@if (User.Identity.IsAuthenticated)
{
p>Current user:@User.Identity.Namep>
@Html.RouteLink("Logout",new {Controller="Account",Action="Logout",returnUrl=Request.Url.PathAndQuery})
}
else
{
span>@Html.RouteLink("Login",new {Controller="Account",Action="Login",returnUrl=Request.Url.PathAndQuery})span>
span>@Html.ActionLink("Register","Register","Account")span>
}
div>
div>
@if (User.IsInRole("Admin"))
{
@Html.ActionLink("Administrate", "Index", "Admin")
}
div>
...
Universal provider
...
configSections>
section name="entityFramework" type="System.Data.Entity.Internal.ConfigFile.EntityFrameworkSection, EntityFramework, Version=6.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" requirePermission="false" />
configSections>
...
profile defaultProvider="DefaultProfileProvider">
providers>
add name="DefaultProfileProvider" type="System.Web.Providers.DefaultProfileProvider, System.Web.Providers, Version=2.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" connectionStringName="DefaultConnection" applicationName="/" />
providers>
profile>
membership defaultProvider="DefaultMembershipProvider">
providers>
add name="DefaultMembershipProvider" type="System.Web.Providers.DefaultMembershipProvider, System.Web.Providers, Version=2.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" connectionStringName="DefaultConnection" enablePasswordRetrieval="false" enablePasswordReset="true" requiresQuestionAndAnswer="false" requiresUniqueEmail="false" maxInvalidPasswordAttempts="5" minRequiredPasswordLength="6" minRequiredNonalphanumericCharacters="0" passwordAttemptWindow="10" applicationName="/" passwordFormat="Hashed" passwordStrengthRegularExpression="" />
providers>
membership>
roleManager defaultProvider="DefaultRoleProvider">
providers>
add name="DefaultRoleProvider" type="System.Web.Providers.DefaultRoleProvider, System.Web.Providers, Version=2.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" connectionStringName="DefaultConnection" applicationName="/" />
providers>
roleManager>
sessionState mode="InProc" customProvider="DefaultSessionProvider">
providers>
add name="DefaultSessionProvider" type="System.Web.Providers.DefaultSessionStateProvider, System.Web.Providers, Version=2.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" connectionStringName="DefaultConnection" />
providers>
sessionState>
....
entityFramework>
defaultConnectionFactory type="System.Data.Entity.Infrastructure.SqlConnectionFactory, EntityFramework" />
providers>
provider invariantName="System.Data.SqlClient" type="System.Data.Entity.SqlServer.SqlProviderServices, EntityFramework.SqlServer" />
providers>
entityFramework>
...
membership>
Simple provider
WebSecurity.InitializeDatabaseConnection("DefaultConnection", "UserProfile", "UserId", "UserName", autoCreateTables: true);
文章标题:ASP.NET MVC 4 (十三) 基于表单的身份验证
文章链接:http://soscw.com/essay/25270.html