程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> .NET網頁編程 >> 關於.NET >> Asp.Net Core 項目實戰之權限管理系統(5) 用戶登錄,core權限管理系統

Asp.Net Core 項目實戰之權限管理系統(5) 用戶登錄,core權限管理系統

編輯:關於.NET

Asp.Net Core 項目實戰之權限管理系統(5) 用戶登錄,core權限管理系統


0 Asp.Net Core 項目實戰之權限管理系統(0) 無中生有

1 Asp.Net Core 項目實戰之權限管理系統(1) 使用AdminLTE搭建前端

2 Asp.Net Core 項目實戰之權限管理系統(2) 功能及實體設計

3 Asp.Net Core 項目實戰之權限管理系統(3) 通過EntityFramework Core使用PostgreSQL

4 Asp.Net Core 項目實戰之權限管理系統(4) 依賴注入、倉儲、服務的多項目分層實現

5 Asp.Net Core 項目實戰之權限管理系統(5) 用戶登錄

6 Asp.Net Core 項目實戰之權限管理系統(6) 功能管理

github源碼地址

0 TagHelper的使用

TagHelper是Asp.Net Core中提供的全新的服務端代碼參與創建和渲染 HTML 元素的方法,TagHelpers 在 Razor視圖中減少或避免了 HTML 和 C# 之間的顯示轉換,它具有以下特點:

  • 一種友好的Html開發體驗

   Razor 標記使用 Tag Helpers 看起來更像標准的 HTML。熟悉 HTML/CSS/JavaScript 的前端設計師在沒有學習 C# Razor 語法的情況下能夠編輯 Razor 。

  • 提供豐富的智能感知環境來創建 HTML和Razor標記

   通過Microsoft.AspNetCore.Razor.Tools提供智能感知和智能提醒,大大提高編碼效率。

  • 提供服務器端更強大,更可靠和可維護代碼的html渲染方式

   TagHelper的使用一般放在“視圖導入頁”中,視圖導入頁中還會放置我們會用到的服務端引用。

0.0 創建視圖導入頁

在Fonour.MVC項目中,右鍵Views文件夾,添加新項,選擇MVC視圖導入頁,添加一個默認名稱為 “_ViewImports.cshtml”的視圖導入頁。

@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers

0.1 使用Microsoft.AspNetCore.Razor.Tools

Microsoft.AspNetCore.Razor.Tools能夠提供TagHelper的智能感知提示和代碼加粗高亮顯示。

  • 通過NuGet程序包管理器安裝
  • 通過NuGet程序包控制台安裝     
  • 直接修改project.json

最終在project.json文件中的dependencies及tools配置節中會出現Microsoft.AspNetCore.Razor.Tools

"dependencies": {
  "Microsoft.NETCore.App": "1.0.1",
  "Microsoft.AspNetCore.Diagnostics": "1.0.0",
  "Microsoft.AspNetCore.Server.IISIntegration": "1.0.0",
  "Microsoft.AspNetCore.Server.Kestrel": "1.0.1",
  "Microsoft.Extensions.Logging.Console": "1.0.0",
  "Microsoft.AspNetCore.Mvc": "1.0.1",
  "Microsoft.AspNetCore.StaticFiles": "1.0.0",
  "Microsoft.Extensions.Configuration": "1.0.0",
  "Microsoft.Extensions.Configuration.FileExtensions": "1.0.0",
  "Microsoft.Extensions.Configuration.Json": "1.0.0",
  "Fonour.Application": "1.0.0-*",
  "Microsoft.AspNetCore.Razor.Tools": "1.0.0-preview2-final",
  "Microsoft.AspNetCore.Session": "1.0.0",
  "Fonour.Utility": "1.0.0-*"
},

"tools": {
  "Microsoft.AspNetCore.Server.IISIntegration.Tools": "1.0.0-preview2-final",
  "Microsoft.AspNetCore.Razor.Tools": "1.0.0-preview2-final"
},

打開Login/Index.cshtml文件,隨意輸入一個label標簽,發現已經可以出現asp-for的TagHelper提示。

