【譯】MVC3 20個秘方-(1)用密碼保護限制對view的訪問
場景
你想阻止用戶訪問你網站的特定頁面,除非用戶已經注冊并且使用了用戶名和密碼登陸。
<!--[if !supportLineBreakNewLine]-->
解決方案
使用一個AccountController,AccountModels 和 幾個MVC View,配合ASP.NET的 AuthorizeAttribute 特性,FormsAuthentication和Membership creation/validation
討論
微軟的MVC團隊已經對賬戶controller做了很多的改進。它已經被更新用于Form驗證,連同Membership 類去創建新的用戶,驗證存在的用戶,創建cookie去檢測用戶登入的狀態。
在MVC 3中 已經提供了幾種默認的應用程序模板。如下圖。

? Empty,一個空的模板將創建一些MVC需要的文件結構。
? Internet Application,一個因特網應用程序的默認的模板將要包含一些預配置:basic layout,一個AccountController包含了多個action(注冊,登陸,修改密碼等)。
? Intranet Application,內部網應用程序。他和第二個模板類似。但是他沒有使用Membership 類,而是使用了windows身份驗證。
對于大多數網站,我們默認應該使用第二個模板。如果你現在還沒有這樣做,你可以現在創建一個MVC 3 Internet Application。
這將生成AccountController, AccountModels 和幾個Account的Views(用戶注冊,登陸,修改密碼)。
為了組織用戶訪問特定的view,MVC 提供了一個AuthorizeAttribute 特性。打開AccountController你可以看到如下代碼:
// GET: /Account/ChangePassword
[Authorize]
public ActionResult ChangePassword()
{
return View();
}
它的意圖是只有登陸用戶才可以訪問密碼修改頁面。
當一個用戶訪問頁面/Account/ChangePassword,如果他沒有預先登陸或注冊。MVC將自動把請求轉到登陸頁面。否則MVC將轉到轉到changePassword頁。對于未驗證的用戶的跳轉頁面是在web.config里配置的。
<authentication mode="Forms">
<forms loginUrl="~/Account/LogOn" timeout="2880"/>
</authentication>
如果用戶從來都沒有注冊過,那么他可以在登陸頁點擊注冊跳轉到注冊頁面。這個頁面包含以下信息:
? Username
? Email Address
? Password
AccountController中的Register action 接收一個RegisterModel 類型的參數。在AccountModels中有一個類型被定義為RegisterModel,它包含了注冊頁面上元素的變量(username,EmailAddress,Password)。
注冊action:
View Code
[HttpPost]
public ActionResult Register(RegisterModel model)
{
if (ModelState.IsValid)
{
// Attempt to register the user
MembershipCreateStatus createStatus;
Membership.CreateUser(model.UserName,
model.Password, model.Email, null, null,
true, null, out createStatus);
if (createStatus ==
MembershipCreateStatus.Success)
{
FormsAuthentication.SetAuthCookie(
model.UserName,
false /* createPersistentCookie */);
return RedirectToAction("Index", "Home");
}
else
{
ModelState.AddModelError("",
ErrorCodeToString(createStatus));
}
}
// If we got this far, something failed,
// redisplay form
return View(model);
上邊的代碼是自動生成的,他們做了三件重要的事。
- 通過Membership.CreateUser()方法創建了一個新的用戶。
- 如果創建成功,設置一個cookie給user 確保他可以訪問隨后的頁面。
- 如果創建成功,會跳轉到主頁(如果創建失敗,將會把錯誤消息顯示到指定的view)。
如果你已經安裝了完整版本的visual studio和SQL Express。你可以在數據庫里看到你創建的user。
方法是:在解決方案管理器里查看AppData下的ASPNETDB.MDF。直接打開就可以。下圖是我剛剛創建的一個用戶。

默認的數據庫連接字符串在webconfig里。
<connectionStrings>
<add name="ApplicationServices" connectionString="data source=.\SQLEXPRESS;Integrated Security=SSPI;AttachDBFilename=|DataDirectory|aspnetdb.mdf;
User Instance=true"providerName="System.Data.SqlClient"/>
</connectionStrings>
將來用戶再次訪問網站的時候,如果FormsAuthentication cookie仍然被保存(假設在登錄的時候他選定了記住我選項,或者他沒有關閉瀏覽器),他們就不需要再次登錄。
如果cookie沒有被保存。他就要被導航到登錄頁面了。一旦用戶輸入了登陸信息并且提交表單。AccountController將再通過Membership 類去驗證用戶。如下:
View Code
[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);
}
上邊的代碼頁是自動生成的。做了三件事:
1. 通過 Membership.ValidateUser() 驗證用戶名和密碼
2.如果登陸成功,使用FormsAuthentication.SetAuthCookie 來保存一個cookie。
3如果通過驗證,會導航到主頁,否則會在登陸頁顯示錯誤信息。
AuthorizeAttribute 特性可以進一步限定特定的用戶組或者特定的用戶才可以訪問指定的action
例如:
View Code
// Retrieve a list of all users to allow an admin
// to manage them
[Authorize(Roles = "Admin")]
public ActionResult UserAdmin()
{
MembershipUserCollection users =
Membership.GetAllUsers();
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();
}
以上簡單的例子僅僅是怎樣限制訪問內容的開始。
另請參閱
AuthorizeAttribute, FormsAuthentication, and Membership
<!--[endif]-->


浙公網安備 33010602011771號