<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          .net core 自定義授權(quán)策略提供程序進(jìn)行權(quán)限驗(yàn)證

          共 19610字,需瀏覽 40分鐘

           ·

          2023-07-19 17:38

          在這之前先了解一下鑒權(quán)和授權(quán)的概念;

          鑒權(quán)

          鑒權(quán)可以說(shuō)是身份驗(yàn)證,身份驗(yàn)證是確定用戶身份的過(guò)程;

          在ASP.NET Core 中身份驗(yàn)證是由身份驗(yàn)證服務(wù)IAuthenticationService負(fù)責(zé)的,它被身份驗(yàn)證中間件使用, 身份驗(yàn)證服務(wù)會(huì)使用已注冊(cè)的身份驗(yàn)證處理程序來(lái)完成與身份驗(yàn)證相關(guān)的操作。身份驗(yàn)證相關(guān)的操作包括:對(duì)用戶身份進(jìn)行驗(yàn)證,對(duì)未經(jīng)身份驗(yàn)證的用戶進(jìn)行資源訪問(wèn)時(shí)做出響應(yīng)。

          身份驗(yàn)證處理程序及其配置選項(xiàng)

          身份驗(yàn)證處理程序包括CookieAuthenticationHandler 和 JwtBearerHandler,身份驗(yàn)證處理程序的注冊(cè) 是在調(diào)用AddAuthentication之后擴(kuò)展方法AddJwtBearer 和 AddCookie 提供的

          身份驗(yàn)證處理程序會(huì)由實(shí)現(xiàn)IAuthenticationService 接口的AuthenticationService 的AuthenticateAsync 方法去調(diào)用

          授權(quán)

          授權(quán)是確定用戶是否有權(quán)訪問(wèn)資源的過(guò)程,這里先簡(jiǎn)單帶過(guò)一下后面接著講

          授權(quán)方案

          授權(quán)方案包括 基于角色的授權(quán),基于聲明的授權(quán),基于策略的授權(quán),這里著重說(shuō)一下策略授權(quán),

          基于策略的授權(quán)

          授權(quán)策略包含一個(gè)或多個(gè)要求

                
                  builder.Services.AddAuthorization(options =>
                
                
                  {
                
                
                      options.AddPolicy("AtLeast21", policy =>
                
                
                          policy.Requirements.Add(new MinimumAgeRequirement(21)));
                
                
                  });
                
              
              
                
              
            

          在前面的示例中,創(chuàng)建了“AtLeast21”策略。該策略有一個(gè)最低年齡要求,其作為要求的參數(shù)提供

          IAuthorizationRequirement

          IAuthorizationRequirement用于跟蹤授權(quán)是否成功的機(jī)制

          在IAuthorizationHandler 的 HandleAsync方法中 作為參數(shù)被調(diào)用,由HttpContext 的Requirements 屬性提供

          IAuthorizationHandler

          IAuthorizationHandler 用于檢查策略是否滿足要求,主要執(zhí)行的方法是HandleAsync,我們可以繼承微軟提供的AuthorizationHandler,默認(rèn)實(shí)現(xiàn)了HandlAsync ,在具有多個(gè)IAuthorizationRequirement 的情況下默認(rèn)是循環(huán)去執(zhí)行HandleRequirementAsync方法,在某些情況下我們可以去重寫從而去執(zhí)行特定IAuthorizationRequirement,當(dāng)然方法多樣

                
                          public virtual async Task HandleAsync(AuthorizationHandlerContext context)
                
                
                          {
                
                
                              if (context.Resource is TResource)
                
                
                              {
                
                
                                  foreach (var req in context.Requirements.OfType<TRequirement>())
                
                
                                  {
                
                
                                      await HandleRequirementAsync(context, req, (TResource)context.Resource);
                
                
                                  }
                
                
                              }
                
                
                          }
                
              
              
                
              
            
          IAuthorizationPolicyProvider

          IAuthorizationPolicyProvider 自定義策略提供程序

          繼承IAuthorizationPolicyProvider 需要去實(shí)現(xiàn)IAuthorizationPolicyProvider 三個(gè)方法,三個(gè)方法的執(zhí)行由我們我們的Authorize特性決定,并且Authorize特性的策略名稱會(huì)傳遞到 IAuthorizationPolicyProvider 的GetPolicyAsync 作為參數(shù)使用

                
                       public Task<AuthorizationPolicy?> GetPolicyAsync(string policyName)
                
                
                          {
                
                
                              var policy = new AuthorizationPolicyBuilder();
                
                
                              //添加鑒權(quán)方案
                
                
                              policy.AddAuthenticationSchemes("Bearer");
                
                
                              policy.AddAuthenticationSchemes(CookieAuthenticationDefaults.AuthenticationScheme);
                
                
                              if (policyName is null)
                
                
                              {
                
                
                                  return Task.FromResult<AuthorizationPolicy>(null);
                
                
                              }
                
                
                              var authorizations = policyName.Split(',');
                
                
                              if (authorizations.Any())
                
                
                              {
                
                
                                  //權(quán)限策略構(gòu)建器,添加自定義的AuthorizaRequirement
                
                
                                  policy.AddRequirements(new AuthorizeRequirement(authorizations));
                
                
                              }
                
                
                              return Task.FromResult(policy.Build());
                
                
                          }
                
              
              
                
              
            

          這里看一下Authorize特性相關(guān)的屬性

                
                      public class AuthorizeAttribute : Attribute, IAuthorizeData
                
                
                      {
                
                
                          /// <summary>
                
                
                          /// </summary>
                
                
                          public AuthorizeAttribute() { }
                
                
                  
                    
          /// <summary> /// 初始化類類實(shí)例并且設(shè)置可訪問(wèn)資源策略名稱 /// </summary> /// <param name="policy">The name of the policy to require for authorization.</param> public AuthorizeAttribute(string policy) { Policy = policy; } /// <summary> /// 設(shè)置或獲取可以訪問(wèn)資源策略名稱 /// </summary> public string? Policy { get; set; }
          /// <summary> /// 設(shè)置或獲取可以訪問(wèn)資源的角色 /// </summary> public string? Roles { get; set; }
          /// <summary> /// 設(shè)置或獲取可以訪問(wèn)資源鑒權(quán)方案名稱 /// </summary> public string? AuthenticationSchemes { get; set; } }
              
                
              
            
          GetDefaultPolicyAsync

          默認(rèn)策略,當(dāng)我們的Authorize特性上不提供策略時(shí)執(zhí)行,這里的CustomAuthorization特性是繼承了Authorize特性

                
                          [CustomAuthorization]
                
                
                          [HttpGet("SetNotOP")]
                
                
                          [NoResult]
                
                
                          public int SetNotOP()
                
                
                          {
                
                
                              throw new ArgumentNullException(nameof(TestTask));
                
                
                              return 1;
                
                
                          }
                
              
              
                
              
            
          GetPolicyAsync

          在Authorize添加策略時(shí)執(zhí)行

                
                          [CustomAuthorization("test1", "test1")]
                
                
                          [HttpGet("TestTask")]
                
                
                          public async Task<int> TestTask()
                
                
                          {
                
                
                              await Task.CompletedTask;
                
                
                              return 1;
                
                
                          }
                
              
              
                
              
            
          GetFallbackPolicyAsync

          后備授權(quán)策略,是指在沒(méi)有為請(qǐng)求指定其他策略時(shí),由授權(quán)中間件提供的策略。在這里可以指返回空值,也可以設(shè)置指定策略返回

                
                      public Task<AuthorizationPolicy?> GetFallbackPolicyAsync()
                
                
                      {
                
                
                          return Task.FromResult<AuthorizationPolicy>(null);
                
                
                      }
                
                
                      //或者
                
                
                      public Task<AuthorizationPolicy?> GetFallbackPolicyAsync()
                
                
                      {
                
                
                          var policy = new AuthorizationPolicyBuilder();
                
                
                          policy.AddAuthenticationSchemes("Bearer");
                
                
                          policy.AddAuthenticationSchemes(CookieAuthenticationDefaults.AuthenticationScheme);
                
                
                          return Task.FromResult<AuthorizationPolicy>(policy.Build());
                
                
                      }
                
              
              
                
              
            
          IAuthorizationService

          IAuthorizationService是確認(rèn)授權(quán)成功與否的主要服務(wù),兵器 負(fù)責(zé)去執(zhí)行我們自定義的AuthorizationHandle

          看一段由微軟官方簡(jiǎn)化授權(quán)服務(wù)的代碼,可以看到AuthorizeAsync會(huì)去循環(huán)執(zhí)行自定義的AuthorizationHandle

                
                  
                    public async Task<AuthorizationResult> AuthorizeAsync(ClaimsPrincipal user, 
                  
                
                
                               object resource, IEnumerable<IAuthorizationRequirement> requirements)
                
                
                  {
                
                
                      // Create a tracking context from the authorization inputs.
                
                
                      var authContext = _contextFactory.CreateContext(requirements, user, resource);
                
                
                  
                    
          // By default this returns an IEnumerable<IAuthorizationHandlers> from DI. var handlers = await _handlers.GetHandlersAsync(authContext);
          // Invoke all handlers. foreach (var handler in handlers) { await handler.HandleAsync(authContext); }
          // Check the context, by default success is when all requirements have been met. return _evaluator.Evaluate(authContext); }
              
                
              
            

          到這里應(yīng)該對(duì)整個(gè)授權(quán)流程有了個(gè)大致的了解,在授權(quán)前會(huì)由鑒權(quán)中間件進(jìn)行一個(gè)鑒權(quán),鑒權(quán)通過(guò)后由IAuthorizationPolicyProvider 來(lái)提供一個(gè)授權(quán)策略(授權(quán)策略里可以添加我們需要的IAuthorizationRequirement),最后由IAuthorizationService 的HandleAsync去執(zhí)行自定義AuthorizeHandle

          具體實(shí)現(xiàn)

          自定義特性
                
                      public class CustomAuthorizationAttribute : AuthorizeAttribute
                
                
                      {
                
                
                          public virtual string[] AuthorizeName { get; private set; }
                
                
                  
                    
          public CustomAuthorizationAttribute(params string[] authorizeName) { AuthorizeName = authorizeName; Policy = string.Join(",", AuthorizeName); } }
              
                
              
            
          自定義策略提供程序
                
                      public class AuthorizationProvider : IAuthorizationPolicyProvider
                
                
                      {
                
                
                          public Task<AuthorizationPolicy> GetDefaultPolicyAsync()
                
                
                          {
                
                
                              var policy = new AuthorizationPolicyBuilder();
                
                
                              policy.AddAuthenticationSchemes("Bearer");
                
                
                              policy.AddAuthenticationSchemes(CookieAuthenticationDefaults.AuthenticationScheme);
                
                
                              //默認(rèn)授權(quán)測(cè)率必須添加一個(gè)IAuthorizationRequirement的實(shí)現(xiàn)
                
                
                              policy.AddRequirements(new AuthorizeRequirement());
                
                
                              return Task.FromResult<AuthorizationPolicy>(policy.Build());
                
                
                          }
                
                
                  
                    
          public Task<AuthorizationPolicy?> GetFallbackPolicyAsync() { return Task.FromResult<AuthorizationPolicy>(null); }
          public Task<AuthorizationPolicy?> GetPolicyAsync(string policyName) { var policy = new AuthorizationPolicyBuilder(); policy.AddAuthenticationSchemes("Bearer"); policy.AddAuthenticationSchemes(CookieAuthenticationDefaults.AuthenticationScheme); if (policyName is null) { return Task.FromResult<AuthorizationPolicy>(null); } var authorizations = policyName.Split(','); if (authorizations.Any()) { policy.AddRequirements(new AuthorizeRequirement(authorizations)); } return Task.FromResult(policy.Build()); } }
              
                
              
            
          自定義授權(quán)處理程序

          IPermissionsCheck 是我注入的權(quán)限檢測(cè)程序,其實(shí)對(duì)于權(quán)限認(rèn)證,重要的是控制對(duì)資源的訪問(wèn),整篇文章下來(lái)無(wú)非就是將特性上的值提供到我們所需要進(jìn)行權(quán)限檢測(cè)的程序中去,當(dāng)然我們也可以用權(quán)限過(guò)濾器反射獲取Authorize特性上的值來(lái)實(shí)現(xiàn)

                
                  public class AuthorizeHandler : AuthorizationHandler<AuthorizeRequirement>
                
                
                  {
                
                
                      private readonly IPermissionCheck _permisscheck;
                
                
                      private readonly IHttpContextAccessor _httpContextAccessor;
                
                
                  
                    
          public AuthorizeHandler(IHttpContextAccessor httpContextAccessor , IServiceProvider serviceProvider) { using var scope = serviceProvider.CreateScope(); _permisscheck = scope.ServiceProvider.GetRequiredService<IPermissionCheck>(); _httpContextAccessor = httpContextAccessor; }
          protected override async Task HandleRequirementAsync(AuthorizationHandlerContext context, AuthorizeRequirement requirement) { var identity = _httpContextAccessor?.HttpContext?.User?.Identity; var httpContext = _httpContextAccessor?.HttpContext; var isAuthenticated = identity?.IsAuthenticated ?? false; var claims = _httpContextAccessor?.HttpContext?.User?.Claims; var userId = claims?.FirstOrDefault(p => p.Type == "Id")?.Value; //判斷是否通過(guò)鑒權(quán)中間件--是否登錄 if (userId is null || !isAuthenticated) { context.Fail(); return; } var defaultPolicy = requirement.AuthorizeName?.Any() ?? false; //默認(rèn)授權(quán)策略 if (!defaultPolicy) { context.Succeed(requirement); return; } var roleIds = claims? .Where(p => p?.Type?.Equals("RoleIds") ?? false) .Select(p => long.Parse(p.Value)); var roleNames = claims? .Where(p => p?.Type?.Equals(ClaimTypes.Role) ?? false) .Select(p => p.Value); UserTokenModel tokenModel = new UserTokenModel() { UserId = long.Parse(userId ?? "0"), UserName = claims?.FirstOrDefault(p => p.Type == ClaimTypes.Name)?.Value ?? "", RoleNames = roleNames?.ToArray(), RoleIds = roleIds?.ToArray(), }; if (requirement.AuthorizeName.Any()) { if (!_permisscheck.IsGranted(tokenModel, requirement.AuthorizeName)) { context.Fail(); return; } } context.Succeed(requirement); } }
              
                
              
            
          自定義IAuthorizationRequirement
              
                
                  
                
              
            
                
                  public class AuthorizeRequirement : IAuthorizationRequirement
                
                
                  {
                
                
                      public virtual string[] AuthorizeName { get; private set; }
                
                
                      public AuthorizeRequirement(params string[] authorizeName)
                
                
                      {
                
                
                          AuthorizeName = authorizeName;
                
                
                      }
                
                
                  
                    
          public AuthorizeRequirement() { } }
          自定義授權(quán)結(jié)果中間件

          自定義授權(quán)結(jié)果中間件的作用,返回自定義響應(yīng),增強(qiáng)默認(rèn)質(zhì)詢或禁止響應(yīng)

                
                      public class AuthorizeMiddleHandle : IAuthorizationMiddlewareResultHandler
                
                
                      {
                
                
                          public async Task HandleAsync(RequestDelegate next, HttpContext context, AuthorizationPolicy                                               policy, PolicyAuthorizationResult authorizeResult)
                
                
                          {
                
                
                              if (!authorizeResult.Succeeded || authorizeResult.Challenged)
                
                
                              {
                
                
                                  var isLogin = context?.User?.Identity?.IsAuthenticated ?? false;
                
                
                                  var path = context?.Request?.Path ?? "";
                
                
                                  context.Response.StatusCode = StatusCodes.Status401Unauthorized;
                
                
                                  var response = new AjaxResponse();
                
                
                                  response.UnAuthorizedRequest = true;
                
                
                                  response.StatusCode = "401";
                
                
                                  var error = new ErrorInfo();
                
                
                                  error.Error = isLogin ? $"你沒(méi)有權(quán)限訪問(wèn)該接口-接口路由{path}" : "請(qǐng)先登錄系統(tǒng)";
                
                
                                  response.Error = error;
                
                
                                  await context.Response.WriteAsJsonAsync(response);
                
                
                                  return;
                
                
                              }
                
                
                              await next(context);
                
                
                          }
                
                
                      }
                
              
              
                
              
            
          相關(guān)服務(wù)的注冊(cè)
              
                
              
            
                
                              context.Services.AddScoped<IPermissionCheck, PermissionCheck>();
                
                
                              context.Services.AddSingleton<IAuthorizationPolicyProvider, AuthorizationProvider>();
                
                
                              context.Services.AddSingleton<IAuthorizationMiddlewareResultHandler, AuthorizeMiddleHandle>();
                
                
                  ????????????context.Services.AddSingleton<IAuthorizationHandler,?AuthorizeHandler>();
                
              

          到這里對(duì)于權(quán)限認(rèn)證有了個(gè)大概的了解,至于是通過(guò)自定義策略提供程序自定義AuthorizHandle這一系列復(fù)雜的操作還是通過(guò)權(quán)限過(guò)濾器取決看官自己。個(gè)人認(rèn)為通過(guò)自定義策略提供程序自定義AuthorizHandle這種方式更靈活性,能夠應(yīng)對(duì)更多復(fù)雜場(chǎng)景。

          作者:阿文不知所措

          原文鏈接:cnblogs.com/lonely-wen/p/17247847.html


          版權(quán)聲明:本文來(lái)源于網(wǎng)友收集或網(wǎng)友供稿,僅供學(xué)習(xí)交流之用,如果有侵權(quán),請(qǐng)轉(zhuǎn)告小編或者留言,本公眾號(hào)立即刪除。



          9dfc0b25ed76f2b73b4159d1760b22c0.webp 支持小薇
              

          關(guān)注公眾號(hào)DotNet開(kāi)發(fā)跳槽?????

                

          點(diǎn)

          e54855b629c4e11709796d25f3a9476b.webp

          點(diǎn)

          35ebf1aaf531f1055a633c45ec74a80b.webp

          點(diǎn) 點(diǎn)

          e7a66e365b993294a3fe66cd3313a2e7.webp

          點(diǎn)在看

          瀏覽 45
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評(píng)論
          圖片
          表情
          推薦
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  人妻资源网 | 蜜桃91精品秘 入口内裤 | 精品无码国产一区二区深花 | 美女操逼的网站 | 日韩一区二区三区免费播放 |