承接上篇,這里主要介紹如何實現cookie驗證登錄以及簡單的BaseRepository編寫。廢話不多說,下面進入主題。
一、cookie驗證登錄
1、startup的ConfigurationServices方法加上如下代碼:

同樣startup的Configure方法加上如下代碼:

2、繼承AuthorizeAttribute標簽並實現IAuthorizationFilter接口,代碼如下:
using Microsoft.AspNetCore.Authentication; using Microsoft.AspNetCore.Authentication.Cookies; 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 Ye.BoardMessage.WebApp.Models { /// <summary> /// 跳過檢查屬性 /// </summary> [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = false, Inherited = true)] public sealed class SkipUserAuthorizeAttribute : Attribute, IFilterMetadata { } [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, Inherited = true, AllowMultiple = true)] public class UserAuthorizeAttribute : AuthorizeAttribute, IAuthorizationFilter { public UserAuthorizeAttribute() { this.AuthenticationSchemes = CookieAuthenticationDefaults.AuthenticationScheme; } public virtual void OnAuthorization(AuthorizationFilterContext filterContext) { var authenticate = filterContext.HttpContext.AuthenticateAsync(CookieAuthenticationDefaults.AuthenticationScheme); if (authenticate.Result.Succeeded || this.SkipUserAuthorize(filterContext.ActionDescriptor)) { return; } HttpRequest httpRequest = filterContext.HttpContext.Request; string url = "/Account/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; } } }
3、驗證,代碼如下:
[HttpPost] [ValidateAntiForgeryToken] public async Task<IActionResult> Login(string email, string password) { password = MD5Encrypted(password); var serviceResponse = service.Login(email, password); if (!serviceResponse.IsSuccess) { return Content("用戶名或者密碼錯誤“); } var claims = new List<Claim> { new Claim(ClaimTypes.Name, serviceResponse.Result.Email), new Claim("FullName", serviceResponse.Result.FullName), new Claim(ClaimTypes.Role, "Administrator"), }; var claimsIdentity = new ClaimsIdentity( claims, CookieAuthenticationDefaults.AuthenticationScheme); await HttpContext.SignInAsync(CookieAuthenticationDefaults.AuthenticationScheme, new ClaimsPrincipal(claimsIdentity)); return LocalRedirect(Request.Query["ReturnUrl"].ToString() ?? "/"); }
4、退出,代碼如下:
[Models.UserAuthorize] [HttpGet] public async Task<IActionResult> Logout() { await HttpContext.SignOutAsync(CookieAuthenticationDefaults.AuthenticationScheme); return LocalRedirect("/Account/Login"); }
說明:以上代碼的實現參考了 《這個大神的博客》
二、BaseRepository實現
封裝了基本的增刪改查方法,可以與其他倉儲共用。此外,有個比較大的缺陷,沒有實現事務方面的UnitOfWork,對這個感興趣的看官可以自行實現,亦可以參考ABP的EF實現,這里有部分代碼也是參考ABP的實現的。好了,廢話不多說,上代碼:
接口:
using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.ChangeTracking; using System; using System.Collections.Generic; using System.Linq; using System.Linq.Expressions; using System.Text; using System.Threading.Tasks; namespace Ye.BoardMessage.Entity.IRepositories { public interface IBaseRepository<TEntity,TKey> where TEntity : class,new() { bool Insert(TEntity entity); Task<EntityEntry<TEntity>> InsertAsync(TEntity entity); TEntity Update(TEntity entity); Task<TEntity> UpdateAsync(TEntity entity); void Delete(TEntity entity); void Delete(IEnumerable<TEntity> entities); TEntity First(); Task<TEntity> FirstAsync(); TEntity First(Expression<Func<TEntity, bool>> where); Task<TEntity> FirstAsync(Expression<Func<TEntity, bool>> where); IQueryable<TEntity> Query(); IQueryable<TEntity> Query(Expression<Func<TEntity,bool>> where); DbContext DbContext { get; } int SaveChanged(); } }
實現:
using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.ChangeTracking; using System; using System.Collections.Generic; using System.Linq.Expressions; using System.Text; using System.Threading.Tasks; using Ye.BoardMessage.Entity.IRepositories; using System.Linq; namespace Ye.BoardMessage.Repository { public class BaseRepository<TEntity, TKey> : IBaseRepository<TEntity, TKey> where TEntity : class, new() { private DbContext _context; protected BaseRepository(DbContext context) { this._context = context; } public bool Insert(TEntity entity) { if (null == entity) return false; Table.Add(entity); return true; } public Task<EntityEntry<TEntity>> InsertAsync(TEntity entity) { return Table.AddAsync(entity); } public TEntity Update(TEntity entity) { AttachIfNot(entity); _context.Entry(entity).State = EntityState.Modified; return entity; } public Task<TEntity> UpdateAsync(TEntity entity) { return Task.FromResult(Update(entity)); } public void Delete(TEntity entity) { AttachIfNot(entity); Table.Remove(entity); } public void Delete(IEnumerable<TEntity> entities) { foreach (TEntity item in entities) Delete(item); } public TEntity First() { return Table.First(); } public Task<TEntity> FirstAsync() { return Table.FirstAsync(); } public TEntity First(Expression<Func<TEntity, bool>> where) { if (null == where) return null; return Table.First(where); } public Task<TEntity> FirstAsync(Expression<Func<TEntity, bool>> where) { if (null == where) return null; return Table.FirstAsync(where); } public DbContext DbContext => _context; public DbSet<TEntity> Table { get { return _context.Set<TEntity>(); } } public IQueryable<TEntity> Query() { return Table.AsQueryable<TEntity>(); } public IQueryable<TEntity> Query(Expression<Func<TEntity, bool>> where) { if (null != where) return Table.Where(where); else return Query(); } protected virtual void AttachIfNot(TEntity entity) { if (!Table.Local.Contains(entity)) { Table.Attach(entity); } } public int SaveChanged() { return _context.SaveChanges(); } } }
三、總結
EFCore的使用與EntityFramework並無多大區別;asp.net core 安全方面集成的東西很多,光是官方文檔就占據了上十個篇幅來介紹,在這方面還需要下苦工來研究,可謂 ”路漫漫其修遠兮“ 。這里稍微提下,前端模板是使用開源的前端模板《SB-admin》,一款bootstrap風格的模板。下面上幾個圖片看看效果。
1、登錄

2、首頁

3、列表頁面
至此,這個系列已經基本完畢,下篇將簡單介紹下如何安裝以及使用(網上參考資料太多,本人主要是整理下本人覺得有用的博文)。
