ASP.NET Identity Core入門 - 2

by vivid 24. 一月 2018 03:27

.NET Magazine國際中文電子雜誌
作 者:許薰尹
審 稿:張智凱
文章編號:
N180119101
出刊日期: 2018/1/24

在這篇文章中,將延續《ASP.NET Identity Core入門- 1》一文的情境,介紹如何在ASP.NET Core網站專案中,使用ASP.NET Core Identity設計會員系統,以完成會員註冊與會員登入的功能。

 

設計ViewModel模型

下一個步驟是在專案中新增「AccountViewModels」資料夾集中管理安控相關的ViewModel。從Visual Studio 2017開發工具 -「Solution Explorer」視窗 - 專案 - 「Models」資料夾上方按滑鼠右鍵,從快捷選單選擇「Add」- 「New Folder」選項,將新建立的資料夾命名為「AccountViewModels」。

新增「RegisterViewModel」類別,從「Solution Explorer」視窗 -「Models」-「AccountViewModels」資料夾上方,按滑鼠右鍵,從快捷選單選擇「Add」- 「Class」項目,從「Add New Item」對話盒中,選取「Code」分類下的「Class」項目,然後在下方將「Name」設定為「RegisterViewModel」,最後按下「Add」按鈕,請參考下圖所示:

clip_image002

圖 1:新增「RegisterViewModel」類別。

「RegisterViewModel」類別定義註冊網頁要顯示「Email」、「Password」、「ConfirmPassword」與「NickName」項目讓使用者輸入,參考以下範例程式碼:

using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Threading.Tasks;

namespace IdentityDemo.Models.AccountViewModels {
  public class RegisterViewModel {
    [Required]
    [EmailAddress]
    [Display( Name = "Email" )]
    public string Email { get; set; }

    [Required]
    [StringLength( 100 , ErrorMessage = "The {0} must be at least {2} and at max {1} characters long." , MinimumLength = 6 )]
    [DataType( DataType.Password )]
    [Display( Name = "Password" )]
    public string Password { get; set; }

    [DataType( DataType.Password )]
    [Display( Name = "Confirm password" )]
    [Compare( "Password" , ErrorMessage = "The password and confirmation password do not match." )]
    public string ConfirmPassword { get; set; }

    [Required]
    [StringLength( 100 , ErrorMessage = "The {0} must be at least {2} and at max {1} characters long." , MinimumLength = 6 )]
    [Display( Name = "Nick Name" )]
    public string NickName { get; set; }
  }
}

 

設計控制器

接下來的步驟要在專案中新增兩個控制器:「HomeController」與「AccountController」。

從Visual Studio 2017開發工具 -「Solution Explorer」視窗 - 專案名稱上方按滑鼠右鍵,從快捷選單選擇「Add」- 「New Folder」選項,將新建立的資料夾命名為「Controllers」。

從「Solution Explorer」視窗 - 「Controllers」資料夾上方,按滑鼠右鍵,從快捷選單選擇「Add」- 「New Scaffolded Item」或「Controllers」項目。在「Add Scaffold」對話盒中選取「MVC Controller - Empty」項目,然後按下「Add 」按鈕,請參考下圖所示:

clip_image004

圖 2:加入控制器。

在「Add Controller」對話盒中,設定控制器名稱為「HomeController」;然後按下「Add 」按鈕,請參考下圖所示:

clip_image006

圖 3:設定控制器名稱。

預設「HomeController」類別中會自動加入以下程式碼,其中包含一個「Index」方法,修改程式碼在類別上方套用「Authorize」Attribute:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Authorization;

namespace IdentityDemo.Controllers {
  [Authorize]
  public class HomeController : Controller {
    public IActionResult Index( ) {
      return View( );
    }
  }
}


 

建立「Index」檢視。將游標停留在控制器程式設計畫面「Index」方法之中,按滑鼠右鍵,從快捷選單選取「Add View」,請參考下圖所示。

clip_image008

圖 4:建立「Index」檢視。

在「Add View」對話盒中,設定:

  • View name:「Index」。
  • Template:「Empty (without model)」。
  • Model class:不設定。
  • 清除勾選所有核取方塊。

