Asp.Net Core 2.0 項目實戰(10) 基於cookie登陸受權認證並實現前臺會員、後臺管理員同時登陸

Asp.Net Core 2.0 項目實戰(1) NCMVC開源下載了html

Asp.Net Core 2.0 項目實戰(2)NCMVC一個基於Net Core2.0搭建的角色權限管理開發框架前端

Asp.Net Core 2.0 項目實戰(3)NCMVC角色權限管理前端UI預覽及下載web

Asp.Net Core 2.0 項目實戰(4)ADO.NET操做數據庫封裝、 EF Core操做及實例數據庫

Asp.Net Core 2.0 項目實戰(5)Memcached踩坑,基於EnyimMemcachedCore整理MemcachedHelper幫助類。編程

Asp.Net Core 2.0 項目實戰(6)Redis配置、封裝幫助類RedisHelper及使用實例後端

Asp.Net Core 2.0 項目實戰(7)MD5加密、AES&DES對稱加解密緩存

Asp.Net Core 2.0 項目實戰(8)Core下緩存操做、序列化操做、JSON操做等Helper集合類cookie

Asp.Net Core 2.0 項目實戰(9) 日誌記錄,基於Nlog或Microsoft.Extensions.Logging的實現及調用實例session

Asp.Net Core 2.0 項目實戰(10) 基於cookie登陸受權認證並實現前臺會員、後臺管理員同時登陸mvc

Asp.Net Core 2.0 項目實戰(11) 基於OnActionExecuting全局過濾器,頁面操做權限過濾控制到按鈕級

1.登陸的實現

  登陸功能實現起來有哪些經常使用的方式,你們首先想到的確定是cookie或session或cookie+session,固然還有其餘模式,今天主要探討一下在Asp.net core 2.0下實現以cookie登陸受權,與net freamwork框架下經常使用的開發方式有所不一樣的是之前開發不論是webform仍是mvc模式,大多數開發者會封裝成第三方操做類,方便項目全局調用;在net core 2.0 下的登陸方式發生了點變化,大概流程是先經過依賴注入相關配置,再經過Action登陸受權,而後Authentication相關屬性認證,具體怎麼實現讓咱們一塊兒一步步操做一下。

2.Cookie開發回顧

  進行net core 2.0 cookie編程前,首先回顧一下原來作asp.net項目開發經常使用的操做cookie封裝的一些封裝。封裝好的cookiehelper類庫,能夠很方便的在項目中調用,如寫入cookie的時候直接調用CookieHelper.WriteCookie(名稱,值)這樣key/value形式寫入cookie,讀取cookie的時候直接使用CookieHelper.GetCookie(名稱)就能夠獲取到cookie值。

using System;
using System.Collections.Generic;
using System.Text;
using System.Text.RegularExpressions;
using System.IO;
using System.Net;
using System.Configuration;
using System.Web;
using System.Security.Cryptography;

namespace ZZ.Common
{
    public class CookieHelper
    {
/// <summary>
        /// 寫cookie值
        /// </summary>
        /// <param name="strName">名稱</param>
        /// <param name="strValue"></param>
        public static void WriteCookie(string strName, string strValue)
        {
            HttpCookie cookie = HttpContext.Current.Request.Cookies[strName];
            if (cookie == null)
            {
                cookie = new HttpCookie(strName);
            }
            cookie.Value = UrlEncode(strValue);
            HttpContext.Current.Response.AppendCookie(cookie);
        }

        /// <summary>
        /// 寫cookie值
        /// </summary>
        /// <param name="strName">名稱</param>
        /// <param name="strValue"></param>
        public static void WriteCookie(string strName, string key, string strValue)
        {
            HttpCookie cookie = HttpContext.Current.Request.Cookies[strName];
            if (cookie == null)
            {
                cookie = new HttpCookie(strName);
            }
            cookie[key] = UrlEncode(strValue);
            HttpContext.Current.Response.AppendCookie(cookie);
        }

