一、簡介
在.net core 中Filter分為以下六大類:
1、AuthorizeAttribute(許可權驗證)
2、IResourceFilter(資源快取)
3、IActionFilter(執行方法前後的記錄)
4、IResultFilter(結果生成前後擴充套件)
5、IAlwaysRun(響應結果的補充)
6、IExceptionFilter(異常處理)
二、AuthorizeAttribute(許可權驗證)
認證授權分為三種,如下:
1、基於角色授權
1.1、配置Startup.cs 類,使用Cookie及角色授權方式訪問 —— 修改 ConfigureServices 與 Configure方法
public void ConfigureServices(IServiceCollection services) { services.AddControllersWithViews(); { // ************1、新增鑑權和授權邏輯************************** services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme).AddCookie(options => { options.LoginPath = new PathString("/Login/LoginView"); // 登入地址 options.AccessDeniedPath = new PathString("/Login/AccessDenied"); // 無許可權訪問需要跳轉的頁面地址 options.LogoutPath = new PathString("/Login/LoginOff"); // 登出地址 options.ExpireTimeSpan = TimeSpan.FromMinutes(1); // cookie有效時間(這裡設定的1分鐘有效時間) options.Cookie = new CookieBuilder { // cookie名稱,Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT")取得是當前環境變數的名稱,使用者可自定義 Name = $"WebUI_{Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT")}" }; }); services.AddAuthorization(); // ********************************************************** } } // This method gets called by the runtime. Use this method to configure the HTTP request pipeline. public void Configure(IApplicationBuilder app, IWebHostEnvironment env, ILoggerFactory loggerFactory) { if (env.IsDevelopment()) { app.UseDeveloperExceptionPage(); } else { app.UseExceptionHandler("/Home/Error"); } app.UseStaticFiles(); app.UseRouting(); // ***************2、鑑權******************* app.UseAuthentication(); // 授權 app.UseAuthorization(); app.UseEndpoints(endpoints => { endpoints.MapControllerRoute( name: "default", pattern: "{controller=Login}/{action=LoginView}/{id?}"); }); }
1.2、使用授權的時候在Action或controller上打上Authorize特性並賦值Role屬性,表示該方法只能由Admin的角色訪問
public class LoginController : Controller { // 登入頁面 public IActionResult LoginView() { return View(); } /// <summary> /// 登入方法 /// </summary> /// <returns></returns> [AllowAnonymous] public async Task<IActionResult> Login() { var claims = new List<Claim> { new Claim(ClaimTypes.Name,"xiaohemiao"), new Claim(ClaimTypes.Role,"Admin") }; var claimsIdentity = new ClaimsIdentity(claims, CookieAuthenticationDefaults.AuthenticationScheme); await HttpContext.SignInAsync(CookieAuthenticationDefaults.AuthenticationScheme , new ClaimsPrincipal(claimsIdentity) , new AuthenticationProperties() { ExpiresUtc = DateTime.UtcNow.AddMinutes(1) }); return Redirect("/Login/Index"); } /// <summary> /// 登入成功之後跳轉的頁面 /// </summary> /// <returns></returns> [Authorize(Roles = "Admin")] public IActionResult Index() { return View(); } /// <summary> /// 登出 /// </summary> /// <returns></returns> public async Task<IActionResult> LoginOff() { await HttpContext.SignOutAsync(); return Redirect("/Login/LoginView"); } /// <summary> /// 無許可權頁面 /// </summary> /// <returns></returns> public IActionResult AccessDenied() { return View(); } }
2、基於宣告授權
修改基於標題1的相關程式碼
public void ConfigureServices(IServiceCollection services) { services.AddControllersWithViews(); { // ************1、新增鑑權和授權邏輯************************** services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme).AddCookie(options => { options.LoginPath = new PathString("/Login/LoginView"); // 登入地址 options.AccessDeniedPath = new PathString("/Login/AccessDenied"); // 無許可權訪問需要跳轉的頁面地址 options.LogoutPath = new PathString("/Login/LoginOff"); // 登出地址 options.ExpireTimeSpan = TimeSpan.FromMinutes(1); // cookie有效時間(這裡設定的1分鐘有效時間) options.Cookie = new CookieBuilder { // cookie名稱,Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT")取得是當前環境變數的名稱,使用者可自定義 Name = $"WebUI_{Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT")}" }; }); services.AddAuthorization(options => { // 當角色是Admin和SuperAdministrator才可以訪問 options.AddPolicy("AdministratorOnly", policy => policy.RequireClaim(ClaimTypes.Role, "Admin", "SuperAdministrator")); }); // ********************************************************** } } // This method gets called by the runtime. Use this method to configure the HTTP request pipeline. public void Configure(IApplicationBuilder app, IWebHostEnvironment env, ILoggerFactory loggerFactory) { if (env.IsDevelopment()) { app.UseDeveloperExceptionPage(); } else { app.UseExceptionHandler("/Home/Error"); } app.UseStaticFiles(); app.UseRouting(); // ***************2、鑑權******************* app.UseAuthentication(); // 授權 app.UseAuthorization(); app.UseEndpoints(endpoints => { endpoints.MapControllerRoute( name: "default", pattern: "{controller=Login}/{action=LoginView}/{id?}"); }); }
public class LoginController : Controller { // 登入頁面 public IActionResult LoginView() { return View(); } /// <summary> /// 登入方法 /// </summary> /// <returns></returns> [AllowAnonymous] public async Task<IActionResult> Login() { var claims = new List<Claim> { new Claim(ClaimTypes.Name,"xiaohemiao"), new Claim(ClaimTypes.Role,"Admin") }; var claimsIdentity = new ClaimsIdentity(claims, CookieAuthenticationDefaults.AuthenticationScheme); await HttpContext.SignInAsync(CookieAuthenticationDefaults.AuthenticationScheme , new ClaimsPrincipal(claimsIdentity) , new AuthenticationProperties() { ExpiresUtc = DateTime.UtcNow.AddMinutes(1) }); return Redirect("/Login/Index"); } /// <summary> /// 登入成功之後跳轉的頁面 /// </summary> /// <returns></returns> [Authorize(Policy = "AdministratorOnly")] public IActionResult Index() { return View(); } /// <summary> /// 登出 /// </summary> /// <returns></returns> public async Task<IActionResult> LoginOff() { await HttpContext.SignOutAsync(); return Redirect("/Login/LoginView"); } /// <summary> /// 無許可權頁面 /// </summary> /// <returns></returns> public IActionResult AccessDenied() { return View(); } }
3、自定義策略授權
3.1、定義許可權策略
public class PermissionRequirement: IAuthorizationRequirement { }
3.2、再定義個策略處理類
public class RoleAuthorizationHandler : AuthorizationHandler<PermissionRequirement> { private readonly ILogger<RoleAuthorizationHandler> _logger; private readonly IHttpContextAccessor _httpContextAccessor; public RoleAuthorizationHandler(ILogger<RoleAuthorizationHandler> logger, IHttpContextAccessor httpContextAccessor) { _logger = logger; this._httpContextAccessor = httpContextAccessor; } public override Task HandleAsync(AuthorizationHandlerContext context) { var mvcContext = _httpContextAccessor.HttpContext; var user = context.User.FindFirst(ClaimTypes.Role)?.Value; if (mvcContext.User.Identity.IsAuthenticated) { var routes = mvcContext.GetRouteData(); var controller = routes.Values["controller"]?.ToString()?.ToLower(); var action = routes.Values["action"]?.ToString()?.ToLower(); var activeTime = mvcContext.User.FindFirst(ClaimTypes.Expired); // 是否登入超時 if (activeTime == null || Convert.ToDateTime(activeTime.Value) < DateTime.Now) { // 登入超時自動跳轉到登入頁面 mvcContext.Response.Redirect("/Login/LoginView"); context.Succeed(context.Requirements.FirstOrDefault()); return Task.CompletedTask; } var hasRole = mvcContext.User.HasClaim(c => c.Type == ClaimTypes.Role); if (!hasRole) { //使用者未在系統新增,即使登入成功,也要提示沒有許可權 context.Fail(); return Task.CompletedTask; } var menuPaths = AuthorizationMenuPath(user); string route = $"/{controller}"; var actionRoute = $"/{controller}/{(routes.Values["action"] ?? "Index")}".ToLower(); if (menuPaths.Any(m => m.ToLower().Contains($"/{controller}/")) || menuPaths.Any(m => m.ToLower() == route) || menuPaths.Any(m => m.ToLower() == actionRoute)) context.Succeed(context.Requirements.FirstOrDefault()); else context.Fail();//會預設跳轉 accessdenied檢視 } else context.Fail(); return Task.CompletedTask; } protected override Task HandleRequirementAsync(AuthorizationHandlerContext context, PermissionRequirement requirement) { throw new NotImplementedException(); } /// <summary> /// 許可權動態快取類 臨時替代資料庫 /// </summary> /// <param name="roleName">角色名稱</param> /// <returns></returns> private List<string> AuthorizationMenuPath(string roleName) { switch (roleName) { case "Admin": return new List<string>() { "/Login/Index" }; default: return new List<string>() { "/Login/Index" }; } } }
3.3、修改 ConfigureServices 與 Configure方法
public void ConfigureServices(IServiceCollection services) { services.AddControllersWithViews(); { // ************3、注入自定義策略************************** services.AddSingleton<IAuthorizationHandler, RoleAuthorizationHandler>(); // ************1、新增鑑權和授權邏輯************************** services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme).AddCookie(options => { options.LoginPath = new PathString("/Login/LoginView"); // 登入地址 options.AccessDeniedPath = new PathString("/Login/AccessDenied"); // 無許可權訪問需要跳轉的頁面地址 options.LogoutPath = new PathString("/Login/LoginOff"); // 登出地址 options.ExpireTimeSpan = TimeSpan.FromMinutes(1); // cookie有效時間(這裡設定的1分鐘有效時間) options.Cookie = new CookieBuilder { // cookie名稱,Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT")取得是當前環境變數的名稱,使用者可自定義 Name = $"WebUI_{Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT")}" }; }); services.AddAuthorization(options => { options.AddPolicy("RolePolicy", policy =>policy.Requirements.Add(new PermissionRequirement())); }); services.AddHttpContextAccessor(); // ********************************************************** } } // This method gets called by the runtime. Use this method to configure the HTTP request pipeline. public void Configure(IApplicationBuilder app, IWebHostEnvironment env, ILoggerFactory loggerFactory) { if (env.IsDevelopment()) { app.UseDeveloperExceptionPage(); } else { app.UseExceptionHandler("/Home/Error"); } app.UseStaticFiles(); app.UseRouting(); // ***************2、鑑權******************* app.UseAuthentication(); // 授權 app.UseAuthorization(); app.UseEndpoints(endpoints => { endpoints.MapControllerRoute( name: "default", pattern: "{controller=Login}/{action=LoginView}/{id?}"); }); }
3.4 、controller程式碼邏輯
public class LoginController : Controller { // 登入頁面 public IActionResult LoginView() { return View(); } /// <summary> /// 登入方法 /// </summary> /// <returns></returns> [AllowAnonymous] public async Task<IActionResult> Login() { var claims = new List<Claim> { new Claim(ClaimTypes.Name,"xiaohemiao"), new Claim(ClaimTypes.Role,"Admin"), new Claim(ClaimTypes.Expired,DateTime.Now.AddMinutes(1).ToString("yyyy-MM-dd HH:mm:ss")) }; var claimsIdentity = new ClaimsIdentity(claims, CookieAuthenticationDefaults.AuthenticationScheme); await HttpContext.SignInAsync(CookieAuthenticationDefaults.AuthenticationScheme , new ClaimsPrincipal(claimsIdentity) , new AuthenticationProperties() { }); return Redirect("/Login/Index"); } /// <summary> /// 登入成功之後跳轉的頁面 /// </summary> /// <returns></returns> [Authorize(Policy = "RolePolicy")] public IActionResult Index() { return View(); } /// <summary> /// 登出 /// </summary> /// <returns></returns> public async Task<IActionResult> LoginOff() { await HttpContext.SignOutAsync(); return Redirect("/Login/LoginView"); } /// <summary> /// 無許可權頁面 /// </summary> /// <returns></returns> public IActionResult AccessDenied() { return View(); } }
三、簡單頁面呈現效果
1、登入頁面
2、登入成功跳轉的頁面
3、無許可權頁面