ASP.NET Core Identity 验证特性
上一章节我们简单介绍了下 Identity 框架,知道 Identity 框架可以用来验证也识别用户。本章节我们就开始进入正题,如何使用 Identity 框架
验证用户身份的第一步就是要标识那些控制器哪些操作需要验证用户,而这一步操作可以使用 Identity 框架提供的 [Authorize]
特性来解决
[Authorize]
就是本章节要讨论的验证特性
到目前为止,在我们的应用程序中,我们已允许匿名用户执行任何操作。任何可以访问我们应用程序的用户,都可以编辑员工详细信息并查看详细信息
咦,好像,我们的应用程序没有创建新员工的功能。那么,我们首先添加创建功能,然后再来讨论如何使用授权特性来限制用户访问
添加新用户
我们先来做这个功能的规划,也就是需求分析
-
首先,首页有一个名为 新增员工 的链接,链接到
/home/create
表单页面用于输入新用户的信息 ( 目前为止,也就是员工姓名啦 ) -
当输入员工信息后,表单将使用 HTTP POST 方法将提交到
/home/create
,数据校验通过并保存后,返回首页
很简单吧,开始吧
我们先双击打开 Views/Home/Index.cshtml
,添加一个名为 新增员工 的链接,链接到 /home/create
,完整代码如下
Index.cshtml
@model HomePageViewModel @{ ViewBag.Title = "职工列表"; } <style> body {margin:10px auto;text-align:center} table { margin:0 auto; width:90% } table, th, td { border:1px solid #eee; border-collapse:collapse; border-spacing:0; padding:5px; text-align:center } .txt-left { text-align:left; } </style> <h1>职工列表</h1> <table> <tr> <td>ID</td> <td>姓名</td> <td class="txt-left">操作</td> </tr> @foreach (var employee in Model.Employees) { <tr> <td>@employee.ID</td> <td>@employee.Name</td> <td class="txt-left"><a asp-action="Detail" asp-route-Id="@employee.ID">详情</a> <a asp-controller="Home" asp-action="Edit" asp-route-id="@employee.ID">编辑</a></td> </tr> } </table> <br/> <p><a asp-action="Create" >新增员工/a></p>
保存 Index.cshtml
并刷新浏览器,显示如下
点击 新增员工 链接,不用想,肯定报错,因为我们没有添加 Create()
方法
好吧,那我们继续修改 HomeController
类添加一个 Create()
方法
[HttpGet] public ViewResult Create() { return View(); }
我们使用 [HttpGet]
来标识该方法只接受 HTTP GET 请求,然后保存文件,当然了,不用重启应用程序,想都不用想,因为我们没有创建 Create.cshtml
所以肯定报错
那么,我们就在 Views/Home/
目录下创建一个普通视图 Create.cshtml
吧,该视图包含一个表单,表单里只有一个字段,用于输入员工姓名
Create.cshtml
@model Employee @{ ViewBag.Title = "Create"; } <h1>新增员工</h1> @using (Html.BeginForm()) { <div> @Html.LabelFor(m => m.Name) @Html.EditorFor(m => m.Name) @Html.ValidationMessageFor(m => m.Name) </div> <div> <input type="submit" value="保存" /> </div> }
是不是又发现了很多新面孔,我们使用了很多标签助手
标签助手 | 说明 |
---|---|
Html.BeginForm | 用于创建一个默认使用 HTTP POST 请求方法的 HTML 表单 <form> |
Html.LabelFor | 用于创建 HTML 标签 <label> |
Html.EditorFor | 用于创建一个 type 属性默认为 text 的 <input> |
Html.ValidationMessageFor | 用于显示验证信息 |
保存所有代码,重新启动应用程序,然后刷新浏览器,输出如下
如果我们输入一些数据,比如 王勃 则继续 404 报错,因为我们没有创建接收 HTTP POST 的 Create
方法
继续修改 HomeController
,添加接收 HTTP POST 的 Create()
方法
[HttpPost] public IActionResult Create(EmployeeEditViewModel model) { if (ModelState.IsValid) { var employee = new Employee(); employee.Name = model.Name; SQLEmployeeData sqlData = new SQLEmployeeData( _context ); sqlData.Add(employee); return RedirectToAction("Detail", new { id = employee.ID }); } return View(); }
这次几乎没啥新面孔了,至于 sqlData.Add(employee)
,扳着脚趾头也知道是将数据保存到数据库中的
所以,直接重启应用程序,然后重新提交我们的 王勃,数据验证通过后,就会跳转到王勃的详情页,显示如下
点击返回首页,就可以看到员工 ID 为 4 的王勃了
[Authorize] 与 [AllowAnonymous]
像我这种程序员也能新增员工,那真是大大的,大大的权限啊,如果这样发不到外网,那肯定要被骂死,扣工资,开除,然后喝西北风了
所以,我们赶紧修改下,让匿名用户只能看到主页上的员工列表,其它任何操作都需要用户已经登录
为了实现这个功能,我们可以使用 [Authorize]
特性来限制
我们可以把 [Authorize]
特性放在控制器上,那么该控制器的所有方法都必须需要授权才能访问,也可以放在控制器内的动作方法上,那么只有该动作方法需要授权访问
[Authorize] public class HomeController : Controller { //.... }
默认情况下,如果不传递其它参数给 Authorize
,授权检查的唯一项目就是确认用户是否已经登录,我们也可以使用参数来指定任何自定义授权策略
除了 [Authorize]
外,还有一个特性 [AllowAnonymous]
。当想要在使用了 [Authorize]
特性的某个控制器的动作方法上取消保护并允许匿名用户访问时,可以使用该特性
[AllowAnonymous] public ViewResult Index() { //.... }
欧,忘记说了 Authorize
与 AllowAnonymous
特性都在命名空间 Microsoft.AspNetCore.Authorization
,所以使用之前先要引入该命名空间
好了,介绍的差不多了,接下来我们给 HomeController
加上 [Authorize]
,然后给 Index()
方法加上 [AllowAnonymous]
添加完成后的完整代码如下
using Microsoft.AspNetCore.Mvc; using System.Collections.Generic; using System.Linq; using System.ComponentModel.DataAnnotations; using Microsoft.AspNetCore.Authorization; using HelloWorld.Models; namespace HelloWorld.Controllers { [Authorize] public class HomeController: Controller { private readonly HelloWorldDBContext _context; public HomeController(HelloWorldDBContext context) { _context = context; } [AllowAnonymous] public ViewResult Index() { var model = new HomePageViewModel(); SQLEmployeeData sqlData = new SQLEmployeeData(_context); model.Employees = sqlData.GetAll(); return View(model); } public ViewResult Detail(int id) { var model = new HomePageViewModel(); SQLEmployeeData sqlData = new SQLEmployeeData(_context); Employee employee = sqlData.Get(id); return View(employee); } [HttpGet] public IActionResult Edit(int id) { var model = new HomePageViewModel(); SQLEmployeeData sqlData = new SQLEmployeeData(_context); Employee employee = sqlData.Get(id); if ( employee == null ) { return RedirectToAction("Index"); } return View(employee); } [HttpPost] public IActionResult Edit(int id, EmployeeEditViewModel input) { SQLEmployeeData sqlData = new SQLEmployeeData( _context ); var employee = sqlData.Get(id); if (employee != null && ModelState.IsValid) { employee.Name = input.Name; _context.SaveChanges(); return RedirectToAction("Detail", new { id = employee.ID }); } return View(employee); } [HttpGet] public ViewResult Create() { return View(); } [HttpPost] public IActionResult Create(EmployeeEditViewModel model) { if (ModelState.IsValid) { var employee = new Employee(); employee.Name = model.Name; SQLEmployeeData sqlData = new SQLEmployeeData(_context); sqlData.Add(employee); return RedirectToAction("Detail", new { id = employee.ID }); } return View(); } } public class SQLEmployeeData { private HelloWorldDBContext _context { get; set; } public SQLEmployeeData(HelloWorldDBContext context) { _context = context; } public void Add(Employee emp) { _context.Add(emp); _context.SaveChanges(); } public Employee Get(int ID) { return _context.Employees.FirstOrDefault(e => e.ID == ID); } public IEnumerable<Employee> GetAll() { return _context.Employees.ToList<Employee>(); } } public class HomePageViewModel { public IEnumerable<Employee> Employees { get; set; } } public class EmployeeEditViewModel { [Required, MaxLength(80)] public string Name { get; set; } } }
保存我们的 HomeController.cs
,重启应用程序,然后刷新浏览器,当访问首页时,因为允许匿名用户访问,所以可以正常显示
但如果我们点击 新增员工 或 详情 或 编辑 时,则会报错
为什么是报错而不是弹出我们想要的 401 未授权用户.....坑啊
为啥呢? 从错误消息中可以看出,我们还没有对 Identity 进行配置
算了,算了,下一章再说吧