然後按下「Add」按鈕。Visual Studio 2017便會在「Views\Home」資料夾下,新增一個「Index.cshtml」檔案,請參考下圖所示:

clip_image010

圖 5:建立「Index」檢視。

改Index檢視的內容。從「Solution Explorer」視窗專案名稱下,雙擊「Views\Home\Index.cshtml」檔案,開啟設計畫面,在<body>下<div>標籤中,新增一個<h1>標籤,顯示「Home」字串:

@{
    Layout = null;
}

<!DOCTYPE html>

<html>
<head>
    <meta name = "viewport" content = "width=device-width" />
    <title> Index </title>
</head>
<body>
    <h1> Home </h1>

</body>
</html>


 

在「Views」資料夾內加入一個「_ViewImports.cshtml」檔案。從「Solution Explorer」視窗專案名稱下「Views」資料夾上方按滑鼠右鍵,從快捷選單選擇「Add」- 「New Item」選項,選取「Web」分類中的「MVC View Imports Page」,檔案名稱設定為「_ViewImports.cshtml」,然後按下「Add」按鈕新增檔案,請參考下圖所示:

clip_image012

圖 6:建立「_ViewImports.cshtml」檔案。

修改新建立的「_ViewImports.cshtml」檔案,在其中加入以下程式碼,引用命名空間,並註冊Tag Helper:

@using Microsoft.AspNetCore.Identity

@using IdentityDemo.Models

@using IdentityDemo.Models.AccountViewModels

@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers

 

設計註冊功能

AccountController負責管理使用者註冊以及登入登出功能,首先先完成註冊功能。從「Solution Explorer」視窗 - 「Controllers」資料夾上方,按滑鼠右鍵,從快捷選單選擇「Add」- 「New Scaffolded Item」或「Controllers」項目。在「Add Scaffold」對話盒中選取「MVC Controller - Empty」項目,然後按下「Add 」按鈕。在「Add Controller」對話盒中,設定控制器名稱為「AccountController」;然後按下「Add 」按鈕建立類別,接著加入以下程式碼,利用相依性插入(Dependency Injection)加入「UserManager<ApplicationUser>」與「SignInManager<ApplicationUser>」:

 

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;

using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Identity;
using IdentityDemo.Models;
using IdentityDemo.Models.AccountViewModels;

namespace IdentityDemo.Controllers {

  public class AccountController : Controller {
    private readonly UserManager<ApplicationUser> _userManager;
    private readonly SignInManager<ApplicationUser> _signInManager;
    public AccountController(
            UserManager<ApplicationUser> userManager ,
            SignInManager<ApplicationUser> signInManager ) {
      _userManager = userManager;
      _signInManager = signInManager;

    }

    [HttpGet]
    public IActionResult Register( ) {
      return View( );
    }

    [HttpPost]
    [ValidateAntiForgeryToken]
    public async Task<IActionResult> Register( RegisterViewModel model ) {

      if ( ModelState.IsValid ) {
        var user = new ApplicationUser {
          UserName = model.Email ,
          Email = model.Email ,
          NickName = model.NickName
        };
        var result = await _userManager.CreateAsync( user , model.Password );
        if ( result.Succeeded ) {
          await _signInManager.SignInAsync( user , isPersistent: false );
          return RedirectToAction( "Index" , "Home" );
        }

        foreach ( var error in result.Errors ) {
          ModelState.AddModelError( string.Empty , error.Description );
        }
      }
      return View( model );
    }
  }
}

「UserManager」管理使用者資訊;而「SignInManager」則負責登入與登出。「AccountController」類別的「Register」方法負責使用者註冊的邏輯。

建立「Register」檢視。將游標停留在「AccountController」控制器程式設計畫面「Register」方法之中,按滑鼠右鍵,從快捷選單選取「Add View」,請參考下圖所示:

clip_image014

圖 7:建立「Register」檢視。

在「Add View」對話盒中,設定:

  • View name:「Register」。
  • Template:「Create」。
  • Model class:設定為「RegisterViewModel」。
  • Data context class:不設定。
  • 清除勾選所有核取方塊。

然後按下「Add」按鈕。Visual Studio 2017便會在「Views\Account」資料夾下,新增一個「Register.cshtml」檔案,請參考下圖所示:

clip_image016

圖 8:建立「Register」檢視。

預設將產生以下Register檢視程式碼:

@model IdentityDemo.Models.AccountViewModels.RegisterViewModel

@{
    Layout = null;
}

<!DOCTYPE html>

<html>
<head>
    <meta name = "viewport" content = "width = device-width" />
    <title> Register </title>
</head>
<body>

<h4> RegisterViewModel </h4>
<hr />
<div class = "row">
    <div class = "col-md-4">
        <form asp-action = "Register">
            <div asp-validation-summary = "ModelOnly" class = "text-danger"> </div>
            <div class = "form-group">
                <label asp-for = "Email" class = "control-label"> </label>
                <input asp-for = "Email" class = "form-control" />
                <span asp-validation-for = "Email" class = "text-danger"> </span>
            </div>
            <div class = "form-group">
                <label asp-for = "Password" class = "control-label"> </label>
                <input asp-for = "Password" class = "form-control" />
                <span asp-validation-for = "Password" class = "text-danger"> </span>
            </div>
            <div class = "form-group">
                <label asp-for = "ConfirmPassword" class = "control-label"> </label>
                <input asp-for = "ConfirmPassword" class = "form-control" />
                <span asp-validation-for = "ConfirmPassword" class = "text-danger"> </span>
            </div>
            <div class = "form-group">
                <label asp-for = "NickName" class = "control-label"> </label>
                <input asp-for = "NickName" class = "form-control" />
                <span asp-validation-for = "NickName" class = "text-danger"> </span>
            </div>
            <div class = "form-group">
                <input type = "submit" value = "Create" class = "btn btn-default" />
            </div>
        </form>
    </div>
</div>

<div>
    <a asp-action = "Index">Back to List</a>
</div>

</body>
</html>

 

修改產生出來的Register檢視的內容。從「Solution Explorer」視窗專案名稱下,雙擊「Views\Account\Register.cshtml」檔案,開啟設計畫面,加入以下程式碼移除不必要的「Back to List」連結,並修改標題:

@model IdentityDemo.Models.AccountViewModels.RegisterViewModel
@{
  Layout = null;
}
<!DOCTYPE html>
<html>
<head>
    <meta name = "viewport" content = "width=device-width" />
    <title> Register </title>
</head>
<body>
    <h4> Register </h4>
    <hr />
    <div class = "row">
        <div class = "col-md-4">
            <form asp-action = "Register">
                <div asp-validation-summary = "ModelOnly" class = "text-danger"> </div>
                <div class = "form-group">
                    <label asp-for = "Email" class = "control-label"> </label>
                    <input asp-for = "Email" class = "form-control" />
                    <span asp-validation-for = "Email" class = "text-danger"> </span>
                </div>
                <div class = "form-group">
                    <label asp-for = "Password" class = "control-label"> </label>
                    <input asp-for = "Password" class = "form-control" />
                    <span asp-validation-for = "Password" class = "text-danger"> </span>
                </div>
                <div class = "form-group">
                    <label asp-for = "ConfirmPassword" class = "control-label"> </label>
                    <input asp-for = "ConfirmPassword" class = "form-control" />
                    <span asp-validation-for = "ConfirmPassword" class = "text-danger"> </span>
                </div>
                <div class = "form-group">
                    <label asp-for = "NickName" class = "control-label"> </label>
                    <input asp-for = "NickName" class = "form-control" />
                    <span asp-validation-for = "NickName" class = "text-danger"> </span>
                </div>
                <div class = "form-group">
                    <input type = "submit" value = "Register" class = "btn btn-default" />
                </div>
            </form>
        </div>
    </div>
</body>
</html>

 

選取Visual Studio開發工具「Build」-「Build Solution」項目編譯目前的專案,確認程式碼能正確編譯。接著按CTRL+F5執行網站首頁(請注意:埠號可能會依據實際上的操作而有所不同,請修改為實際的埠號),然後在瀏覽器輸入以下URL:

http://localhost:1880/account/register

執行結果參考如下:

clip_image018

圖 9:執行註冊。

試著註冊一個新使用者,然後按下「Register」按鈕,請參考下圖所示:

clip_image020

圖 10:輸入資料。

註冊成功將導向首頁畫面,請參考下圖所示:

clip_image022

圖 11:註冊成功將導向首頁。

檢查資料庫結構描述資訊。展開「Server Explorer」視窗-「Data Connections」-「IdentityDemo資料庫」-「Tables」- 「AspNetUsers」資料表,在「AspNetUsers」資料表上按滑鼠右鍵,從快捷選單中選取「Show Table Data」顯示資料表所有資料,請參考下圖所示:

clip_image024

圖 12:檢查資料庫結構描述資訊。

設計登入功能

接下來說明登入功能的設計。從「Solution Explorer」視窗 -「Models」-「AccountViewModels」資料夾上方,按滑鼠右鍵,從快捷選單選擇「Add」- 「Class」項目,從「Add New Item」對話盒中,選取「Code」分類下的「Class」項目,然後在下方將「Name」設定為「LoginViewModel」最後按下「Add」按鈕,請參考下圖所示:

clip_image026

圖 13:加入「LoginViewModel」類別。


在「LoginViewModel」類別中加入以下程式碼:

using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Threading.Tasks;

namespace IdentityDemo.Models.AccountViewModels {
  public class LoginViewModel {
    [Required]
    [EmailAddress]
    public string Email { get; set; }

    [Required]
    [DataType( DataType.Password )]
    public string Password { get; set; }
  }
}


修改「AccountController」類別,加入「Login」方法程式碼,叫用SignInManager<ApplicationUser>的「PasswordSignInAsync」方法驗證使用者帳號與密碼是否與資料庫中的相符,若輸入正確的帳號與密碼將被導首頁:

[HttpGet]
public IActionResult Login( ) {
  return View( );
}

[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Login( LoginViewModel model ) {
  var result = await _signInManager.PasswordSignInAsync( model.Email , model.Password , false , false );
  if ( result.Succeeded ) {
    return RedirectToAction( "Index" , "Home" );
  } else {
    ModelState.AddModelError( string.Empty , "Invalid login attempt." );
    return View( model );
  }
}


 

建立「Login」檢視。將游標停留在控制器程式設計畫面「Login」方法之中,按滑鼠右鍵,從快捷選單選取「Add View」,請參考下圖所示:

clip_image028

圖 14:建立「Login」檢視。

在「Add View」對話盒中,設定:

  • View name:「Login」。
  • Template:「Create)」。
  • Model class:設定「LoginViewModel」。
  • Data context class:不設定。
  • 清除勾選所有核取方塊。

然後按下「Add」按鈕。Visual Studio 2017便會在「Views\Account」資料夾下,新增一個「Login.cshtml」檔案,請參考下圖所示:

clip_image030

圖 15:建立「Login」檢視。

修改「Login」檢視的內容。從「Solution Explorer」視窗專案名稱下,雙擊「Views\Account\Login.cshtml」檔案,開啟設計畫面,加入以下程式碼:

 

@model IdentityDemo.Models.AccountViewModels.LoginViewModel
@inject SignInManager<ApplicationUser> SignInManager

@{
  Layout = null;
}
<!DOCTYPE html>
<html>
<head>
    <meta name = "viewport" content = "width=device-width" />
    <title> Login </title>
</head>
<body>
    <h4> Login </h4>
    <hr />
    <div class = "row">
        <div class = "col-md-4">
            <form asp-action = "Login">
                <div asp-validation-summary = "ModelOnly" class = "text-danger"> </div>
                <div class = "form-group">
                    <label asp-for = "Email" class = "control-label"> </label>
                    <input asp-for = "Email" class = "form-control" />
                    <span asp-validation-for = "Email" class = "text-danger"> </span>
                </div>
                <div class = "form-group">
                    <label asp-for = "Password" class = "control-label"> </label>
                    <input asp-for = "Password" class = "form-control" />
                    <span asp-validation-for = "Password" class = "text-danger"> </span>
                </div>
                <div class = "form-group">
                    <input type = "submit" value = "Login" class = "btn btn-default" />
                </div>
            </form>
        </div>
    </div>
