前言
之前我們進行了MVC的web頁面的Cookie-based認證實現,接下來的開發我們要基於之前的MvcCookieAuthSample項目做修改。
MvcCookieAuthSample項目地址:http://www.cnblogs.com/wyt007/p/8128186.html
UI
我們首先在AccountController中添加兩個Action
public IActionResult Register()
{
return View();
} public IActionResult Login() { return View(); }
然后在Views文件夾下新增Account文件夾並新增Register.cshtml與Login.cshtml視圖,樣式我們盡量從上一節的Identity視圖中拷貝過來。
我們還需要新建一個ViewModels,在ViewModels中新建RegisterViewModel.cs來接收表單提交的值以及來進行強類型視圖
namespace MvcCookieAuthSample.ViewModels { public class RegisterViewModel { //郵箱 public string Email { get; set; } //密碼 public string Password { get; set; } //確認密碼 public string ConfirmedPassword { get; set; } } }
Register.cshtml代碼(只保留部分拷貝過來的內容,並加入強類型視圖引用):

@{ ViewData["Title"] = "Register"; } @using MvcCookieAuthSample.ViewModels; @model RegisterViewModel; <h2>@ViewData["Title"]</h2> <h3>@ViewData["Message"]</h3> <div class="row"> <div class="col-md-4"> <form method="post"> <h4>Create a new account.</h4> <hr /> <div class="form-group"> <label asp-for="Email"></label> <input asp-for="Email" class="form-control" /> </div> <div class="form-group"> <label asp-for="Password"></label> <input asp-for="Password" class="form-control" /> </div> <div class="form-group"> <label asp-for="ConfirmedPassword"></label> <input asp-for="ConfirmedPassword" class="form-control" /> </div> <button type="submit" class="btn btn-default">Register</button> </form> </div> </div>
Login.cshtml代碼(只保留部分拷貝過來的內容,並加入強類型視圖引用):

@{ ViewData["Title"] = "Login"; } @using MvcCookieAuthSample.ViewModels; @model RegisterViewModel; <div class="row"> <div class="col-md-4"> <section> <form method="post"> <h4>Use a local account to log in.</h4> <hr /> <div class="form-group"> <label asp-for="Email"></label> <input asp-for="Email" class="form-control" /> </div> <div class="form-group"> <label asp-for="Password"></label> <input asp-for="Password" type="password" class="form-control" /> </div> <div class="form-group"> <button type="submit" class="btn btn-default">Log in</button> </div> </form> </section> </div> </div>
然后在_Layout.cshtml中添加導航代碼:

<ul class="nav navbar-nav navbar-right"> <li><a asp-area="" asp-controller="Account" asp-action="Register">Register</a></li> <li><a asp-area="" asp-controller="Account" asp-action="Login">Log in</a></li> </ul>
然后運行網站,UI已經實現
EF + Identity實現
EF實現
首先我們添加一個Data文件夾,由於VSCode的代碼提示不是很好,接下來我們用VS2017開發。
我們首先在Models文件夾下面新建ApplicationUser.cs與ApplicationUserRole.cs
ApplicationUser.cs代碼:
using Microsoft.AspNetCore.Identity; namespace MvcCookieAuthSample.Models { public class ApplicationUser:IdentityUser<int>//不加int的話是默認主鍵為guid { } }
ApplicationUserRole.cs代碼:
using Microsoft.AspNetCore.Identity; namespace MvcCookieAuthSample.Models { public class ApplicationUserRole: IdentityRole<int>//不加int的話是默認主鍵為guid { } }
然后在Data文件夾下新建一個ApplicationDbContext.cs類,使它繼承IdentityDbContext
using Microsoft.AspNetCore.Identity.EntityFrameworkCore; using Microsoft.EntityFrameworkCore; using MvcCookieAuthSample.Models; namespace MvcCookieAuthSample.Data { public class ApplicationDbContext:IdentityDbContext<ApplicationUser, ApplicationUserRole,int> { public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options):base(options) { } } }
然后我們需要在Startup.cs添加EF的注冊進來
//使用配置ApplicationDbContext使用sqlserver數據庫,並配置數據庫連接字符串 services.AddDbContext<ApplicationDbContext>(options=> { options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection")); });
然后我們需要在appsettings.json中配置數據庫連接字符串
"ConnectionStrings": { "DefaultConnection": "Server=192.168.1.184;Database=aspnet-IdentitySample-9A22BB3E-8D53-4F44-B533-2EF927C959DE;Trusted_Connection=True;MultipleActiveResultSets=true;uid=sa;pwd=123456" }
EF實現結束
Identity實現
我們需要在Startup.cs添加Identity的注冊進來
//配置Identity services.AddIdentity<ApplicationUser, ApplicationUserRole>() .AddEntityFrameworkStores<ApplicationDbContext>() .AddDefaultTokenProviders();
由於默認的Identity在密碼上限制比較嚴格,我們把它改的寬松簡單一點(不設置也行)
//修改Identity配置 services.Configure<IdentityOptions>(options => { options.Password.RequireLowercase = false;//需要小寫 options.Password.RequireNonAlphanumeric = false;//需要字母 options.Password.RequireUppercase = false;//需要大寫 });
然后我們把認證的地址改成/Account/Login
然后我們修改AccountController,加入以下代碼
private UserManager<ApplicationUser> _userManager;//創建用戶的 private SignInManager<ApplicationUser> _signInManager;//用來登錄的 //依賴注入 public AccountController(UserManager<ApplicationUser> userManager, SignInManager<ApplicationUser> signInManager) { _userManager = userManager; _signInManager = signInManager; } [HttpPost] public async Task<IActionResult> Register(RegisterViewModel registerViewModel) { var identityUser = new ApplicationUser { Email = registerViewModel.Email, UserName = registerViewModel.Email, NormalizedUserName = registerViewModel.Email }; var identityResult=await _userManager.CreateAsync(identityUser, registerViewModel.Password); if (identityResult.Succeeded) { return RedirectToAction("Index", "Home"); } return View(); }
完整的AccountController

using System; using System.Collections.Generic; using System.Diagnostics; using System.Linq; using System.Threading.Tasks; using Microsoft.AspNetCore.Mvc; using MvcCookieAuthSample.Models; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Authentication; using Microsoft.AspNetCore.Authentication.Cookies; using System.Security.Claims; using MvcCookieAuthSample.ViewModels; using Microsoft.AspNetCore.Identity; namespace MvcCookieAuthSample.Controllers { public class AccountController : Controller { private UserManager<ApplicationUser> _userManager;//創建用戶的 private SignInManager<ApplicationUser> _signInManager;//用來登錄的 //依賴注入 public AccountController(UserManager<ApplicationUser> userManager, SignInManager<ApplicationUser> signInManager) { _userManager = userManager; _signInManager = signInManager; } public IActionResult Register() { return View(); } [HttpPost] public async Task<IActionResult> Register(RegisterViewModel registerViewModel) { var identityUser = new ApplicationUser { Email = registerViewModel.Email, UserName = registerViewModel.Email, NormalizedUserName = registerViewModel.Email }; var identityResult=await _userManager.CreateAsync(identityUser, registerViewModel.Password); if (identityResult.Succeeded) { return RedirectToAction("Index", "Home"); } return View(); } public IActionResult Login() { return View(); } //登陸 public IActionResult MakeLogin() { var claims=new List<Claim>(){ new Claim(ClaimTypes.Name,"wyt"), new Claim(ClaimTypes.Role,"admin") }; var claimIdentity= new ClaimsIdentity(claims,CookieAuthenticationDefaults.AuthenticationScheme); HttpContext.SignInAsync(CookieAuthenticationDefaults.AuthenticationScheme,new ClaimsPrincipal(claimIdentity)); return Ok(); } //登出 public IActionResult Logout() { HttpContext.SignOutAsync(CookieAuthenticationDefaults.AuthenticationScheme); return Ok(); } } }
接下來我們重新生成一下,我們需要執行shell命令生成一下數據庫,只有添加 Microsoft.EntityFrameworkCore.Tools 才會生成成功,否則會報以下錯誤
執行命令總是提示 未找到與命令“dotnet-ef”匹配的可執行文件,根據網上的解決辦法引用 Microsoft.EntityFrameworkCore.Tools 問題依舊不能得到解決。
解決辦法:
右擊項目彈出菜單點擊編輯***.csprog,增加如下配置。
<ItemGroup> <DotNetCliToolReference Include="Microsoft.EntityFrameworkCore.Tools.DotNet" Version="2.0.0" /> </ItemGroup>
執行增加配置命令后
這時候Data文件夾下已經有新增的數據庫更新配置文件了
然后我們執行更新命令,執行成功后我們就可以看到數據庫表已經生成了
接下來我們運行一下網站進行注冊,注冊成功,已經存儲進數據庫
注冊實現
前面雖然可以注冊了,但是我們注冊完成后並沒有生成Cookies信息。所以我們要在Register方法中進行登陸生成Cookies
完整的注冊方法如下:

[HttpPost] public async Task<IActionResult> Register(RegisterViewModel registerViewModel) { var identityUser = new ApplicationUser { Email = registerViewModel.Email, UserName = registerViewModel.Email, NormalizedUserName = registerViewModel.Email }; var identityResult=await _userManager.CreateAsync(identityUser, registerViewModel.Password); if (identityResult.Succeeded) { //注冊完成登錄生成cookies信息 await _signInManager.SignInAsync(identityUser, new AuthenticationProperties { IsPersistent = true }); return RedirectToAction("Index", "Home"); } return View(); }
一般來說,如果用戶已經注冊或者登陸了,注冊和登陸按鈕是要隱藏的,所以我們接下來要修改_Layout.cshtml視圖頁面判斷注冊/登陸按鈕是否應該隱藏
完整的_Layout.cshtml代碼:

<!DOCTYPE html> <html> <head> <meta charset="utf-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <title>@ViewData["Title"] - MvcCookieAuthSample</title> <environment include="Development"> <link rel="stylesheet" href="~/lib/bootstrap/dist/css/bootstrap.css" /> <link rel="stylesheet" href="~/css/site.css" /> </environment> <environment exclude="Development"> <link rel="stylesheet" href="https://ajax.aspnetcdn.com/ajax/bootstrap/3.3.7/css/bootstrap.min.css" asp-fallback-href="~/lib/bootstrap/dist/css/bootstrap.min.css" asp-fallback-test-class="sr-only" asp-fallback-test-property="position" asp-fallback-test-value="absolute" /> <link rel="stylesheet" href="~/css/site.min.css" asp-append-version="true" /> </environment> </head> <body> <nav class="navbar navbar-inverse navbar-fixed-top"> <div class="container"> <div class="navbar-header"> <button type="button" class="navbar-toggle" data-toggle="collapse" data-target=".navbar-collapse"> <span class="sr-only">Toggle navigation</span> <span class="icon-bar"></span> <span class="icon-bar"></span> <span class="icon-bar"></span> </button> <a asp-area="" asp-controller="Home" asp-action="Index" class="navbar-brand">MvcCookieAuthSample</a> </div> <div class="navbar-collapse collapse"> <ul class="nav navbar-nav"> <li><a asp-area="" asp-controller="Home" asp-action="Index">Home</a></li> <li><a asp-area="" asp-controller="Home" asp-action="About">About</a></li> <li><a asp-area="" asp-controller="Home" asp-action="Contact">Contact</a></li> </ul> @if (User.Identity.IsAuthenticated) { <form asp-action="Logout" asp-controller="Account" method="post"> <ul class="nav navbar-nav navbar-right"> <li> <a title="Welcome" asp-controller="Admin" asp-action="Index">@User.Identity.Name</a> </li> <li> <button type="submit" class="btn btn-link navbar-btn navbar-link">Log out</button> </li> </ul> </form> } else { <ul class="nav navbar-nav navbar-right"> <li><a asp-area="" asp-controller="Account" asp-action="Register">Register</a></li> <li><a asp-area="" asp-controller="Account" asp-action="Login">Log in</a></li> </ul> } </div> </div> </nav> <div class="container body-content"> @RenderBody() <hr /> <footer> <p>© 2018 - MvcCookieAuthSample</p> </footer> </div> <environment include="Development"> <script src="~/lib/jquery/dist/jquery.js"></script> <script src="~/lib/bootstrap/dist/js/bootstrap.js"></script> <script src="~/js/site.js" asp-append-version="true"></script> </environment> <environment exclude="Development"> <script src="https://ajax.aspnetcdn.com/ajax/jquery/jquery-2.2.0.min.js" asp-fallback-src="~/lib/jquery/dist/jquery.min.js" asp-fallback-test="window.jQuery" crossorigin="anonymous" integrity="sha384-K+ctZQ+LL8q6tP7I94W+qzQsfRV2a+AfHIi9k8z8l9ggpc8X+Ytst4yBo/hH+8Fk"> </script> <script src="https://ajax.aspnetcdn.com/ajax/bootstrap/3.3.7/bootstrap.min.js" asp-fallback-src="~/lib/bootstrap/dist/js/bootstrap.min.js" asp-fallback-test="window.jQuery && window.jQuery.fn && window.jQuery.fn.modal" crossorigin="anonymous" integrity="sha384-Tc5IQib027qvyjSMfHjOMaLkfuWVxZxUPnCJA7l2mCWNIpG9mGCD8wGNIcPD7Txa"> </script> <script src="~/js/site.min.js" asp-append-version="true"></script> </environment> @RenderSection("Scripts", required: false) </body> </html>
這時候登陸的之后的導航欄信息就有了
登陸實現
我們接下來實現一下登陸邏輯,我們首先新建一個HttpPost的Login的Action
[HttpPost] public async Task<IActionResult> Login(RegisterViewModel loginViewModel) { var user= await _userManager.FindByEmailAsync(loginViewModel.Email); if (user==null) { //異常先不寫,后期統一收集 } //賬號密碼先不做驗證,需要可以自己寫 await _signInManager.SignInAsync(user, new AuthenticationProperties { IsPersistent = true }); return RedirectToAction("Index", "Home"); }
然后我們把原來的Logout也順便修改一下,不能是return OK();而要跳轉到首頁
//登出 public async Task<IActionResult> Logout() { //HttpContext.SignOutAsync(CookieAuthenticationDefaults.AuthenticationScheme); //return Ok(); await _signInManager.SignOutAsync(); return RedirectToAction("Index", "Home"); }
接下來我們修改一下Login.cshtml頁面

@{ ViewData["Title"] = "Login"; } @using MvcCookieAuthSample.ViewModels; @model RegisterViewModel; <div class="row"> <div class="col-md-4"> <section> <form method="post" asp-controller="Account" asp-action="Login"> <h4>Use a local account to log in.</h4> <hr /> <div class="form-group"> <label asp-for="Email"></label> <input asp-for="Email" class="form-control" /> </div> <div class="form-group"> <label asp-for="Password"></label> <input asp-for="Password" type="password" class="form-control" /> </div> <div class="form-group"> <button type="submit" class="btn btn-default">Log in</button> </div> </form> </section> </div> </div>
接下來我們可以運行一下登陸注冊,即可成功登陸后跳轉到首頁,注冊后跳轉倒是首頁