        /// <summary>
        /// 寫cookie值
        /// </summary>
        /// <param name="strName">名稱</param>
        /// <param name="strValue"></param>
        public static void WriteCookie(string strName, string key, string strValue, int expires)
        {
            HttpCookie cookie = HttpContext.Current.Request.Cookies[strName];
            if (cookie == null)
            {
                cookie = new HttpCookie(strName);
            }
            cookie[key] = UrlEncode(strValue);
            cookie.Expires = DateTime.Now.AddMinutes(expires);
            HttpContext.Current.Response.AppendCookie(cookie);
        }

        /// <summary>
        /// 寫cookie值
        /// </summary>
        /// <param name="strName">名稱</param>
        /// <param name="strValue"></param>
        /// <param name="strValue">過時時間(分鐘)</param>
        public static void WriteCookie(string strName, string strValue, int expires)
        {
            HttpCookie cookie = HttpContext.Current.Request.Cookies[strName];
            if (cookie == null)
            {
                cookie = new HttpCookie(strName);
            }
            cookie.Value = UrlEncode(strValue);
            cookie.Expires = DateTime.Now.AddMinutes(expires);
            HttpContext.Current.Response.AppendCookie(cookie);
        }

        /// <summary>
        /// 讀cookie值
        /// </summary>
        /// <param name="strName">名稱</param>
        /// <returns>cookie值</returns>
        public static string GetCookie(string strName)
        {
            if (HttpContext.Current.Request.Cookies != null && HttpContext.Current.Request.Cookies[strName] != null)
                return UrlDecode(HttpContext.Current.Request.Cookies[strName].Value.ToString());
            return "";
        }

        /// <summary>
        /// 讀cookie值
        /// </summary>
        /// <param name="strName">名稱</param>
        /// <returns>cookie值</returns>
        public static string GetCookie(string strName, string key)
        {
            if (HttpContext.Current.Request.Cookies != null && HttpContext.Current.Request.Cookies[strName] != null && HttpContext.Current.Request.Cookies[strName][key] != null)
                return UrlDecode(HttpContext.Current.Request.Cookies[strName][key].ToString());

            return "";
        }
    }
}
CookieHelper

3.NET Core2.0 下Cookie的使用

  3.1添加Nuget相關依賴

  

  

  我這裏使用 Microsoft.AspNetCore.All大而全的,逐項引用這裏不作過多探討,適合本身的就是最好的。

  參照搜狐網上看到的一段話:

  Microsoft.AspNetCore.All包,它是一個元數據包,包含了大量的東西,其中包括:Authorization, Authentication, Identity, CORS, Localization, Logging, Razor, Kestrel 等,除了這些它還附加了 EntityFramework, SqlServer, Sqlite 等包。有些同窗可能會以爲這樣會引用了不少項目中使用不到的程序集,致使發佈後的程序變得很龐大,不過我要告訴你沒必要擔憂,發佈後的程序集不但不會變得很大,反而會小不少,由於 Microsoft 把全部的這些依賴所有都集成到了sdk中,也就是說當你安裝sdk的以後,MVC相關的包就已經安裝到了你的系統上。

3.2配置

  3.2.1首先在Startup.cs中ConfigureServices添加Cookie中間件,使用自定義Scheme

 
    //Cookie(1)添加 Cookie 服務
    services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme)
            //後臺管理員cookie服務
            .AddCookie(AdminAuthorizeAttribute.AdminAuthenticationScheme, options =>
            {
                options.LoginPath = "/admin/Login/Index";//登陸路徑
                options.LogoutPath = "/admin/Login/LogOff";//退出路徑
                options.AccessDeniedPath = new PathString("/Error/Forbidden");//拒絕訪問頁面
                options.Cookie.Path = "/";
            })
            //前臺用戶cookie服務
            .AddCookie(UserAuthorizeAttribute.UserAuthenticationScheme, options =>
            {
                options.LoginPath = "/Login/Index";
                options.LogoutPath = "/Login/LogOff";
                options.AccessDeniedPath = new PathString("/Error/Forbidden");//拒絕訪問頁面
                options.Cookie.Path = "/";
            });
在ConfigureServices方法中添加受權支持,並添加使用Cookie的方式,配置登陸頁面、登出頁面和沒有權限時的跳轉頁面。AdminAuthorizeAttribute、UserAuthorizeAttribute爲自定義AuthorizeAttribute類,兩個登陸方案,同時類中實現虛方法OnAuthorization過濾,若是系統中只有一個登陸受權所有使用默認便可。
      //Cookie(1)添加 Cookie 服務
      services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme)
//後臺管理員cookie服務 .AddCookie(CookieAuthenticationDefaults.AuthenticationScheme, options => { options.LoginPath = "/admin/Login/Index";//登陸路徑 options.LogoutPath = "/admin/Login/LogOff";//退出路徑 options.AccessDeniedPath = new PathString("/Error/Forbidden");//拒絕訪問頁面 options.Cookie.Path = "/"; });

 

  3.2.2在Configure使用Cookie中間件

public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)

{

            //Cookie(2)使用Cookie的中間件

            app.UseAuthentication();

}

  3.3[自定義AuthorizeAttribute]特性

    添加一個登陸方案(Scheme)

  CookieAuthenticationDefaults.AuthenticationScheme,這是系統已經定義好的一個默認的登陸方案,添加一個新的來實現一個不一樣的身份登陸。代碼以下:

using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Abstractions;
using Microsoft.AspNetCore.Mvc.Filters;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;

namespace NC.MVC
{
    /// <summary>
    /// 跳過檢查屬性
    /// </summary>
    [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = false, Inherited = true)]
    public sealed class SkipUserAuthorizeAttribute : Attribute, IFilterMetadata
    {
    }
    /// <summary>
    /// 前臺登陸驗證
    /// </summary>
    [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, Inherited = true, AllowMultiple = true)]
    public class UserAuthorizeAttribute : AuthorizeAttribute, IAuthorizationFilter
    {
        public const string UserAuthenticationScheme = "UserAuthenticationScheme";//自定義一個默認的登陸方案
        public UserAuthorizeAttribute()
        {
            this.AuthenticationSchemes = UserAuthenticationScheme;
        }
        public virtual void OnAuthorization(AuthorizationFilterContext filterContext)
        {
            //獲取對應Scheme方案的登陸用戶呢?使用HttpContext.AuthenticateAsync
            var authenticate = filterContext.HttpContext.AuthenticateAsync(UserAuthorizeAttribute.UserAuthenticationScheme);
            //authenticate.Wait();
            if (authenticate.Result.Succeeded || this.SkipUserAuthorize(filterContext.ActionDescriptor))
            {
                return;
            }
            //若是是默認Scheme可使用 
            //if (filterContext.HttpContext.User.Identity.IsAuthenticated || this.SkipUserAuthorize(filterContext.ActionDescriptor))
            //{
            //    return;
            //}

              HttpRequest httpRequest = filterContext.HttpContext.Request;
            string url = filterContext.HttpContext.Content("~/login");
                url = string.Concat(url, "?returnUrl=", httpRequest.Path);

                RedirectResult redirectResult = new RedirectResult(url);
                filterContext.Result = redirectResult;
                return;
        }

        protected virtual bool SkipUserAuthorize(ActionDescriptor actionDescriptor)
        {
            bool skipAuthorize = actionDescriptor.FilterDescriptors.Where(a => a.Filter is SkipUserAuthorizeAttribute).Any();
            if (skipAuthorize)
            {
                return true;
            }

            return false;
        }
    }
}

 

  這裏有一個點須要注意登陸多個用戶,filterContext.HttpContext.User.Identity這裏會默認AddAuthentication(Scheme)中的Scheme, 網上看到「若是你的Controller或者Action上有使用AuthorizeAttribute,那這個Attribute使用的登陸方案是哪一個,則這個HttpContext.User對應的就是那個方案的登陸用戶。若是沒有使用,則AddAuthentication()方法默認指它的方案(Scheme)所登陸的用戶,就是這個HttpContext.User」這裏跟我實際測試的有所不一樣,你們能夠多測試一下。

  因此獲取對應方案的登陸用戶,這裏用的是

    var authenticate = filterContext.HttpContext.AuthenticateAsync(UserAuthorizeAttribute.UserAuthenticationScheme);

    if (authenticate.Result.Succeeded){return;}

  若是您有更好的方案請留言告知!