</body>
</html>

 

最後我們希望使用者登入之後,首頁會顯示歡迎使用者的訊息。修改「HomeController」類別程式碼,類別上方套用「Authorize」Attribute,表示需登入才可以存取首頁:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Http;
using IdentityDemo.Models;

namespace IdentityDemo.Controllers {
  [Authorize]
  public class HomeController : Controller {
    private readonly UserManager<ApplicationUser> _userManager;
    private readonly IHttpContextAccessor _context;
    public HomeController( UserManager<ApplicationUser> userManager , IHttpContextAccessor context ) {
      _userManager = userManager;
      _context = context;
    }
    public async Task<IActionResult> Index( ) {
      var user = await _userManager.GetUserAsync( _context.HttpContext.User );
      ViewBag.NickName = user.NickName;

      return View( );
    }
  }
}


修改首頁「Index」檢視的內容。從「Solution Explorer」視窗專案名稱下,雙擊「Views\Home\ Index.cshtml」檔案,開啟設計畫面,加入以下程式碼:

 

@{
  Layout = null;
}
<!DOCTYPE html>
<html>
<head>
    <meta name = "viewport" content = "width=device-width" />
    <title> Index </title>
</head>
<body>
    <h1> Home </h1>
    <p>Hello , @ViewBag.NickName  [@User.Identity.Name]</p>
</body>
</html>

選取Visual Studio 開發工具「Build」-「Build Solution」項目編譯目前的專案,確認程式碼能正確編譯。按CTRL+F5執行網站首頁(請注意:埠號可能會依據實際上的操作而有所不同,請修改為實際的埠號),執行結果參考如下,會自動導向登入畫面:

clip_image032

圖 16:登入測試。

登入網站之後,首頁將顯示使用者NickName與電子郵件資訊,請參考下圖所示:

clip_image034

圖 17:登入網站顯示使用者NickName與電子郵件。

設計登出功能

修改「AccountController」類別,在「Login」方法下方,加入以下「Logout」方法程式碼,利用SignInManager的「SignOutAsync」方法登出,登出後將被導向登入畫面:

[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Logout( ) {
  await _signInManager.SignOutAsync( );
  return RedirectToAction( nameof( AccountController.Login ) , "Account" );
}

 

除了使用「User.Identity.Name」程式來取得登入帳號資訊之外,也可以利用「UserManager」的「GetUserName」方法,修改「Views\Home\Index」檢視程式如下:

@inject UserManager<ApplicationUser> UserManager

@{
  Layout  =  null;
}
<!DOCTYPE html>
<html>
<head>
    <meta name = "viewport" content = "width=device-width" />
    <title> Index </title>
</head>
<body>
    <h1> Home </h1>
    <p>Hello , @ViewBag.NickName  [@UserManager.GetUserName( User )]</p>

    <form asp-area = "" asp-controller = "Account" asp-action = "Logout" method = "post" id = "logoutForm">
        <button type = "submit"> Log out </button>
    </form>
</body>
</html>

 

選取Visual Studio 開發工具「Build」-「Build Solution」項目編譯目前的專案,確認程式碼能正確編譯。按CTRL+F5執行網站首頁,然後登入網站,執行結果參考如下:

clip_image036

圖 18:登入顯示歡迎資訊。

按下「Log out」按鈕登出後,將回到Login畫面,請參考下圖所示:

clip_image038

圖 19:登出將回到登入畫面。

Tags:

.NET Magazine國際中文電子雜誌 | ASP.NET Core MVC | C# | 許薰尹Vivid Hsu

新增評論




  Country flag
biuquote
  • 評論
  • 線上預覽
Loading






NET Magazine國際中文電子雜誌

NET Magazine國際中文電子版雜誌,由恆逸資訊創立於2000,自發刊日起迄今已發行超過500篇.NET相關技術文章,擁有超過40000名註冊讀者群。NET Magazine國際中文電子版雜誌希望藉於電子雜誌與NET Developer達到共同學習與技術新知分享,歡迎每一位對.NET 技術有興趣的朋友們多多支持本雜誌,讓作者群們可以有持續性的動力繼續爬文。<請加入免費訂閱>

月分類Month List