上篇:
上面我們把自定義認證和授權的相關的最小基礎類和要實現的接口都實現了,下面就是如何來進行認證和授權的配置。
首先我們要告訴系統,我們的用戶和角色類以及實現的接口,這樣系統在認證的時候就知道要調用哪些類和方法,其實就是注冊一下上面定義的幾個類而已,在Startup.cs文件的ConfigureServices方法添加如下代碼:
1 public void ConfigureServices(IServiceCollection services) 2 { 3 4 ... 5 6 services.AddIdentity<HDUser, HDRole>(); 7 services.AddSingleton<IUserStore<HDUser>, HDUserStore<HDUser>>(); 8 services.AddSingleton<IRoleStore<HDRole>, HDRoleStore<HDRole>>(); 9 ... 10 11 12 }
第6行,注冊我們定義的用戶和角色類。第7行和第8行注冊用戶和角色操作類。
那么這三行代碼有什么關系呢?
我們去看一下AddIdentity的源代碼,看看里面都干了什么活:
1 public static IdentityBuilder AddIdentity<TUser, TRole>( 2 this IServiceCollection services, 3 Action<IdentityOptions> setupAction) 4 where TUser : class 5 where TRole : class 6 { 7 // Services used by identity 8 services.AddOptions(); 9 services.AddAuthentication(options => 10 { 11 // This is the Default value for ExternalCookieAuthenticationScheme 12 options.SignInScheme = new IdentityCookieOptions().ExternalCookieAuthenticationScheme; 13 }); 14 15 // Identity services 16 services.TryAddSingleton<IdentityMarkerService>(); 17 services.TryAddScoped<IUserValidator<TUser>, UserValidator<TUser>>(); 18 services.TryAddScoped<IPasswordValidator<TUser>, PasswordValidator<TUser>>(); 19 services.TryAddScoped<IPasswordHasher<TUser>, PasswordHasher<TUser>>(); 20 services.TryAddScoped<ILookupNormalizer, UpperInvariantLookupNormalizer>(); 21 services.TryAddScoped<IRoleValidator<TRole>, RoleValidator<TRole>>(); 22 // No interface for the error describer so we can add errors without rev'ing the interface 23 services.TryAddScoped<IdentityErrorDescriber>(); 24 services.TryAddScoped<ISecurityStampValidator, SecurityStampValidator<TUser>>(); 25 services.TryAddScoped<IUserClaimsPrincipalFactory<TUser>, UserClaimsPrincipalFactory<TUser, TRole>>(); 26 services.TryAddScoped<UserManager<TUser>, UserManager<TUser>>(); 27 services.TryAddScoped<SignInManager<TUser>, SignInManager<TUser>>(); 28 services.TryAddScoped<RoleManager<TRole>, RoleManager<TRole>>(); 29 30 if (setupAction != null) 31 { 32 services.Configure(setupAction); 33 } 34 35 return new IdentityBuilder(typeof(TUser), typeof(TRole), services); 36 }
原來這貨把認證授權需要實現的接口都注冊了一遍,光看方法名字確實讓人很難想象。
那么后兩行是干什么的呢?看一下AddIdentity源代碼的26~28行,需要用到usermanger、signinmanager和rolemanager,這幾個類里面需要用到IUserStore和IRoleStore,這兩行就是注冊這兩個接口的實現的。
好了,上面是注冊的,那么光注冊還不行,還要啟用才行,咱們再看一下Configure方法,添加如下代碼:
1 public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerfactory) 2 { 3 ... 4 app.UseIdentity(); 5 ... 6 7 }
這樣就告訴系統要啟用認證這套機制了。
OK。到這里基礎工作都做完了。
是不是活都干完了?沒有啊,還沒有告訴我怎么登錄,怎么對網頁或方法應用角色權限啊,我們慢慢來。
我們再寫一個簡單的登錄和退出的管理類,假設叫AccountController吧,代碼如下:
1 [Route("account")] 2 public class AccountController : Controller 3 { 4 [FromServices] 5 public SignInManager<HDUser> SignInManager { get; set; } 6 7 8 [AllowAnonymous] 9 [HttpGet("login")] 10 public IActionResult Login(string returnUrl) 11 { 12 ViewBag.ReturnUrl = returnUrl; 13 return View(); 14 } 15 16 [HttpPost("login")] 17 [AllowAnonymous] 18 public async Task<IActionResult> Login(LoginViewModel model, string returnUrl) 19 { 20 if (ModelState.IsValid == true) 21 { 22 var result = await SignInManager.PasswordSignInAsync(model.UserName, model.Password, model.RememberMe, lockoutOnFailure: false); 23 if (result.Succeeded) 24 { 25 26 return RedirectToLocal(returnUrl); 27 } 28 29 ModelState.AddModelError("", "用戶名或密碼錯誤."); 30 return View(model); 31 } 32 return View(model); 33 } 34 35 [HttpPost] 36 [ValidateAntiForgeryToken] 37 public async Task<IActionResult> LogOff() 38 { 39 await SignInManager.SignOutAsync(); 40 return RedirectToAction(nameof(HomeController.Index), "Home"); 41 } 42 43 private IActionResult RedirectToLocal(string returnUrl) 44 { 45 if (Url.IsLocalUrl(returnUrl)) 46 { 47 return Redirect(returnUrl); 48 } 49 else 50 { 51 return RedirectToAction(nameof(HomeController.Index), "Home"); 52 } 53 } 54 55 }
這里面最重要的就是Login方法,它根據傳入的登錄信息,調用SignInManager.PasswordSignInAsync方法,就能完成登錄了。等等,這個SignInManager怎么來的?你咋可以直接用呢?看看上面的定義:
1 [FromServices] 2 public SignInManager<HDUser> SignInManager { get; set; }
有一個FromServices標記,原來這個是系統自動從服務里面取得的,還記得我們上面調用了一次AddIdentity嗎?它就把SignInManager注冊到服務里,然后就可以到處使用了,這個可以認為是asp.net5的非常重要的依賴注入機制,也是靈魂之一,如果不明白的,一定要好好看看哦。
好了,我們再看看LoginViewModel,這個也是比較重要的一個參數:
1 public class LoginViewModel 2 { 3 [Required] 4 [Display(Name = "User name")] 5 public string UserName { get; set; } 6 7 [Required] 8 [DataType(DataType.Password)] 9 [Display(Name = "Password")] 10 public string Password { get; set; } 11 12 [Display(Name = "Remember me?")] 13 public bool RememberMe { get; set; } 14 }
不過代碼很簡單,vs自動生成項目的時候,一般都這么生成登錄代碼。
有Controler了,是不是還要有View呢,當然要有,不過很簡單,就不貼出來了。
最后,我們看一下應用權限的類是什么樣的:
[Authorize] [Route("api/data")] public class DatasApiController : Controller { [HttpGet("daxialist")] [Authorize(Roles ="user")] public JsonResult GetDaxiaList() { ... return Json(...); } [HttpGet("daxiacount")] public JsonResult GetDaxiaCount() { return Json(...); } }
這里使用[Authorize]表示要對這個類的所有方法應用權限管理
[Authorize(Roles ="user")]表示這個方法只能角色為user的用戶可以訪問。
那個GetDaxiaCount方法,沒有應用角色,表示所有經過認證的用戶都可以訪問,不管角色是什么。
至此,我們最終完成了一個最簡單的基於asp.net5的認證授權。當然,這里可能連認證授權百分之一的功能都沒有體現出來,要想深入了解,還要花大量的時間去研究啊。