3.4登陸受權實現

  配置文件中處理完成以後,接下來就是在登陸Action中實現登陸。添加一個Controller,如LoginController,再添加一個Action,如 Login,所配置的路由,要與上面的配置對應,否則跳轉登陸時會跳錯頁面。

  下面展現前臺會員登陸類:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Security.Claims;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Authentication.Cookies;
using Microsoft.AspNetCore.Mvc;

namespace NC.MVC.Controllers
{
    public class LoginController : Controller
    {
        public IActionResult Index()
        {
            return View();
        }
        /// <summary>
        /// 用戶登陸
        /// </summary>
        /// <param name="userName">用戶ID</param>
        /// <param name="passWord">用戶密碼</param>
        /// <param name="rememberMe">是否記住密碼</param>
        /// <returns></returns>
        [HttpPost]
        public IActionResult Login(string userName, string passWord, string rememberMe, string txtCode)
        {
            var user = new ClaimsPrincipal(
             new ClaimsIdentity(new[]
             {
                        new Claim("UserName","UserNameValue"),
                        new Claim("UserPwd","UserPwdValue"),
             }, UserAuthorizeAttribute.UserAuthenticationScheme)
            );
            HttpContext.SignInAsync(UserAuthorizeAttribute.UserAuthenticationScheme, user, new AuthenticationProperties
            {
                ExpiresUtc = DateTime.UtcNow.AddMinutes(60),// 有效時間
                //ExpiresUtc = DateTimeOffset.Now.Add(TimeSpan.FromDays(7)), // 有效時間
                IsPersistent = true,
                AllowRefresh = false
            });
            return new RedirectResult("~/Home/Index");//登陸成功
        }
    }
}

 


  這裏要注意的是HttpContext.SignInAsync(AuthenticationType,…) 所設置的Scheme必定要與前面的配置同樣,這樣對應的登陸受權纔會生效。

3.5認證驗證

  登陸完成後,進入須要受權才能進入的管理頁面,在作限制的Controller上加上[自定義AuthorizeAttribute]特性來作限制。這裏咱們自定義了兩個AuthorizeAttribute;UserAuthorizeAttribute和AdminAuthorizeAttribute,結合3.3的實現,咱們使用UserAuthorizeAttribute在Contoller或Action上加特性。這裏咱們先在HomeController上加上[UserAuthorize]

using Microsoft.AspNetCore.Mvc;
using System.Data;
using Microsoft.Extensions.Logging;
using Microsoft.AspNetCore.Authorization;

namespace NC.MVC.Controllers
{
    [UserAuthorize]
    public class HomeController : Controller
  {
        public IActionResult Index()
        {
           return View();
     }
  }
}

 

 

3.6退出登陸

  若是是多用戶登陸的系統,退出的時候須要指定方案退出。
public async Task Logout(string returnurl)
{
    await HttpContext.SignOutAsync(UserAuthorizeAttribute.UserAuthenticationScheme);
    return Redirect(returnurl ?? "~/");
}

 

4.總結

  以上就是我對net core 2.0 cookie受權登陸實際編程測試遇到的坑點以及編程過程當中用到的部分代碼,後端管理員登陸相關代碼以及AdminAuthorizeAttribute和前端會員UserAuthorizeAttribute代碼基本一致,這裏限於時間及篇幅不作過多處理,本身動手是學習技術最快的方式,沒有之一。

  在進行netcore2.0編程或者學習的時候,必定要拋卻固有的一些編程形式、思惟。新的事物總會對舊有規則,舊有思惟產生必定的衝擊,必定要學會適應,提醒你們同時警醒本身。Net core 開源跨平臺總的來講是屬因而良性的變化,變得更方便,更容易擴展,NET陣營須要咱們你們共同去努力。

  感謝ace chloe core開源、zkea cms core開源,在學習Asp.Net Core 2.0開發的時候網上資料相對較少,找了不少資料,有不少大牛的文章代碼對我幫助很大,寫博的時候不少創意、文章忘記出處,之後會留意。整理此篇備忘,但願對你有些許幫助。

相關文章
相關標籤/搜索