public void ConfigureServices(IServiceCollection services) { //獲取數據庫連接字符串 var sqlConnectionString = Configuration.GetConnectionString("Default"); //添加數據上下文 services.AddDbContext<FonourDbContext>(options =>options.UseNpgsql(sqlConnectionString)); services.AddScoped<IUserRepository, UserRepository>(); services.AddScoped<IUserAppService, UserAppService>(); services.AddMvc(); //Session服務 services.AddSession(); }

2 修改Startup.cs文件的的Configure方法,請求管道中啟用Session

public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
{
    loggerFactory.AddConsole();

    if (env.IsDevelopment())
    {
        //開發環境異常處理
        app.UseDeveloperExceptionPage();
    }
    else
    {
        //生產環境異常處理
        app.UseExceptionHandler("/Shared/Error");
    }
    //使用靜態文件
    app.UseStaticFiles();
    //Session
    app.UseSession();
    //使用Mvc,設置默認路由為系統登錄
    app.UseMvc(routes =>
    {
        routes.MapRoute(
            name: "default",
            template: "{controller=Login}/{action=Index}/{id?}");
    });

    SeedData.Initialize(app.ApplicationServices); //初始化數據
}

1.1 Byte數組與對象轉換幫助類ByteConvertHelper

Asp.Net Core中Session的Set方法必須提供一個Byte[]數組來存放對象,此外為了方便使用,還提供了SetString和SetInt32擴展方法。

void Set(string key, byte[] value);

我們在Fonour.Utility項目中增加一個Byte數組與對象互相轉換的幫助類ByteConVertHelper。

public class ByteConvertHelper
{
    /// <summary>
    /// 將對象轉換為byte數組
    /// </summary>
    /// <param name="obj">被轉換對象</param>
    /// <returns>轉換後byte數組</returns>
    public static byte[] Object2Bytes(object obj)
    {
        string json = JsonConvert.SerializeObject(obj);
        byte[] serializedResult = System.Text.Encoding.UTF8.GetBytes(json);
        return serializedResult;
    }

    /// <summary>
    /// 將byte數組轉換成對象
    /// </summary>
    /// <param name="buff">被轉換byte數組</param>
    /// <returns>轉換完成後的對象</returns>
    public static object Bytes2Object(byte[] buff)
    {
        string json = System.Text.Encoding.UTF8.GetString(buff);
        return JsonConvert.DeserializeObject<object>(json);
    }

    /// <summary>
    /// 將byte數組轉換成對象
    /// </summary>
    /// <param name="buff">被轉換byte數組</param>
    /// <returns>轉換完成後的對象</returns>
    public static T Bytes2Object<T>(byte[] buff)
    {
        string json = System.Text.Encoding.UTF8.GetString(buff);
        return JsonConvert.DeserializeObject<T>(json);
    }
}

2 用戶登錄實現

有了以上准備工作,我們可以開始正式實現用戶登錄功能了。

2.0 Model

在Fonour.MVC項目中增加一個Models文件夾,用於存放前端交互使用的Model類,在Models文件夾下新建一個LoginModel類,並通過DataAnnotations特性指定屬性的驗證信息。

public class LoginModel
 {
     [Required(ErrorMessage = "用戶名不能為空。")]
     public string UserName { get; set; }

     [Required(ErrorMessage = "密碼不能為空。")]
     [DataType(DataType.Password)]
     public string Password { get; set; }

     public bool RememberMe { get; set; }
 }

在視圖導入頁_ViewImport.cshtml中增加對模型的引用

@using Fonour.MVC.Models

2.1 View

使用TagHelper修改Login/Index.cshtml為如下內容

@{
    Layout = null;
}
@model LoginModel
<!DOCTYPE html>
<html>
<head>
    <title>系統登錄</title>
    <!-- Tell the browser to be responsive to screen width -->
    <meta content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no" name="viewport">
    <link rel="stylesheet" href="~/lib/bootstrap/dist/css/bootstrap.css">
    <link rel="stylesheet" href="~/lib/font-awesome/css/font-awesome.css">
    <link rel="stylesheet" href="~/css/AdminLTE.css">
    <link rel="stylesheet" href="~/lib/iCheck/skins/square/blue.css">
</head>
<body class="hold-transition login-page">
    <div class="login-box">
        <div class="login-logo">
            <a href="http://fonour.cnblogs.com" target="_blank"><b>Fonour</b></a>
        </div>
        <!-- /.login-logo -->
        <div class="login-box-body">
            <p class="login-box-msg">權限管理系統</p>
            <div asp-validation-summary="All" class="text-danger"></div>
            <form asp-controller="Login" asp-action="Index" method="post">
                <div class="form-group has-feedback">
                    <input asp-for="UserName" type="text" class="form-control" placeholder="用戶名">
                    <span class="glyphicon glyphicon-user form-control-feedback"></span>
                    <span asp-validation-for="UserName" class="text-danger"></span>
                </div>
                <div class="form-group has-feedback">
                    <input asp-for="Password" type="password" class="form-control" placeholder="密碼">
                    <span class="glyphicon glyphicon-lock form-control-feedback"></span>
                </div>
                <div class="row">
                    <div class="col-xs-8">
                        <div class="checkbox icheck">
                            <label>
                                <input asp-for="RememberMe" type="checkbox"> 記住我
                            </label>
                        </div>
                    </div>
                    <!-- /.col -->
                    <div class="col-xs-4">
                        <button type="submit" class="btn btn-primary btn-block btn-flat">登錄</button>
                    </div>
                    <!-- /.col -->
                </div>
            </form>
        </div>
        <!-- /.login-box-body -->
    </div>
    <!-- /.login-box -->
    <script src="~/lib/jquery/dist/jquery.js"></script>
    <script src="~/lib/bootstrap/dist/js/bootstrap.js"></script>
    <script src="~/lib/iCheck/icheck.js"></script>
    <script>
        $(function () {
            $('input').iCheck({
                checkboxClass: 'icheckbox_square-blue',
                radioClass: 'iradio_square-blue',
                increaseArea: '20%' // optional
            });
        });
    </script>
</body>
</html>

關鍵說明

  • @model LoginModel  指定頁面綁定的模型為LoginModel。
  • asp-controller 指定form標簽提交時對應的控制器名稱。
  • asp-action 指定form標簽提交時對應的Action名稱。
  • asp-for 指定HTML元素綁定的模型對應的屬性名稱。
  • asp-validation-for 綁定對應模型屬性名稱,模型驗證失敗時,顯示模型定義的ErrorMessage。
  • asp-validation-summary="All" 顯示所有驗證失敗的錯誤信息。

2.2 Controller

修改LoginController,增加用戶登錄對應的控制器方法。

[HttpPost]
public IActionResult Index(LoginModel model)
{
    if (ModelState.IsValid)
    {
        //檢查用戶信息
         var user = _userAppService.CheckUser(model.UserName, model.Password);
        if (user != null)
        {
            //記錄Session
            HttpContext.Session.Set("CurrentUser", ByteConvertHelper.Object2Bytes(user));
            //跳轉到系統首頁
              return RedirectToAction("Index", "Home");
        }
        ModelState.AddModelError("", "用戶名或密碼錯誤。");
        return View();
    }
    return View(model);
}

到此我們基本上就完成了用戶登錄的邏輯,以及服務器端的登錄驗證。當輸入用戶名、密碼信息不符合條件時,會給出詳細的錯誤提示。

[HttpPost] public IActionResult Index(LoginModel model) { if (ModelState.IsValid) { //檢查用戶信息 var user = _userAppService.CheckUser(model.UserName, model.Password); if (user != null) { //記錄Session HttpContext.Session.Set("CurrentUser", ByteConvertHelper.Object2Bytes(user)); //跳轉到系統首頁 return RedirectToAction("Index", "Home"); } ViewBag.ErrorInfo = "用戶名或密碼錯誤。"; return View(); } ViewBag.ErrorInfo = ModelState.Values.First().Errors[0].ErrorMessage; return View(model); }

通過Bower程序包管理器添加對Layer的引用,在Login/Index.cshtml中增加對layer.js的引用

<script src="~/lib/layer/layer.js"></script>

增加一個隱藏的input標簽用於記錄錯誤信息。

<input id="errorInfo" type="hidden" value="@ViewBag.ErrorInfo" />

初始化完成後增加對錯誤信息的處理。

<script>
    $(function () {
        $('input').iCheck({
            checkboxClass: 'icheckbox_square-blue',
            radioClass: 'iradio_square-blue',
            increaseArea: '20%' // optional
        });
        //顯示服務端驗證的錯誤信息
         if ($("#errorInfo").val()) {
            layer.tips($("#errorInfo").val(), "#btnLogin");
        };
    });
</script>

此時運行程序,服務器端錯誤信息的展示樣式已經比較美觀了。

<script src="~/lib/jquery.cookie/src/jquery.cookie.js"></script>

增加form的onsubmit方法

<form asp-controller="Login" asp-action="Index" method="post" onsubmit="onSubmit()">
<script>
    $(function () {
        $('input').iCheck({
             checkboxClass: 'icheckbox_square-blue',
            radioClass: 'iradio_square-blue',
            increaseArea: '20%' // optional
        });
        
        //顯示服務端驗證的錯誤信息
        if ($("#errorInfo").val()) {
            layer.tips($("#errorInfo").val(), "#btnLogin");
        };

        //判斷之前是否有設置cookie,如果有,則設置【記住我】選擇框
        if ($.cookie("fonour_userName") != undefined) {
            $("#RememberMe").attr("checked", "checked");
        }
        else {
            $("#RememberMe").removeAttr("checked");
        }
        //讀取cookie
        if ($("#RememberMe:checked").length > 0) {
            $("#UserName").val($.cookie("fonour_userName"));
            $("#Password").val($.cookie("fonour_password"));
        }
    });
    //根據是否勾選記住我記錄或清除cookie
    function onSubmit() {
        if ($("#RememberMe:checked").length > 0) {//設置cookie
            $.cookie("fonour_userName", $("#UserName").val());
            $.cookie("fonour_password", $("#Password").val());
        } else {//清除cookie
            $.removeCookie("fonour_userName");
            $.removeCookie("fonour_password");
        }
    };
</script>

輸入用戶名密碼登陸後,再次回到登錄界面,會發現用戶名及密碼已經填充。

3 用戶是否登錄控制器攔截

一個最基本的控制器攔截,就是當我們直接通過在地址欄輸入訪問路由地址時,首先應該判斷用戶是否已經登錄,如果沒有登錄應該實現跳轉到登錄頁面。大致思路是通過重寫Controller的OnActionExecuting方法,在OnActionExecuting方法中判斷用戶是否登錄並實現跳轉。

3.1 新建控制器基類

在Fonour.MVC中右鍵Controllers文件夾,添加一個名稱為FonourControllerBase的控制器基類,內容如下。

public abstract class FonourControllerBase : Controller
{
    public override void OnActionExecuting(ActionExecutingContext filterContext)
    {
        byte[] result; 
        filterContext.HttpContext.Session.TryGetValue("CurrentUser",out result);
        if (result == null)
        {
            filterContext.Result = new RedirectResult("/Login/Index");
            return;
        }
        base.OnActionExecuting(filterContext);
    }
}

需要進行登陸驗證的控制器,修改為從FonourControllerBase繼承,這裡我們修改HomeController

public class HomeController : FonourControllerBase

啟動程序,在未登錄情況下,通過地址欄直接訪問/Home/Index,會發現已經自動跳轉到系統登錄界面。

4 總結

本次主要介紹了TagHelper的簡單實用;Asp.Net Core中的Session中間件的使用;以及系統登錄的服務端驗證,並對控制器的訪問進行了統一的是否登錄驗證攔截。下一節主要進行功能管理的實現。

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved