開發了一個公司內部系統,使用asp.net core 3.1。在開發用戶認證受權使用的是簡單的cookie認證方式,而後開發好了要寫幾個接口給其它系統調用數據。而且只是幾個簡單的接口不許備再從新部署一個站點,因此就直接在MVC的項目裏面加了一個API區域用來寫接口。這時候由於是接口因此就不能用cookie方式進行認證,得加一個jwt認證,採用多種身份驗證方案來進行認證受權。前端
身份驗證是肯定用戶身份的過程。 受權是肯定用戶是否有權訪問資源的過程。 在 ASP.NET Core 中,身份驗證由 IAuthenticationService 負責,而它供身份驗證中間件使用。 身份驗證服務會使用已註冊的身份驗證處理程序來完成與身份驗證相關的操做。json
認證-->受權
關於認證受權咱們要區分認證和受權是兩個概念,具體可查看MSDN官方文檔也能夠搜索其它文章看看,講的不少。其中包括OAuth 2.0 以及jwt的相關知識都有不少資料而且講解的很好。瀏覽器
身份驗證方案由 Startup.ConfigureServices 中的註冊身份驗證服務指定:
方式是在調用 services.AddAuthentication 後調用方案特定的擴展方法(例如 AddJwtBearer 或 AddCookie)。 這些擴展方法使用 AuthenticationBuilder.AddScheme 向適當的設置註冊方案。cookie
public void ConfigureServices(IServiceCollection services) { services.AddSession(); services.AddMvc(o => { o.Filters.Add(typeof(MyExceptionFilterAttribute));// 全局異常Filter }).AddRazorRuntimeCompilation(); //添加身份認證方案 var jwtConfig= Configuration.GetSection("Jwt").Get<JwtConfig>(); services.AddAuthentication (authoption =>{ //指定默認選項 authoption.DefaultChallengeScheme= CookieAuthenticationDefaults.AuthenticationScheme; authoption.DefaultAuthenticateScheme = CookieAuthenticationDefaults.AuthenticationScheme; authoption.DefaultSignOutScheme = CookieAuthenticationDefaults.AuthenticationScheme; authoption.DefaultSignInScheme= CookieAuthenticationDefaults.AuthenticationScheme; }) .AddCookie(CookieAuthenticationDefaults.AuthenticationScheme, option => { option.Cookie.Name = "adCookie";//設置存儲用戶登陸信息(用戶Token信息)的Cookie名稱 option.Cookie.HttpOnly = true;//設置存儲用戶登陸信息(用戶Token信息)的Cookie,沒法經過客戶端瀏覽器腳本(如JavaScript等)訪問到 option.ExpireTimeSpan = TimeSpan.FromDays(3);// 過時時間 option.SlidingExpiration = true;// 是否在過時時間過半的時候,自動延期 option.LoginPath = "/Account/Login"; option.LogoutPath = "/Account/LoginOut"; }) .AddJwtBearer(option => { option.TokenValidationParameters = new TokenValidationParameters { ValidIssuer = jwtConfig.Issuer, ValidAudience = jwtConfig.Audience, ValidateIssuer = true, ValidateLifetime = jwtConfig.ValidateLifetime, IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(jwtConfig.SigningKey)), //緩衝過時時間,總的有效時間等於這個時間加上jwt的過時時間 ClockSkew = TimeSpan.FromSeconds(0) }; }); }
JwtConfig
public class JwtConfig { /// <summary> /// 誰頒發的 /// </summary> public string Issuer { get; set; } /// <summary> /// 頒發給誰 /// </summary> public string Audience { get; set; } /// <summary> /// 令牌密碼 /// a secret that needs to be at least 16 characters long /// </summary> public string SigningKey { get; set; } /// <summary> /// 過時時間(分鐘) /// </summary> public int Expires { get; set; } /// <summary> /// 是否校驗過時時間 /// </summary> public bool ValidateLifetime { get; set; } }
"Jwt": { "Issuer": "issuer", "Audience": "audience", "SigningKey": "c0d32c63-z43d-4917-bbc2-5e726d087452", //過時時間(分鐘) "Expires": 10080, //是否驗證過時時間 "ValidateLifetime": true }
經過在應用的 IApplicationBuilder 上調用 UseAuthentication 擴展方法,在 Startup.Configure 中添加身份驗證中間件。 若是調用 UseAuthentication,會註冊使用以前註冊的身份驗證方案的中間節。 請在依賴於要進行身份驗證的用戶的全部中間件以前調用 UseAuthentication。 若是使用終結點路由,則必須按如下順序調用 UseAuthentication:
● 在 UseRouting以後調用,以便路由信息可用於身份驗證決策。
● 在 UseEndpoints 以前調用,以便用戶在通過身份驗證後才能訪問終結點。app
public void Configure(IApplicationBuilder app, IWebHostEnvironment env) { if (env.IsDevelopment()) { app.UseDeveloperExceptionPage(); } else { app.UseExceptionHandler("/Home/Error"); app.UseHsts(); } app.UseHttpsRedirection(); app.UseSession(); app.UseRouting(); //開啓認證中間件 app.UseAuthentication(); //開啓受權中間件 app.UseAuthorization(); app.UseEndpoints(endpoints => { endpoints.MapControllerRoute( name: "areas", pattern: "{area:exists}/{controller=Home}/{action=Index}/{id?}"); endpoints.MapControllerRoute( name: "default", pattern: "{controller=Home}/{action=Index}/{id?}"); }); }
[HttpPost] public async Task<NewtonsoftJsonResult> LoginIn(string userName, string userPassword, string code) { AjaxResult objAjaxResult = new AjaxResult(); var user = _userBll.GetUser(userName, userPassword); if (user == null) { objAjaxResult.Result = DoResult.NoAuthorization; objAjaxResult.PromptMsg = "用戶名或密碼錯誤"; } else { var claims = new List<Claim> { new Claim("userName", userName), new Claim("userID",user.Id.ToString()), }; await HttpContext.SignInAsync(new ClaimsPrincipal(new ClaimsIdentity(claims,CookieAuthenticationDefaults.AuthenticationScheme))); objAjaxResult.Result = DoResult.Success; objAjaxResult.PromptMsg = "登陸成功"; } return new NewtonsoftJsonResult(objAjaxResult); }
[HttpPost] public NewtonsoftJsonResult Token([FromBody] UserInfo model) { AjaxResult objAjaxResult = new AjaxResult(); var user = _userBll.GetUser(model.UserName, model.Password); if (user == null) { objAjaxResult.Result = DoResult.NoAuthorization; objAjaxResult.PromptMsg = "用戶名或密碼錯誤"; } else { //jwtTokenOptions 是經過配置獲取上面配置的參數信息 var jwtTokenOptions = BaseConfigModel.jwtConfig; var key = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(jwtTokenOptions.SigningKey)); var credentials = new SigningCredentials(key, SecurityAlgorithms.HmacSha256); //身份 var claims = new List<Claim> { new Claim("userID",user.Id.ToString()), new Claim("userName",user.UserName), }; //令牌 var expires = DateTime.Now.AddMinutes(jwtTokenOptions.Expires); var token = new JwtSecurityToken( issuer: jwtTokenOptions.Issuer, audience: jwtTokenOptions.Audience, claims: claims, notBefore: DateTime.Now, expires: expires, signingCredentials: credentials ); string jwtToken = new JwtSecurityTokenHandler().WriteToken(token); objAjaxResult.Result = DoResult.Success; objAjaxResult.RetValue = new { token = jwtToken }; objAjaxResult.PromptMsg = "登陸成功"; } return new NewtonsoftJsonResult(objAjaxResult); }
在受權時,應用指示要使用的處理程序。 選擇應用程序將經過以逗號分隔的身份驗證方案列表傳遞到來受權的處理程序 [Authorize] 。 [Authorize]屬性指定要使用的身份驗證方案或方案,無論是否配置了默認。asp.net
[Authorize(AuthenticationSchemes = JwtBearerDefaults.AuthenticationScheme)]
關於多種方案混合驗證受權的流程:
一、配置認證方案(相關的配置參數可採用配置文件形式)。
二、添加受權驗證中間件。
三、提供認證接口。
四、配置須要受權的接口受權方案。async