【從0開始.NET CORE認證】-2 使用.Net Core Identity和EF Core


回顧

朋友們,距離上次從0開始.NET CORE認證-1發布已經過去一周了,上次第一篇文章,其實並沒有涉及到Net Core Identity,就是簡單的搭了一個項目,讓大家對Identity中各種術語有個理解,明白他們出現的位置,已經他們出現能夠達到某種功能。以及出現的位置順序不同,則會出現什么不同的情況。

回顧一下上次寫的主要的知識點

  1. Authentication和Authorization 是什么,怎么解釋他們
  2. Claim和ClaimType又是什么,能舉例子說明嗎?
  3. ClaimsIdentity和ClaimsPrincipal的含義是什么,他們的從屬關系是什么樣的?
  4. app.UseAuthorization()和app.UseAuthentication()的意義是什么,能不能調換?

如果你對上面的問題都能回答,我相信你已經看懂了第一篇我講了什么。

介紹

本章,我將會正式引入.Net Core Identity,然后還會引入EF Core,將.Net Core Identity的用戶數據通過EF Core持久化到數據庫中,用大白話就是把用戶數據保存到數據庫,以下思維導圖的部分就是我們要做的部分

本文含有大量GIF圖,請耐心等待加載


創建項目

我們繼續使用第一篇文章中的解決方案,然后右鍵——添加——新建項目,選擇ASP.NET CORE Web 應用程序,項目名稱我們取為:AspNetCoreIdentityExample

同樣,我們需要MVC框架來幫助我們搭建前端頁面,所以修改一下StartUp.cs的內容,可以直接從上個項目BasiclyIdentity中復制一個基本代碼,使其修改成這樣。

 1 public class Startup
 2     {
 3         public void ConfigureServices(IServiceCollection services)
 4         {
 5             services.AddControllersWithViews();
 6         }
 7 
 8         public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
 9         {
10             if (env.IsDevelopment())
11             {
12                 app.UseDeveloperExceptionPage();
13             }
14 
15             app.UseRouting();
16 
17             app.UseEndpoints(endpoints =>
18             {
19                 endpoints.MapDefaultControllerRoute();
20             });
21         }
22     }
StartUp.cs

 具體操作看下面的圖

然后我們創建一個控制器名為HomeController,里面定義兩個Action,一個為Index,另外一個為Secert。也創建兩個視圖。我們可以直接復制BasiclyIdentity的視圖和控制器,並且運行。查看能否正常運行。

具體操作請看圖(

tips:一個解決方案內有多個可啟動項目,注意調試的時候選擇正確的項目):

 調試,發現可以成功運行了。那我們可以開展下一步了

配置框架

我們將會使用.Net Core Identity和EF Core幫助我們管理用戶,他並不會默認自帶在我們創建的項目中

所以我們需要引入五個Nuget包:

  1. Microsoft.AspNetCore.Identity
  2. Microsoft.AspNetCore.Identity.EntityFrameworkCore
  3. Microsoft.EntityFrameworkCore
  4. Microsoft.EntityFrameworkCore.SqlServer
  5. Microsoft.EntityFrameworkCore.Tools

這五個包負責不同的功能,

  1. Microsoft.AspNetCore.Identity //包含AspNetCore.Identity的框架,我們可以使用里面認證授權等功能,最基礎的功能
  2. Microsoft.AspNetCore.Identity.EntityFrameworkCore //對AspNetCore.Identity的擴展,讓其可以和EF Core配合使用
  3. Microsoft.EntityFrameworkCore //EF Core 這個不用我多說了吧
  4. Microsoft.EntityFrameworkCore.SqlServer //EF Core用來連接sql server的包,如果使用mysql,最后一個換名字就行了
  5. Microsoft.EntityFrameworkCore.Tools //在VS 命令行里面遷移數據需要用的命令 add-migration  update-database

然后安裝好這五個包之后,創建一個數據庫(這個數據庫可以是專門存放用戶信息的數據庫,也可以是跟業務耦合在一起的數據庫)因為這個只是關於用戶管理的示例項目,所以沒有業務。所以我會創建一個AppUserDb的數據庫,在項目中的appsetting.json中會配置好連接字符串

