ASP.NET Core集成现有系统认证
我們現(xiàn)在大多數(shù)轉(zhuǎn)向ASP.NET Core來使用開發(fā)的團(tuán)隊(duì),應(yīng)該都不是從0開始搭建系統(tǒng),而是老的業(yè)務(wù)系統(tǒng)已經(jīng)在運(yùn)行,ASP.NET Core用來開發(fā)新模塊。那么解決用戶認(rèn)證的問題,成為我們的第一個(gè)攔路虎。
認(rèn)證與授權(quán)?
什么是認(rèn)證??
?
首先認(rèn)證并不是登錄。認(rèn)證是一個(gè)知道用戶是誰的一個(gè)過程。我們最早使用的基于Session的認(rèn)證,拿到用戶輸入的用戶名和密碼到數(shù)據(jù)庫里面校驗(yàn)一,看看是否正確,如果是正確的我們就放到session里面。這是一個(gè)完成認(rèn)證的過程,系統(tǒng)現(xiàn)在知道你是我的某一個(gè)用戶了。
那么何謂授權(quán)??
現(xiàn)在用戶登錄之后我們跳轉(zhuǎn)到了另一個(gè)頁面,這個(gè)頁面可能會寫一段這樣的代碼。
if(Session["user"]==null) {Response.redirect("/login.aspx") }如果用戶登錄的Session不存在則再跳回到登錄頁面讓用戶登錄。 檢查當(dāng)前用戶有沒有某個(gè)權(quán)限的這個(gè)過程叫授權(quán)。如果沒有怎么辦?我們就會跳轉(zhuǎn)用戶到一個(gè)沒有權(quán)限的提示頁面,或者返回? Forbidden 403 的HTTP 狀態(tài)碼,這是最簡單的授權(quán)。
復(fù)雜的授權(quán)方式包括對角色,對具體資源訪問以及操作的授權(quán),這塊我們后面再講。
?
當(dāng)我們的ASP.NET Core項(xiàng)目需要與老的項(xiàng)目兼容的時(shí)候,就需要兼容老項(xiàng)目的認(rèn)證方式,比如某種自定義的token(這是之前比較常見的做法)。我們需要在ASP.NET Core中根據(jù)當(dāng)前用戶header里面的token來判斷是否為一個(gè)合法的用戶。
用Middleware攔截
第一種簡單粗暴的方法即用Middleware來攔截。
在ASP.NET Core下,MVC以一個(gè)Middleware加入到整個(gè)HTTP管道。在此之前還會添加一個(gè)Routing的Middleware,注意這里的意思也就是說 Routing不再和ASP.NET MVC一樣屬于它的一部分。正好相反,在ASP.NET Core里面是有一個(gè)MVCRouteHandler被 Routing Middleware 加載出來處理請求。關(guān)于路由這塊我們后面再說。
如果我們要在MVC Middleware執(zhí)行之請攔截請求只要加一個(gè)Middleware在 MVC Middleware或者Routing之前即可。
public void Configure(IApplicationBuilder app){app.Use(async (context, next) => { ??if (context.Request.Headers.ContainsKey("token")){ ? ? ?
? ?var token = context.Request.Headers["token"].FirstOrDefault(); ? ? ?
? ? ?if (token == "jessetalk.cn"){ ? ? ? ? ?await next();}} ?context.Response.StatusCode = 401;});app.UseMvc(); }
上面是我們有簡易的方法實(shí)現(xiàn)的一個(gè)Middleware,被加到了MVC之前。當(dāng)Request的Headers中沒有一個(gè)值為“jessetalk.cn” 以及 name為” token”的項(xiàng)的時(shí)候,我們就返回401狀態(tài),并且不執(zhí)行后面的處理。(不調(diào)用 next方法)
但是這種辦法相當(dāng)于一刀切,我們添加的這個(gè)Middleware發(fā)生在 MVC Middleware之前把所有沒有認(rèn)證信息的請求全部攔截掉了。好處是有節(jié)省服務(wù)器資源(如果確定是要攔截的就沒有必須再經(jīng)過MVC的一些處理了),壞處是無法實(shí)現(xiàn)單個(gè)Controller或者Action的靈活配置。
定制JWTBearer Authentication
ASP.NET Core為我們實(shí)現(xiàn)了JWTBearer Authentication,關(guān)于 JWTBearer Authentication的實(shí)現(xiàn)可以參考另外一篇文章《在ASP.NET Core中使用JWTBearer Authentication》。我們今天要做的就是通過定制JWTBearer Authentication來達(dá)到讓它讀取我們自定義的Token并且用我們自己的方式來校驗(yàn)這個(gè)Token。有點(diǎn)時(shí)代倒退的感覺是不是?
如果在時(shí)間和人員都足夠的情況下,我們是可能直接整體替換成標(biāo)準(zhǔn)的JWT方案,甚至做到SSO。但是架構(gòu)是沒有止境的,在一定的時(shí)間框架下,要做到高效且安全的切換,這不失為一種好辦法。
首先我們需要看一下在JWTBearer中默認(rèn)獲取的token是在Authorization的頭里,Bearer空格加上token。而如果有不規(guī)范的做法,可能是直接在headers里面加了一個(gè)token,里面有一個(gè)用我們自己的算法生成的token。
更改token的來源
JWTBearer authentication handler提供的Events中有一個(gè)OnMessageReceived委托可以讓我們從另外的地方讀取token。
services.AddAuthentication(options => {options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme; }).AddJwtBearer(o => {o.Events = new JwtBearerEvents(){OnMessageReceived = context => { ? ? ? ? ??var token = context.Request.Headers["token"];context.Token = token.FirstOrDefault(); ? ? ?
? ? ? ?return Task.CompletedTask;},}; });
定制token的驗(yàn)證方式
從headers里面拿到token之后,下一步就是要把它的驗(yàn)證算法改成我們自己的。這一步可以通過自定義?ISecurityTokenValidator來實(shí)現(xiàn) 。我們在這個(gè)Validator里面,校驗(yàn)token生成一個(gè)ClaimsPrincipal,這個(gè)principal就會被賦值到 HttpContext.User上。
同時(shí)我們還根據(jù)當(dāng)前的token添加了一個(gè)Role Claim,它的值有user和admin。這個(gè)可能用來做基于角色的授權(quán) 。
public class MyTokenValidator : ISecurityTokenValidator{ ??public ClaimsPrincipal ValidateToken(string securityToken,
TokenValidationParameters validationParameters, out SecurityToken validatedToken)
? ?{validatedToken = null; ? ? ?
? ?var identity = new ClaimsIdentity(JwtBearerDefaults.AuthenticationScheme);identity.AddClaim(new Claim("name", "jesse"));identity.AddClaim(new Claim(ClaimsIdentity.DefaultRoleClaimType, securityToken == "jessetalk.cn" ? "admin" : "user")); ? ? ? ?var principal = new ClaimsPrincipal(identity); ? ? ? ?return principal;} }
注意ClaimsIdentity的AuthenticationScheme一定要與我們在UseAuthentication時(shí)設(shè)置的名稱一樣。否則Identity.IsAuthenticated無法正確設(shè)置為true,我們的授權(quán)就沒有辦法完成。
有了我們自定義的Validator之后,我們要對JwtBearer進(jìn)行改造,去掉它默認(rèn)的Validator,加上我們自己定義的這個(gè)。
開始進(jìn)行授權(quán)
為了給大家演示上面的功能,我們新建兩個(gè)Controller,一個(gè)是Admin,另一個(gè)是Home。兩者都需要用戶有token才能正常訪問,但是對于Admin我們需要用戶具有admin的role才可以,否則會被拒絕返回403。
HomeController.cs
[Authorize]public class HomeController : Controller{ ??public IActionResult Index() ? ?{ ? ? ?
? ?return Ok();} }
當(dāng)Headers里面沒有token?值的時(shí)候,API請求返回 401。
當(dāng)Headers里面有token值時(shí),API可以被正常訪問。
我們又加了一個(gè)AdminController,不一樣的是這次我們給Authorize加上了Role=”admin”,也就是只有擁有admin的Role才可以訪問這個(gè)API。
[Authorize(Roles ="admin")]public class AdminController : Controller{ ?
?public IActionResult Index() ? ?{ ? ?
? ? ?return Ok();} }
當(dāng)我們用user的token訪問時(shí),我們會得到403。
只有用admin的token,才能正常訪問。
以是就是基于JWT Authentication來定制的我們自己的認(rèn)證方案的一個(gè)基本思路,主要是實(shí)現(xiàn)OnMessageReceived來改造token的來源,以及定義自己的?ISecurityTokenValidator?來實(shí)現(xiàn)對token的驗(yàn)證。
原文地址:http://www.jessetalk.cn/2017/11/03/asp-net-core-authentication-with-legacy-system/
.NET社區(qū)新聞,深度好文,歡迎訪問公眾號文章匯總 http://www.csharpkit.com
總結(jié)
以上是生活随笔為你收集整理的ASP.NET Core集成现有系统认证的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 向ASP.NET Core迁移
- 下一篇: .NET Core跨平台的奥秘[中篇]: