假设有这么一个场景你想阻止用户访问你网站的特定页面除非用户已经注册并且使用了用户名和密码登陆
解决方案使用一个AccountControllerAccountModels 和 几个MVC View配合ASPNET的 AuthorizeAttribute 特性FormsAuthentication和Membership creation/validation
讨论
微软的MVC团队已经对账户controller做了很多的改进它已经被更新用于Form验证连同Membership 类去创建新的用户验证存在的用户创建cookie去检测用户登入的状态
在MVC 中 已经提供了几种默认的应用程序模板如下图
①Empty一个空的模板将创建一些MVC需要的文件结构
②Internet Application一个因特网应用程序的默认的模板将要包含一些预配置basic layout一个AccountController包含了多个action(注册登陆修改密码等)
③Intranet Application内部网应用程序他和第二个模板类似但是他没有使用Membership 类而是使用了windows身份验证
对于大多数网站我们默认应该使用第二个模板如果你现在还没有这样做你可以现在创建一个MVC Internet Application
这将生成AccountController AccountModels 和几个Account的Views(用户注册登陆修改密码)
为了组织用户访问特定的viewMVC 提供了一个AuthorizeAttribute 特性打开AccountController你可以看到如下代码
// GET: /Account/ChangePassword
[Authorize]
public ActionResult ChangePassword()
{
return View(); }
它的意图是只有登陆用户才可以访问密码修改页面
当一个用户访问页面/Account/ChangePassword如果他没有预先登陆或注册MVC将自动把请求转到登陆页面否则MVC将转到转到changePassword页对于未验证的用户的跳转页面是在nfig里配置的
<authentication mode=Forms>
<forms loginUrl=~/Account/LogOn timeout=/>
</authentication>
如果用户从来都没有注册过那么他可以在登陆页点击注册跳转到注册页面这个页面包含以下信息UsernameEmail Address和Password
AccountController中的Register action 接收一个RegisterModel 类型的参数在AccountModels中有一个类型被定义为RegisterModel它包含了注册页面上元素的变量(usernameEmailAddressPassword)
注册action
[HttpPost]
public ActionResult Register(RegisterModel model)
{
if (ModelStateIsValid)
{
// Attempt to register the user
MembershipCreateStatus createStatus;
MembershipCreateUser(modelUserName
modelPassword modelEmail null null
true null out createStatus);
if (createStatus ==
MembershipCreateStatusSuccess)
{
FormsAuthenticationSetAuthCookie(
modelUserName
false /* createPersistentCookie */);
return RedirectToAction(Index Home);
}
else
{
ModelStateAddModelError(
ErrorCodeToString(createStatus));
}
}
// If we got this far something failed
// redisplay form
return View(model);
上边的代码是自动生成的他们做了三件重要的事
①通过MembershipCreateUser()方法创建了一个新的用户
②如果创建成功设置一个cookie给user 确保他可以访问随后的页面
③如果创建成功会跳转到主页(如果创建失败将会把错误消息显示到指定的view)
如果你已经安装了完整版本的visual studio和SQL Express你可以在数据库里看到你创建的user
方法是在解决方案管理器里查看AppData下的ASPNETDBMDF直接打开就可以下图是我刚刚创建的一个用户
默认的数据库连接字符串在webconfig里
<connectionStrings>
<add name=ApplicationServices connectionString=data source=\SQLEXPRESS;Integrated Security=SSPI;AttachDBFilename=|DataDirectory|aspnetdbmdf;
User Instance=trueproviderName=SystemDataSqlClient/>
</connectionStrings>
将来用户再次访问网站的时候如果FormsAuthentication cookie仍然被保存(假设在登录的时候他选定了记住我选项或者他没有关闭浏览器)他们就不需要再次登录
如果cookie没有被保存他就要被导航到登录页面了一旦用户输入了登陆信息并且提交表单AccountController将再通过Membership 类去验证用户如下
[HttpPost]
public ActionResult LogOn(LogOnModel model
string returnUrl)
{
if (ModelStateIsValid)
{
if (MembershipValidateUser(modelUserName
modelPassword))
{
FormsAuthenticationSetAuthCookie(
modelUserName modelRememberMe);
if (UrlIsLocalUrl(returnUrl)
&& returnUrlLength >
&& returnUrlStartsWith(/)
&& !returnUrlStartsWith(//)
&& !returnUrlStartsWith(/\\))
{
return Redirect(returnUrl);
}
else
{
return RedirectToAction(Index Home);
}
}
else
{
ModelStateAddModelError(
The user name or password provided
is incorrect);
}
}
// If we got this far something failed
// redisplay form
return View(model);
}
上边的代码页是自动生成的做了三件事
①通过 MembershipValidateUser() 验证用户名和密码
②如果登陆成功使用FormsAuthenticationSetAuthCookie 来保存一个cookie
③如果通过验证会导航到主页否则会在登陆页显示错误信息
AuthorizeAttribute 特性可以进一步限定特定的用户组或者特定的用户才可以访问指定的action
例如
// Retrieve a list of all users to allow an admin
// to manage them
[Authorize(Roles = Admin)]
public ActionResult UserAdmin()
{
MembershipUserCollection users =
MembershipGetAllUsers();
return View(users);
}
// Create some custom reports for me only
[Authorize(Users = Jamie)]
public ActionResult JamieAdmin()
{
// Perform some logic to generate usage reports
return View();
}