鏈接字符串的格式

Server=.;Database=TBS;User ID=AppUserDb;Password=Dd112233;Trusted_Connection=False;MultipleActiveResultSets=true

具體操作看圖-安裝NuGet包

創建數據庫和配置連接字符串

 

配置EF Core

我們先開始在項目下面創建一個Data文件夾,然后創建數據庫上下文AppDbContext.cs,讓其繼承DbContext,然后在StartUp.cs中注入這個上下文,隨后執行遷移命令,通過EF Core在數據庫內生成相應的表。

創建上下文,並注入。主要是以下代碼

 1 using Microsoft.EntityFrameworkCore;
 2 
 3 namespace AspNetCoreIdentityExample.Data
 4 {
 5     public class AppDbContext:DbContext
 6     {
 7         public AppDbContext(DbContextOptions<AppDbContext> options)
 8             :base(options)
 9         {
10 
11         }
12     }
13 }
AppDbContext.cs 
1  services.AddDbContext<AppDbContext>(config =>
2             {
3                 config.UseSqlServer(configuration.GetSection("ConnectionString").Value, opt =>
4                 {
5                     //opt.CommandTimeout(6000);
6                 });
7             });
在ConfigureServices增加下列代碼

具體操作看圖:

配置.Net Core Identity

我們在StartUp.cs文件中引用.Net Core Identity,其中IdentityUser和IdentityRole是框架內置的用戶類和角色類,如果我們需要做擴展,只需要繼承此類即可

主要是以下代碼

1 services.AddIdentity<IdentityUser, IdentityRole>()
2                 .AddDefaultTokenProviders();
在ConfigureServices增加下列代碼 

你認為到此結束了嗎?其實還沒有,在第一篇文章中,我們使用了Cookie作為認證授權的條件,但是我們這里好像沒有指定什么東西作為登錄授權的條件。所以我們也要為.Net Core Identity開啟Cookies認證(.Net Core Identity不僅僅支持Cookie,此話后文再說)

1 services.ConfigureApplicationCookie(config =>
2             {
3                 config.Cookie.Name = ".NetCoreIdentity.Cookies";
4                 config.LoginPath = "/Home/Login"; //讓沒有Cookie的用戶訪問被保護的接口時候跳轉到這個Api
5             });
在ConfigureServices增加下列代碼

具體操作看下圖:

同理,我們既然指定了當用戶沒有授權的時候,要跳轉到/Home/Login,所以我們要新增兩個頁面一個是登錄頁,一個是注冊頁

在HomeController里面增加兩個Action,使其變成下面的代碼,然后增加兩個頁面一個是Login.cshtml一個是Register.cshtml,代碼如下

 1 using Microsoft.AspNetCore.Authentication;
 2 using Microsoft.AspNetCore.Authorization;
 3 using Microsoft.AspNetCore.Mvc;
 4 using System.Collections.Generic;
 5 using System.Security.Claims;
 6 
 7 namespace AspNetCoreIdentityExample.Controllers
 8 {
 9     public class HomeController : Controller
10     {
11         public IActionResult Index()
12         {
13             return View("Index");
14         }
15 
16         [Authorize]
17         public IActionResult Secert()
18         {
19             return View("Secert");
20         }
21 
22         [HttpGet]
23         public IActionResult Login()
24         {
25             return View("Login");
26         }
27 
28         [HttpGet]
29         public IActionResult Register()
30         {
31             return View("Register");
32         }
33     }
34 }
HomeController
1 <h1>登錄頁</h1>
2 <form method="post" formaction="/Home/Login">
3     <input name="username" type="text" value="" />
4     <input name="password" type="password" value="" />
5     <button>登錄</button>
6 </form>
7 <a href="/Home/Register">沒有賬號去注冊</a>
Login.cshtml
1 <h1>注冊頁</h1>
2 <form method="post" formaction="/Home/Register">
3     <input name="username" type="text" value="" />
4     <input name="password" type="password" value="" />
5     <button>注冊</button>
6 </form>
7 <a href="/Home/Login">已有賬號去登陸</a>
Register.cshtml

操作請看圖

好了,現在我們想一想我們的准備工作還差什么,我們已經有了登錄、注冊頁面,然后認證方式也選了Cookie,我們也配置了數據庫。

所以,我們目前還少了將登錄、注冊的業務邏輯、將用戶數據持久化到數據庫的代碼。還有一個最重要的就是調用UseAuthorization()和UseAuthentication()方法,如果你不用這個方法,當訪問帶有[Authorize]標簽的控制器的時候,就會出錯,所以我們在StartUp.cs內配置一下

 

 

 

將Identity和EF Core結合起來

還記得我們安裝了一個Microsoft.AspNetCore.Identity.EntityFrameworkCore的包嗎?微軟給我們已經寫好了一個關於Identity的數據庫上下文,讓我們直接繼承這個上下文就可以在EF Core中使用Identity。

所以我們修改一下,打開AppDbContext.cs將本來繼承DbContext的,更改成IdentityDbContext

然后我們執行以下數據庫遷移(EF Core 一般都是寫代碼,然后把代碼中的類通過tools遷移到數據庫,就不需要手動設置數據庫了)。

在程序包控制台執行以下命令

1 Add-Migration InitUserDb -c AppDbContext -o AppMigration/User

然后執行

1 update-database

這樣數據庫就遷移成功了。具體操作看圖

現在數據庫也生成了,我們還需要在StartUp.cs將兩個關系綁定起來

上面兩個是孤立的,我們要增加一個方法改成下圖

在認證中開啟EntityFramworkStores;

現在運行一下我們的項目,能夠正常運行,然后訪問被保護的資源的時候會提示跳轉到登錄頁。

具體看圖

CURD用戶

准備工作

微軟很貼心的為我們准備了兩個類,一個是負責管理用戶信息的,一個是負責用戶登錄、登出轉換權限的

  1. UserManager<T>
  2. SignInManager<T>

從字面意思也能看出來,UserManager是管理用戶的,SiginManager是處理用戶登錄登出的,我們要在HomeController注入它們,然后使用它們,<T>是指用戶類型,如果你有個類繼承了IdentityUser這個類,那么你應該傳入你自定義的類,否則傳IdentityUser即可

代碼如下

1 private readonly UserManager<IdentityUser> _userManager;
2         private readonly SignInManager<IdentityUser> _signInManager;
3 
4         public HomeController(UserManager<IdentityUser> userManager,SignInManager<IdentityUser> signInManager)
5         {
6             _userManager = userManager;
7             _signInManager = signInManager;
8         }
注入UserManager和SiginManager

 

操作示意圖如下

 

登錄處理

一個用戶需要登錄,我們最簡單的登錄需要知道用戶的用戶名和密碼,so,我們在Home控制器下創建一個action叫做Login,指定參數username和password,如果登錄成功就跳轉到/Home/Secert頁面

代碼如下

 1 [HttpPost]
 2         public async Task<IActionResult> Login(string username, string password)
 3         {
 4             var user = await _userManager.FindByNameAsync(username).ConfigureAwait(false);
 5             if (user != null)
 6             {
 7                 var signResult = await _signInManager.PasswordSignInAsync(user, password, false, false).ConfigureAwait(false);
 8                 if (signResult.Succeeded)
 9                 {
10                     return View("Secert");
11                 }
12             }
13             return View("Index");
14         }
Login

 

操作示意圖如下

注冊處理

一個用戶需要注冊,我們可能需要很多信息,但是最重要的也就是賬號和密碼這是我們必須要收集的,我們在Home控制器下創建一個action叫做Register,指定參數username和password,如果注冊成功,那么我們就默認其已經登錄,然后就跳轉到/Home/Secert頁面

