西北狼

-- 学而时习之,不亦乐乎!
  博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

MVC学习之认证和授权

Posted on 2009-05-25 01:50  西北老狼  阅读(1690)  评论(1编辑  收藏  举报

 

现在NerdDinner范例程序可以让访问网站的任何人创建和编辑任何Dinner的信息。下面我们改变这些,仅仅注册和登录的用户才允许创建新的Dinner,并且增加限制,仅仅Dinner的主持人才允许编辑Dinner的详细信息。
为了实现上述功能,我们将使用认证和授权来保护应用程序。
 
理解认证和授权
认证是识别和验证访问应用程序的客户,简而言之,就是识别访问网站的终端用户是谁。
ASP.NET 支持多种方式来认证浏览器用户。对Internet应用程序而言,最通用的认证方法是Forms Authentication。Form Authentication允许开发人员创建一个HTML登录表单,连接数据库或其它密码表,验证用户提交的用户名/密码。如果用户名/密码是正确的,开发人员接着让ASP.NET生成一个加密的HTTP cookie,识别用户随后的请求。我们将在NerdDinner范例程序中使用Form Authentication。
 
授权是判断是否一个验证的用户有权限访问一个特定的URL或资源,执行一些操作。例如,在NerdDinner范例程序中,我们将授权仅仅登录的用户可以访问/Dinners/Create URL网址,并创建一个新的Dinner对象。我们也授权仅仅Dinner的主持人可以编辑该条记录,并拒绝其他人修改。
 
Forms Authentication和AccountController
在创建ASP.NET MVC应用程序时,ASP.NET MVC的默认Visual Studio 项目模板自动实现了Forms Authentication,也自动添加一个预先创建的账户登录实现,使得站点集成安全验证更加容易。
 
当未登录的用户访问NerdDinner范例程序时,默认的Site.Master Master 页面在右上角显示一个Log On(登录)链接。点击Log On 链接,引导用户到/Account/LogOn URL。
 

 
没有注册的访问者可点击Register注册链接,进入/Account/Register 地址,允许输入帐号的信息:
 
 
点击Register按钮在ASP.NET Membership 系统创建一个新的用户,并使用Forms Authentication认证用户。
当用户登录后,Site.Master更改右上角的输出为Welcome [username]!,以及一个Log Off的链接,一旦点击Log Off链接将退出登录。
上述的登录、退出和注册功能都在AccountController类中实现,该类是在创建ASP.NET MVC项目时自动创建的,相应的用户界面通过视图模板实现的,存放在\Views\Account目录:
 
 
AccountController类使用ASP.NET Forms Authentication系统生成加密的认证cookies,和ASP.NET Membership API来存放和验证用户名/密码。ASP.NET Membership API是可扩展的,并实现任何使用任何密码库。ASP.NET 内置的membership provider实现了将用户名/密码存放在SQL数据库,或者活动目录(Active Directory)中。
我们可以配置NerdDinner范例程序中的membership provider,打开根目录的web.config 配置文件,查找<membership>节点。当项目创建时,默认的web.config已经添加了,并注册了SQL Membership Provider,并配置了使用ApplicationServices连接字符串来指定数据库。
默认的ApplicationServices连接字符串(web.config配置文件中的<connectionStrings>节点)配置使用SQL Express,指向ASPNETDB.MDF SQL Express数据库,该DB文件存放在App_Data目录。如果在Membership API第一次使用时,该数据库文件不存在,ASP.NET 将自动创建数据库,并准备合适的数据库schema。
 

 
如果不想使用SQL Express,而想使用SQL Server实例(或连接一个远程数据库),我们需要做的只是更新web.config 配置文件中的ApplicationServices连接字符串,并确保合适的membership schema在该数据库中已经正确地创建了。你可以在如下目录:
\Windows\Microsoft.NET\Framework\v2.0.50727\
运行 aspnet_regsql.exe 工具,添加合适的membership schema,以及其他ASP.NET 应用程序服务到数据库中。
 
使用[Authorize]过滤器对/Dinners/Create授权
对NerdDinner范例程序,我们不必写任何代码来实现安全认证和帐号管理实现。用户可以注册新帐号,登录/退出网站。现在,我们添加授权逻辑到范例应用程序中,并使用认证状态和访问者的用户名,来控制他们在站点中能做什么,和不能做什么。
首先,我们添加授权逻辑到DinnersController类的Create Action方法上。我们要求访问/Dinners/Create URL网址的用户必须登录,如果他们没有登录,将重定向到登录页面,以便他们可以登录。
实现这一逻辑非常简单,我们需要做的是添加 [Authorize] 过滤器属性到Create Action 方法上,如下所示:
//
// GET: /Dinners/Create
[Authorize]
public ActionResult Create() {
...
}
//
// POST: /Dinners/Create
[AcceptVerbs(HttpVerbs.Post), Authorize]
public ActionResult Create(Dinner dinnerToCreate) {
...
}
 
ASP.NET MVC 支持创建action过滤器,实现可重用的逻辑应用到action方法上。[Authorize] 过滤器是ASP.NET MVC内置的action过滤器,开发人员可以定义授权规则应用到action方法和Controller 类上。
如果[Authorize] 没有带任何参数,则强制要求用户请求action方法时必须登录,否则重定向到登录页面。当重定向时,原来的请求URL会作为querystring参数跟在URL后面(如,/Account/LogOn?ReturnUrl=%2fDinners%2fCreate),在用户登录完成后,AccountController再次重定向用户返回开始请求的页面。
[Authorize] 过滤器也支持指定Users或Roles属性,该属性要求用户必须登录,此外还要求用户必须在允许的用户列表中或允许的角色成员。例如,如下代码仅允许2个指定的用户,”EntLib.com”和”EntLibForum” 访问/Dinners/Create 路径:
[Authorize(Users="EntLib.com,EntLibForum")]
public ActionResult Create() {
...
}
 
将特定的用户名直接写在代码中不易于将来的代码维护,更好的办法是定义一个roles(角色),然后通过数据库或者活动目录(Active Directory)映射用户到角色中。ASP.NET 提供了一个内置的角色管理API和一组内置的Role provider(包括SQL 和活动目录),帮助实现用户/角色的映射。我们接着更新代码,仅允许admin角色的用户访问/Dinners/Create URL。
[Authorize(Roles="admin")]
public ActionResult Create() {
...
}
 
创建Dinners时,使用User.Identity.Name 属性
在查询当前登录的用户名时,我们可以使用Controller基类公开的User.Identity.Name属性。
之前,我们实现HTTP-POST 的Create() action 方法时,Dinner的HostedBy属性是让用户在页面手动输入的。这里,我们可以更新代码,使用User.Identity.Name属性给HostedBy赋值,同时自动为支持人增加一条RSVP记录:
        //
        // POST: /Dinners/Create
        [AcceptVerbs(HttpVerbs.Post), Authorize]
        public ActionResult Create(Dinner dinner)
        {
            if (ModelState.IsValid)
            {
                try
                {
                    dinner.HostedBy = User.Identity.Name;
 
                    RSVP rsvp = new RSVP();
                    rsvp.AttendeeName = User.Identity.Name;
                    dinner.RSVPs.Add(rsvp);
 
                    dinnerRepository.Add(dinner);
                    dinnerRepository.Save();
                   
                    return RedirectToAction("Details", new { id = dinner.DinnerID });
                }
                catch
                {
                    ModelState.AddRuleViolations(dinner.GetRuleViolations());
                    // ViewData["countries"] = new SelectList(PhoneValidator.Countries, dinner.Country);
                }
            }
            // return View(dinner);
 
            // 使用ViewModel
            return View(new DinnerFormViewModel(dinner));
 
        }
 
因为我们给Create() 方法添加了[Authorize] 属性,ASP.NET MVC将确保仅登录的用户才允许访问/Dinners/Create 地址,并执行该方法。同时,User.Identity.Name属性将一定有一个有效的用户名。