日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

aspnet core 2.1中使用jwt从原理到精通二

發(fā)布時(shí)間:2023/12/4 编程问答 38 豆豆
生活随笔 收集整理的這篇文章主要介紹了 aspnet core 2.1中使用jwt从原理到精通二 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

在aspnet core中,自定義jwt管道驗(yàn)證

有了上一節(jié)的內(nèi)容作為基礎(chǔ),那這點(diǎn)也是非常容易的,關(guān)鍵點(diǎn)在中間件,只是把上一級在測試類中的自定義驗(yàn)證放到中間件中來即可,

不過需要注意:中間件 的位置很重要,只有它后面的管道才會收到影響;

那我們先建一個(gè)自定義中間件類:(中間件的詳細(xì)內(nèi)容這里就不講了,大家可以參考官網(wǎng)和其他博文)

/// <summary>

? ? /// 自定義授權(quán)中間件

? ? /// </summary>

? ? public class JwtCustomerAuthorizeMiddleware

? ? {

? ? ? ? private readonly RequestDelegate next;


? ? ? ? public JwtCustomerAuthorizeMiddleware(RequestDelegate next, string secret, List<string> anonymousPathList)

? ? ? ? {

? ? ? ? ? ? #region? ?設(shè)置自定義jwt 的秘鑰

? ? ? ? ? ? if(!string.IsNullOrEmpty(secret))

? ? ? ? ? ? {

? ? ? ? ? ? ? ? TokenContext.securityKey = secret;

? ? ? ? ? ? }

? ? ? ? ? ? #endregion

? ? ? ? ? ? this.next = next;

? ? ? ? ? ? UserContext.AllowAnonymousPathList.AddRange(anonymousPathList);

? ? ? ? }


? ? ? ? public async Task Invoke(HttpContext context, UserContext userContext,IOptions<JwtOption> optionContainer)

? ? ? ? {

? ? ? ? ? ? if (userContext.IsAllowAnonymous(context.Request.Path))

? ? ? ? ? ? {

? ? ? ? ? ? ? ? await next(context);

? ? ? ? ? ? ? ? return;

? ? ? ? ? ? }


? ? ? ? ? ? var option = optionContainer.Value;


? ? ? ? ? ? #region 身份驗(yàn)證,并設(shè)置用戶Ruser值

?

? ? ? ? ? ? var result = context.Request.Headers.TryGetValue("Authorization", out StringValues authStr);

? ? ? ? ? ? if (!result || string.IsNullOrEmpty(authStr.ToString()))

? ? ? ? ? ? {

? ? ? ? ? ? ? ? throw new UnauthorizedAccessException("未授權(quán)");

? ? ? ? ? ? }

? ? ? ? ? ? result = TokenContext.Validate(authStr.ToString().Substring("Bearer ".Length).Trim(), payLoad =>

? ? ? ? ? ? {

? ? ? ? ? ? ? ? var success = true;

? ? ? ? ? ? ? ? //可以添加一些自定義驗(yàn)證,用法參照測試用例

? ? ? ? ? ? ? ? //驗(yàn)證是否包含aud 并等于 roberAudience

? ? ? ? ? ? ? ? success = success && payLoad["aud"]?.ToString() == option.Audience;

? ? ? ? ? ? ? ? if (success)

? ? ? ? ? ? ? ? {

? ? ? ? ? ? ? ? ? ? //設(shè)置Ruse值,把user信息放在payLoad中,(在獲取jwt的時(shí)候把當(dāng)前用戶存放在payLoad的ruser鍵中)

? ? ? ? ? ? ? ? ? ? //如果用戶信息比較多,建議放在緩存中,payLoad中存放緩存的Key值

? ? ? ? ? ? ? ? ? ? userContext.TryInit(payLoad["ruser"]?.ToString());

? ? ? ? ? ? ? ? }

? ? ? ? ? ? ? ? return success;

? ? ? ? ? ? });

? ? ? ? ? ? if (!result)

? ? ? ? ? ? {

? ? ? ? ? ? ? ? throw new UnauthorizedAccessException("未授權(quán)");

? ? ? ? ? ? }


? ? ? ? ? ? #endregion

? ? ? ? ? ? #region 權(quán)限驗(yàn)證

? ? ? ? ? ? if (!userContext.Authorize(context.Request.Path))

? ? ? ? ? ? {

? ? ? ? ? ? ? ? throw new UnauthorizedAccessException("未授權(quán)");

? ? ? ? ? ? }

? ? ? ? ? ? #endregion


? ? ? ? ? ? await next(context);

? ? ? ? }

? ? }