代碼如下

 1 [HttpPost]
 2         public async Task<IActionResult> Register(string username, string password)
 3         {
 4             var user = new IdentityUser
 5             {
 6                 UserName = username,
 7                 Email = "lihua@qq.com",
 8             };
 9             var createResult = await _userManager.CreateAsync(user, password);
10             if (createResult.Succeeded)
11             {
12                 var signResult = await _signInManager.PasswordSignInAsync(user, password, false, false);
13                 if (signResult.Succeeded)
14                 {
15                     return View("Index");
16                 }
17                 else
18                 {
19                     return View("Index");
20                 }
21             }
22             else
23                 return View("Register");
24         }
Register

 

操作示意圖如下

修改用戶

修改用戶我們必須先拿到這個用戶,然后去修改,所以肯定會傳遞過來一個要修改用戶的主鍵,我們在Home控制器下創建一個action叫做Update,這里我就演示成通過用戶名修改,

增加一個個人信息頁面名稱為Update.cshtml

代碼如下

1 [Authorize]
2         [HttpGet]
3         public async Task<IActionResult> Update()
4         {
5             var user = await _userManager.GetUserAsync(HttpContext.User);
6             ViewBag.Curs = user;
7             return View("Update");
8         }
在HomeController增加一個Action

 

然后增加一個頁面

1 <h1>修改個人信息</h1>
2 <form formaction="/Home/Update" method="post">
3     <input name="username" value="@ViewBag.Curs.UserName" />
4     <input name="email" value="@ViewBag.Curs.Email" />
5     <button>確認修改</button>
6 </form>
Update.cshtml

 

代碼如下

 1 [Authorize]
 2         [HttpPost]
 3         public async Task<IActionResult> Update(string username,string email)
 4         {
 5             var user = await _userManager.FindByNameAsync(username);
 6             if (user != null)
 7             {
 8                 user.Email = email;
 9                 var result = await _userManager.UpdateAsync(user);
10                 if (result.Succeeded)
11                     return RedirectToAction("Update");
12                 else
13                     return Ok("失敗");
14             }
15             else
16                 return Ok("user is not existed");
17         }
Update

 

操作示意圖如下

刪除用戶

跟修改用戶一樣,肯定是拿到主鍵才能刪除,所以我演示成username作為主鍵拿到用戶

代碼如下

1 [Authorize]
2         [HttpGet]
3         public async Task<IActionResult> RemoveUser()
4         {
5             var user = await _userManager.GetUserAsync(HttpContext.User);
6             ViewBag.Curs = user;
7             return View("Remove");
8         }
在HomeController增加一個Action

 

然后增加一個頁面

1 <h1>刪除信息</h1>
2 <form formaction="/Home/RemoveUser" method="post">
3     <input name="username" value="@ViewBag.Curs.UserName" />
4     <button>確認刪除</button>
5 </form>
RemoveUser.cshtml

 

 1 [Authorize]
 2         [HttpPost]
 3         public async Task<IActionResult> RemoveUser(string username)
 4         {
 5             var user = await _userManager.FindByNameAsync(username);
 6             if (user != null)
 7             {
 8                 var result = await _userManager.DeleteAsync(user);
 9                 if(result.Succeeded)
10                     return RedirectToAction("Index");
11                 else
12                     return Ok("失敗");
13             }
14             return Ok("user is not existed");
15         }
RemoveUser

 

操作示意圖如下

 

 

 至此所有工作都准備好,測試一下。

可以看到,非常成功。有了.Net Core Identity配合EF Core就不需要我們自己去寫一套用戶管理邏輯了。

總結

  1. 學習了怎么使用.Net Core Identity和EF Core綁定使用
  2. 學習了兩個基本類UserManager和SiginManager
  3. 學習了增刪改用戶信息

問題

  1. 如果我刪除用戶的時候,我把我自己刪除了,然后我還能繼續訪問需要授權的頁面嗎?
  2. 更新個人信息的時候,更新成功了,Cookies會變嗎?
  3. 隱藏小BUG,在注冊用戶的時候,會提示一個錯誤,並且需要修改一處代碼!你能找到它嗎?

又寫完一篇,決定上傳項目

gitee地址:https://gitee.com/JiMoKongTingChunYuWan_admin/IdentityDemo

github地址:https://github.com/Mrlie/IdentityDemo.git

下周見


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM