asp.net core3.1cookie和jwt混合認(rèn)證授權(quán)實(shí)現(xiàn)多種身份驗(yàn)證方案
開(kāi)發(fā)了一個(gè)公司內(nèi)部系統(tǒng),使用asp.net core 3.1。在開(kāi)發(fā)用戶認(rèn)證授權(quán)使用的是簡(jiǎn)單的cookie認(rèn)證方式,然后開(kāi)發(fā)好了要寫幾個(gè)接口給其它系統(tǒng)調(diào)用數(shù)據(jù)。并且只是幾個(gè)簡(jiǎn)單的接口不準(zhǔn)備再重新部署一個(gè)站點(diǎn),所以就直接在MVC的項(xiàng)目里面加了一個(gè)API區(qū)域用來(lái)寫接口。這時(shí)候因?yàn)槭墙涌谒跃筒荒苡胏ookie方式進(jìn)行認(rèn)證,得加一個(gè)jwt認(rèn)證,采用多種身份驗(yàn)證方案來(lái)進(jìn)行認(rèn)證授權(quán)。
認(rèn)證授權(quán)
身份驗(yàn)證是確定用戶身份的過(guò)程。 授權(quán)是確定用戶是否有權(quán)訪問(wèn)資源的過(guò)程。 在 ASP.NET Core 中,身份驗(yàn)證由 IAuthenticationService 負(fù)責(zé),而它供身份驗(yàn)證中間件使用。 身份驗(yàn)證服務(wù)會(huì)使用已注冊(cè)的身份驗(yàn)證處理程序來(lái)完成與身份驗(yàn)證相關(guān)的操作。
認(rèn)證-->授權(quán)
關(guān)于認(rèn)證授權(quán)我們要區(qū)分認(rèn)證和授權(quán)是兩個(gè)概念,具體可查看MSDN官方文檔也可以搜索其它文章看看,講的很多。其中包括OAuth 2.0 以及jwt的相關(guān)知識(shí)都有很多資料并且講解的很好。
身份認(rèn)證
身份驗(yàn)證方案由 Startup.ConfigureServices 中的注冊(cè)身份驗(yàn)證服務(wù)指定:
方式是在調(diào)用 services.AddAuthentication 后調(diào)用方案特定的擴(kuò)展方法(例如 AddJwtBearer 或 AddCookie)。 這些擴(kuò)展方法使用 AuthenticationBuilder.AddScheme 向適當(dāng)?shù)脑O(shè)置注冊(cè)方案。
添加cookie JwtBearer驗(yàn)證方案
public void ConfigureServices(IServiceCollection services) { services.AddSession(); services.AddMvc(o => { o.Filters.Add(typeof(MyExceptionFilterAttribute));// 全局異常Filter }).AddRazorRuntimeCompilation(); //添加身份認(rèn)證方案 var jwtConfig= Configuration.GetSection("Jwt").Get<JwtConfig>(); services.AddAuthentication (authoption =>{ //指定默認(rèn)選項(xiàng) authoption.DefaultChallengeScheme= CookieAuthenticationDefaults.AuthenticationScheme; authoption.DefaultAuthenticateScheme = CookieAuthenticationDefaults.AuthenticationScheme; authoption.DefaultSignOutScheme = CookieAuthenticationDefaults.AuthenticationScheme; authoption.DefaultSignInScheme= CookieAuthenticationDefaults.AuthenticationScheme; }) .AddCookie(CookieAuthenticationDefaults.AuthenticationScheme, option => { option.Cookie.Name = "adCookie";//設(shè)置存儲(chǔ)用戶登錄信息(用戶Token信息)的Cookie名稱 option.Cookie.HttpOnly = true;//設(shè)置存儲(chǔ)用戶登錄信息(用戶Token信息)的Cookie,無(wú)法通過(guò)客戶端瀏覽器腳本(如JavaScript等)訪問(wèn)到 option.ExpireTimeSpan = TimeSpan.FromDays(3);// 過(guò)期時(shí)間 option.SlidingExpiration = true;// 是否在過(guò)期時(shí)間過(guò)半的時(shí)候,自動(dòng)延期 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)), //緩沖過(guò)期時(shí)間,總的有效時(shí)間等于這個(gè)時(shí)間加上jwt的過(guò)期時(shí)間 ClockSkew = TimeSpan.FromSeconds(0) }; }); }
JwtBearer認(rèn)證的配置參數(shù)類JwtConfig
public class JwtConfig { /// <summary> /// 誰(shuí)頒發(fā)的 /// </summary> public string Issuer { get; set; } /// <summary> /// 頒發(fā)給誰(shuí) /// </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> /// 過(guò)期時(shí)間(分鐘) /// </summary> public int Expires { get; set; } /// <summary> /// 是否校驗(yàn)過(guò)期時(shí)間 /// </summary> public bool ValidateLifetime { get; set; } }
appsettings.json 配置參數(shù)
"Jwt": { "Issuer": "issuer", "Audience": "audience", "SigningKey": "c0d32c63-z43d-4917-bbc2-5e726d087452", //過(guò)期時(shí)間(分鐘) "Expires": 10080, //是否驗(yàn)證過(guò)期時(shí)間 "ValidateLifetime": true }
添加身份驗(yàn)證中間件
通過(guò)在應(yīng)用的 IApplicationBuilder 上調(diào)用 UseAuthentication 擴(kuò)展方法,在 Startup.Configure 中添加身份驗(yàn)證中間件。 如果調(diào)用 UseAuthentication,會(huì)注冊(cè)使用之前注冊(cè)的身份驗(yàn)證方案的中間節(jié)。 請(qǐng)?jiān)谝蕾囉谝M(jìn)行身份驗(yàn)證的用戶的所有中間件之前調(diào)用 UseAuthentication。 如果使用終結(jié)點(diǎn)路由,則必須按以下順序調(diào)用 UseAuthentication:
- 在 UseRouting之后調(diào)用,以便路由信息可用于身份驗(yàn)證決策。
- 在 UseEndpoints 之前調(diào)用,以便用戶在經(jīng)過(guò)身份驗(yàn)證后才能訪問(wèn)終結(jié)點(diǎn)。
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(); //開(kāi)啟認(rèn)證中間件 app.UseAuthentication(); //開(kāi)啟授權(quán)中間件 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?}"); }); }
cookie認(rèn)證
[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 = "用戶名或密碼錯(cuò)誤"; } 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); }
jwt認(rèn)證
[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 = "用戶名或密碼錯(cuò)誤"; } else { //jwtTokenOptions 是通過(guò)配置獲取上面配置的參數(shù)信息 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); }
授權(quán)
在授權(quán)時(shí),應(yīng)用指示要使用的處理程序。 選擇應(yīng)用程序?qū)⑼ㄟ^(guò)以逗號(hào)分隔的身份驗(yàn)證方案列表傳遞到來(lái)授權(quán)的處理程序 [Authorize] 。 [Authorize]屬性指定要使用的身份驗(yàn)證方案或方案,不管是否配置了默認(rèn)。
默認(rèn)授權(quán)
因?yàn)樯厦嬲J(rèn)證配置中我們使用cookie作為默認(rèn)配置,所以前端對(duì)應(yīng)的controller就不用指定驗(yàn)證方案,直接打上[Authorize]即可。
選擇授權(quán)
對(duì)于API接口我們使用Jwt授權(quán),在Controller上打上指定方案。
[Authorize(AuthenticationSchemes = JwtBearerDefaults.AuthenticationScheme)]
總結(jié)
關(guān)于多種方案混合驗(yàn)證授權(quán)的流程:
1、配置認(rèn)證方案(相關(guān)的配置參數(shù)可采用配置文件形式)。
2、添加授權(quán)驗(yàn)證中間件。
3、提供認(rèn)證接口。
4、配置需要授權(quán)的接口授權(quán)方案。
到此這篇關(guān)于asp.net core3.1cookie和jwt混合認(rèn)證授權(quán)實(shí)現(xiàn)多種身份驗(yàn)證方案的文章就介紹到這了,更多相關(guān)asp.net core cookie和jwt認(rèn)證授權(quán)內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
- ASP.NET?Core?模型驗(yàn)證消息的本地化新姿勢(shì)詳解
- ASP.NET?Core?6.0?基于模型驗(yàn)證的數(shù)據(jù)驗(yàn)證功能
- ASP.NET?Core中Cookie驗(yàn)證身份用法詳解
- asp.net core配合vue實(shí)現(xiàn)后端驗(yàn)證碼邏輯
- [Asp.Net Core]用Blazor Server Side實(shí)現(xiàn)圖片驗(yàn)證碼
- ASP.NET Core實(shí)現(xiàn)自定義WebApi模型驗(yàn)證詳解
- asp.net core系列之模型綁定和驗(yàn)證方法
- ASP.NET Core WebApi中使用FluentValidation驗(yàn)證數(shù)據(jù)模型的方法
相關(guān)文章
ASP.NET Core使用AutoMapper實(shí)現(xiàn)實(shí)體映射
本文詳細(xì)講解了ASP.NET Core使用AutoMapper實(shí)現(xiàn)實(shí)體映射的方法,文中通過(guò)示例代碼介紹的非常詳細(xì)。對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2022-03-03.net微信開(kāi)發(fā) 如何獲取AccessToken
這篇文章主要為大家詳細(xì)介紹了微信開(kāi)發(fā)中AccessToken的獲取方法,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-03-03ASP.NET性能優(yōu)化小結(jié)(ASP.NET&C#)
ASP.NET性能優(yōu)化,提高頁(yè)面的執(zhí)行效率與下載速度,等很多需要考慮的細(xì)節(jié),編程人員值得參考下。2011-01-01點(diǎn)擊圖片,AJAX刪除后臺(tái)圖片文件的實(shí)現(xiàn)代碼(asp.net)
點(diǎn)擊頁(yè)面上的圖片,用jQuery的AJAX來(lái)刪除后臺(tái)真實(shí)的文件。2010-11-11關(guān)于Metalama使用Fabric操作項(xiàng)目或命名空間的問(wèn)題
Metalama是一個(gè)基于微軟編譯器Roslyn的元編程的庫(kù),可以解決我在開(kāi)發(fā)中遇到的重復(fù)代碼的問(wèn)題,這篇文章主要介紹了Metalama使用Fabric操作項(xiàng)目或命名空間,需要的朋友可以參考下2022-04-04ASP.NET Core 2.0 支付寶掃碼支付的實(shí)現(xiàn)代碼
這篇文章主要介紹了ASP.NET Core 2.0 支付寶掃碼支付的實(shí)現(xiàn)代碼,需要的朋友可以參考下2017-10-10ADO.NET實(shí)現(xiàn)對(duì)SQL Server數(shù)據(jù)庫(kù)的增刪改查示例
本篇文章主要介紹了ADO.NET實(shí)現(xiàn)對(duì)SQL Server數(shù)據(jù)庫(kù)的增刪改查示例,非常具有實(shí)用價(jià)值,需要的朋友可以參考下。2017-01-01ASP.NET數(shù)據(jù)庫(kù)操作類實(shí)例
這篇文章主要介紹了ASP.NET數(shù)據(jù)庫(kù)操作類,結(jié)合實(shí)例形式分析了asp.net基本的數(shù)據(jù)庫(kù)增刪改查操作封裝相關(guān)技巧,需要的朋友可以參考下2017-03-03