上面這個(gè)中間件中有個(gè)UserContext上線文,這個(gè)類主要管理當(dāng)前用戶信息和權(quán)限,其他信息暫時(shí)不管;我們先看一下這個(gè)中間件的驗(yàn)證流程如何:

該中間件主要是針對訪問的路徑進(jìn)行驗(yàn)證,當(dāng)然你也可以針對其他信息進(jìn)行驗(yàn)證,比如(控制器名稱,動作名稱,等)

  • 檢查當(dāng)前url是否可以匿名訪問,如果可以就直接通過,不做驗(yàn)證了;如果不是可以匿名訪問的路徑,那就繼續(xù)

  • 獲取當(dāng)前http頭部攜帶的jwt(存放在頭部的 Authorization中);

  • 使用上一節(jié)的講的TokenContext做必須的驗(yàn)證和自定義復(fù)雜驗(yàn)證;

  • 獲取當(dāng)前訪問用戶信息,我們把用戶的基本信息放在payLoad["ruser"]中,請看代碼如何操作

  • 到這里為止,都是做的身份驗(yàn)證,表明你是一個(gè)有身份的的人;接下來是做權(quán)限驗(yàn)證,你是一個(gè)有身份的人,并不代表你是一個(gè)隨便到處訪問的人;你能訪問哪些url或者action,就要得到權(quán)限驗(yàn)證的認(rèn)可

  • 我們把權(quán)限驗(yàn)證放到 userContext.Authorize方法中(這里怎么操作,這里就不深入講解,基本原理是從數(shù)據(jù)庫或者緩存中獲取當(dāng)前用戶對應(yīng)的權(quán)限列表,也就是url列表,進(jìn)行對比);

  • 自定義中間件使用jwt驗(yàn)證就這些內(nèi)容,是不是感覺很清晰,很簡單,有木有;

    中間已經(jīng)完成了,那接下來我們來使用它,我們再startup中的Configure方法中添加如下代碼

    app.UseMiddleware<JwtCustomerAuthorizeMiddleware>(Configuration["JwtOption:SecurityKey"], new List<string>() { "/api/values/getjwt","/" });

    當(dāng)然上面可匿名訪問的url也可以定義在appsetting.json文件中,可以自行嘗試

    如何通過自定義策略形式實(shí)現(xiàn)自定義jwt驗(yàn)證

    創(chuàng)建自定義策略的詳細(xì)介紹可以參考官網(wǎng),這里就不詳細(xì)介紹,

    首先我們上代碼,創(chuàng)建自定義策略非常重要的兩個(gè)類,如下:

    public class CommonAuthorizeHandler : AuthorizationHandler<CommonAuthorize>

    ? ? {

    ? ? ? ? /// <summary>

    ? ? ? ? /// 常用自定義驗(yàn)證策略,模仿自定義中間件JwtCustomerauthorizeMiddleware的驗(yàn)證范圍

    ? ? ? ? /// </summary>

    ? ? ? ? /// <param name="context"></param>

    ? ? ? ? /// <param name="requirement"></param>

    ? ? ? ? /// <returns></returns>

    ? ? ? ? protected override Task HandleRequirementAsync(AuthorizationHandlerContext context, CommonAuthorize requirement)

    ? ? ? ? {

    ? ? ? ? ? ? var httpContext = (context.Resource as AuthorizationFilterContext).HttpContext;

    ? ? ? ? ? ? var userContext = httpContext.RequestServices.GetService(typeof(UserContext)) as UserContext;


    ? ? ? ? ? ? var jwtOption = (httpContext.RequestServices.GetService(typeof(IOptions<JwtOption>)) as IOptions<JwtOption>).Value;


    ? ? ? ? ? ? #region 身份驗(yàn)證,并設(shè)置用戶Ruser值


    ? ? ? ? ? ? var result = httpContext.Request.Headers.TryGetValue("Authorization", out StringValues authStr);

    ? ? ? ? ? ? if (!result || string.IsNullOrEmpty(authStr.ToString()))

    ? ? ? ? ? ? {

    ? ? ? ? ? ? ? ? return Task.CompletedTask;

    ? ? ? ? ? ? }

    ? ? ? ? ? ? result = TokenContext.Validate(authStr.ToString().Substring("Bearer ".Length).Trim(), payLoad =>

    ? ? ? ? ? ? {

    ? ? ? ? ? ? ? ? var success = true;

    ? ? ? ? ? ? ? ? //可以添加一些自定義驗(yàn)證,用法參照測試用例

    ? ? ? ? ? ? ? ? //驗(yàn)證是否包含aud 并等于 roberAudience

    ? ? ? ? ? ? ? ? success = success && payLoad["aud"]?.ToString() == jwtOption.Audience;

    ? ? ? ? ? ? ? ? if (success)

    ? ? ? ? ? ? ? ? {

    ? ? ? ? ? ? ? ? ? ? //設(shè)置Ruse值,把user信息放在payLoad中,(在獲取jwt的時(shí)候把當(dāng)前用戶存放在payLoad的ruser鍵中)

    ? ? ? ? ? ? ? ? ? ? //如果用戶信息比較多,建議放在緩存中,payLoad中存放緩存的Key值

    ? ? ? ? ? ? ? ? ? ? userContext.TryInit(payLoad["ruser"]?.ToString());

    ? ? ? ? ? ? ? ? }

    ? ? ? ? ? ? ? ? return success;

    ? ? ? ? ? ? });

    ? ? ? ? ? ? if (!result)

    ? ? ? ? ? ? {

    ? ? ? ? ? ? ? ? return Task.CompletedTask;

    ? ? ? ? ? ? }


    ? ? ? ? ? ? #endregion

    ? ? ? ? ? ? #region 權(quán)限驗(yàn)證

    ? ? ? ? ? ? if (!userContext.Authorize(httpContext.Request.Path))

    ? ? ? ? ? ? {

    ? ? ? ? ? ? ? ? return Task.CompletedTask;

    ? ? ? ? ? ? }

    ? ? ? ? ? ? #endregion


    ? ? ? ? ? ? context.Succeed(requirement);

    ? ? ? ? ? ? return Task.CompletedTask;

    ? ? ? ? }

    ? ? }

    ? ? public class CommonAuthorize: IAuthorizationRequirement

    ? ? {


    ? ? }

    其中兩個(gè)重要的類是哪兩個(gè)呢?他們的作用又是什么呢?

  • CommonAuthorize: IAuthorizationRequirement,至于取什么名字,自己定義,但必須繼承IAuthorizationRequirement,這類主要是承載一些初始化值,讓后傳遞到Handler中去,給驗(yàn)證做邏輯運(yùn)算提供一些可靠的信息;我這里是空的;自己根據(jù)自身情況自己定義適當(dāng)?shù)膶傩宰鳛槌跏紨?shù)據(jù)的承載容器;
  • CommonAuthorizeHandler : AuthorizationHandler<CommonAuthorize>這個(gè)是重點(diǎn),承載了驗(yàn)證的邏輯運(yùn)算
    需要重寫override Task HandleRequirementAsync方法,所有的邏輯都在該方法中,他的主要邏輯和上面的自定義中間件很相似,只少了上面的第一步;驗(yàn)證流程如下:
  • 獲取當(dāng)前http頭部攜帶的jwt(存放在頭部的 Authorization中);

  • 使用上一節(jié)的講的TokenContext做必須的驗(yàn)證和自定義復(fù)雜驗(yàn)證;

  • 獲取當(dāng)前訪問用戶信息,我們把用戶的基本信息放在payLoad["ruser"中,請看代碼如何操作

  • 到這里為止,都是做的身份驗(yàn)證,表明你是一個(gè)有身份的的人;接下來是做權(quán)限驗(yàn)證,你是一個(gè)有身份的人,并不代表你是一個(gè)隨便到處訪問的人;你能訪問哪些url或者action,就要得到權(quán)限驗(yàn)證的認(rèn)可

  • 我們把權(quán)限驗(yàn)證放到 userContext.Authorize方法中(這里怎么操作,這里就不深入講解,基本原理是從數(shù)據(jù)庫或者緩存中獲取當(dāng)前用戶對應(yīng)的權(quán)限列表,也就是url列表,進(jìn)行對比);

    context.Succeed(requirement);是驗(yàn)證成功,如果沒有這個(gè),就默認(rèn)驗(yàn)證失敗

    因?yàn)閁serContext把負(fù)責(zé)了權(quán)限驗(yàn)證,所以不會把流程搞得感覺很亂,并且可以重用,至于用那種形式驗(yàn)證也很容易切換

  • 是不是很簡單,和自定義管道驗(yàn)證的的代碼幾乎一模一樣,

  • 如何使用自定義定義策略呢?

  • 在startup類中的ConfigureServices中加入如下代碼:

  • 以上代碼主要分3個(gè)部分
    1、添加上面自定義的策略,并取名;
    2、設(shè)置秘鑰,這個(gè)秘鑰就是上一節(jié)中生成jwt的秘鑰,必須要要一樣,否則是簽名不正確
    3、注入上面建立的一個(gè)重要類CommonAuthorizeHandler,如上面代碼

  • 在startup類中的Configure中添加?app.UseAuthentication();

  • 在需要驗(yàn)證的Controller或者Action中加上[Authorize(Policy = "common")]屬性,看下圖:

    到此為止你就可以使用自定義策略的驗(yàn)證了;

  • ?

    使用管道和自定義策略兩種形式進(jìn)行驗(yàn)證有什么區(qū)別呢?

    從效果上看都是一樣的,稍微有點(diǎn)區(qū)別

  • 使用管道的方式,感覺方便點(diǎn),清晰點(diǎn)

  • 使用自定義策略的方式,效率稍微高一點(diǎn),畢竟不是所有的請求都會進(jìn)行是否可以匿名訪問運(yùn)算和建立管道的消耗,只有加入Authorize屬性的Controller和Action的才會進(jìn)入;當(dāng)然這點(diǎn)損耗可以忽略不計(jì),看自己的喜好;

  • 至于你喜歡那種,就使用哪種吧,性能可以忽略不計(jì);

    不管使用哪種方式使用jwt作為身份和權(quán)限驗(yàn)證是不是很簡單,關(guān)鍵這里也把權(quán)限驗(yàn)證的邏輯抽出來了,這樣代碼就更清晰明了了;

    至于Authorize的屬性形式,還有很多其他的策略,比如用戶、申明,角色等,可查看官網(wǎng)https://docs.microsoft.com/zh-cn/aspnet/core/security/authorization/?view=aspnetcore-2.0

    下一章將講解 用戶,申明 ,角色的驗(yàn)證,并這些怎么在自定義的驗(yàn)證中實(shí)現(xiàn),以便大家對他有個(gè)清晰的對比

    相關(guān)文章:

    • aspnet core 2.1中使用jwt從原理到精通一

    • IdentityServer4之JWT簽名(RSA加密證書)及驗(yàn)簽

    • IdentityServer4實(shí)戰(zhàn) - 談?wù)?JWT Token 的安全策略

    • 如何簡單的在 ASP.NET Core 中集成 JWT 認(rèn)證?

    原文地址:?https://www.cnblogs.com/lechengbo/p/9861501.html


    .NET社區(qū)新聞,深度好文,歡迎訪問公眾號文章匯總 http://www.csharpkit.com

    總結(jié)

    以上是生活随笔為你收集整理的aspnet core 2.1中使用jwt从原理到精通二的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。