Ocelot統一許可權驗證

来源:http://www.cnblogs.com/axzxs2001/archive/2017/12/08/8005084.html
-Advertisement-
Play Games

一篇,我們創建了OcelotGateway網關項目,DemoAAPI項目,DemoBAPI項目,為了驗證用戶並分發Token,現在還需要添加AuthenticationAPI項目,也是asp.net core web api項目,整體思路是,當用戶首次請求(Request)時web服務,網關會判斷本... ...


Ocelot作為網關,可以用來作統一驗證,接上一篇博客,我們繼續

前一篇,我們創建了OcelotGateway網關項目,DemoAAPI項目,DemoBAPI項目,為了驗證用戶並分發Token,現在還需要添加AuthenticationAPI項目,也是asp.net core web api項目,整體思路是,當用戶首次請求(Request)時web服務,網關會判斷本請求有無Token,並是否正確,如果沒有或不正確,就會反回401 Unauthorized;如果請求調用登錄,正確輸入用戶名或密碼,AuthenticationAPI會驗證並分發Token;當客戶端帶上Token再次訪問web服務時,網關就會放過本請求,當請求到達web服務時,web服務要對本Token進行授權驗證,如果有訪問請求的地址,會成功返回應答,負責會提示沒有權驗,所以只要具有正確的Token,應答返回都是200 OK,因為Token正確,只是沒有許可權訪問請求的內容。
下麵創建最重要的一個項目Ocelot.JWTAuthorizePolicy,選.NET Standard的類庫作為項目模板創建本項目,本項目的作用是為網關項目(OcelotGateway),web服務項目(DemoAAPI和DemoBAPI),和AuthenticationAPI提供註入JWT或自定義策略的API,關於自定義策略,可參考(http://www.cnblogs.com/axzxs2001/p/7530929.html)
本項目中的組成部分:
Permission.cs

 1 namespace Ocelot.JWTAuthorizePolicy
 2 {
 3 /// <summary>
 4 /// 用戶或角色或其他憑據實體
 5 /// </summary>
 6 public class Permission
 7 {
 8 /// <summary>
 9 /// 用戶或角色或其他憑據名稱
10 /// </summary>
11 public virtual string Name
12 { get; set; }
13 /// <summary>
14 /// 請求Url
15 /// </summary>
16 public virtual string Url
17 { get; set; }
18 }
19 }
View Code

PermissionRequirement.cs

 1 using Microsoft.AspNetCore.Authorization;
 2 using Microsoft.IdentityModel.Tokens;
 3 using System;
 4 using System.Collections.Generic;
 5 
 6 namespace Ocelot.JWTAuthorizePolicy
 7 {
 8 /// <summary>
 9 /// 必要參數類
10 /// </summary>
11 public class PermissionRequirement : IAuthorizationRequirement
12 {
13 /// <summary>
14 /// 無許可權action
15 /// </summary>
16 public string DeniedAction { get; set; }
17 
18 /// <summary>
19 /// 認證授權類型
20 /// </summary>
21 public string ClaimType { internal get; set; }
22 /// <summary>
23 /// 請求路徑
24 /// </summary>
25 public string LoginPath { get; set; } = "/Api/Login";
26 /// <summary>
27 /// 發行人
28 /// </summary>
29 public string Issuer { get; set; }
30 /// <summary>
31 /// 訂閱人
32 /// </summary>
33 public string Audience { get; set; }
34 /// <summary>
35 /// 過期時間
36 /// </summary>
37 public TimeSpan Expiration { get; set; }
38 /// <summary>
39 /// 簽名驗證
40 /// </summary>
41 public SigningCredentials SigningCredentials { get; set; }
42 
43 /// <summary>
44 /// 構造
45 /// </summary>
46 /// <param name="deniedAction">無許可權action</param>
47 /// <param name="userPermissions">用戶許可權集合</param>
48 
49 /// <summary>
50 /// 構造
51 /// </summary>
52 /// <param name="deniedAction">拒約請求的url</param> 
53 /// <param name="claimType">聲明類型</param>
54 /// <param name="issuer">發行人</param>
55 /// <param name="audience">訂閱人</param>
56 /// <param name="signingCredentials">簽名驗證實體</param>
57 public PermissionRequirement(string deniedAction, string claimType, string issuer, string audience, SigningCredentials signingCredentials, TimeSpan expiration)
58 {
59 ClaimType = claimType;
60 DeniedAction = deniedAction; 
61 Issuer = issuer;
62 Audience = audience;
63 Expiration = expiration;
64 SigningCredentials = signingCredentials;
65 }
66 }
67 }
View Code

PermissionHandler.cs

 1 using Microsoft.AspNetCore.Authentication;
 2 using Microsoft.AspNetCore.Authentication.JwtBearer;
 3 using Microsoft.AspNetCore.Authorization;
 4 using Microsoft.Extensions.DependencyInjection;
 5 using System;
 6 using System.Collections.Generic;
 7 using System.Linq;
 8 using System.Security.Claims;
 9 using System.Threading.Tasks;
10 
11 namespace Ocelot.JWTAuthorizePolicy
12 {
13 /// <summary>
14 /// 許可權授權Handler
15 /// </summary>
16 public class PermissionHandler : AuthorizationHandler<PermissionRequirement>
17 {
18 /// <summary>
19 /// 驗證方案提供對象
20 /// </summary>
21 public IAuthenticationSchemeProvider Schemes { get; set; }
22 /// <summary>
23 /// 用戶許可權集合
24 /// </summary>
25 List<Permission> _permissions;
26 /// <summary>
27 /// 構造
28 /// </summary>
29 /// <param name="schemes"></param>
30 public PermissionHandler(IAuthenticationSchemeProvider schemes, List<Permission> permissions=null)
31 {
32 Schemes = schemes;
33 _permissions = permissions;
34 }
35 
36 protected override async Task HandleRequirementAsync(AuthorizationHandlerContext context, PermissionRequirement requirement)
37 {
38 //從AuthorizationHandlerContext轉成HttpContext,以便取出表求信息
39 var httpContext = (context.Resource as Microsoft.AspNetCore.Mvc.Filters.AuthorizationFilterContext).HttpContext;
40 //請求Url
41 var questUrl = httpContext.Request.Path.Value.ToLower();
42 //判斷請求是否停止
43 var handlers = httpContext.RequestServices.GetRequiredService<IAuthenticationHandlerProvider>();
44 foreach (var scheme in await Schemes.GetRequestHandlerSchemesAsync())
45 {
46 var handler = await handlers.GetHandlerAsync(httpContext, scheme.Name) as IAuthenticationRequestHandler;
47 if (handler != null && await handler.HandleRequestAsync())
48 {
49 context.Fail();
50 return;
51 }
52 }
53 //判斷請求是否擁有憑據,即有沒有登錄
54 var defaultAuthenticate = await Schemes.GetDefaultAuthenticateSchemeAsync();
55 if (defaultAuthenticate != null)
56 {
57 var result = await httpContext.AuthenticateAsync(defaultAuthenticate.Name);
58 //result?.Principal不為空即登錄成功
59 if (result?.Principal != null)
60 {
61 httpContext.User = result.Principal;
62 //許可權中是否存在請求的url
63 if (_permissions!=null&&_permissions.GroupBy(g => g.Url).Where(w => w.Key.ToLower() == questUrl).Count() > 0)
64 {
65 var name = httpContext.User.Claims.SingleOrDefault(s => s.Type == requirement.ClaimType).Value;
66 //驗證許可權
67 if (_permissions.Where(w => w.Name == name && w.Url.ToLower() == questUrl).Count() == 0)
68 {
69 //無許可權跳轉到拒絕頁面 
70 httpContext.Response.Redirect(requirement.DeniedAction);
71 context.Succeed(requirement);
72 return;
73 }
74 }
75 //判斷過期時間
76 if (DateTime.Parse(httpContext.User.Claims.SingleOrDefault(s => s.Type == ClaimTypes.Expiration).Value) >= DateTime.Now)
77 {
78 context.Succeed(requirement);
79 }
80 else
81 {
82 context.Fail();
83 }
84 return;
85 }
86 }
87 //判斷沒有登錄時,是否訪問登錄的url,並且是Post請求,並且是form表單提交類型,否則為失敗
88 if (!questUrl.Equals(requirement.LoginPath.ToLower(), StringComparison.Ordinal) && (!httpContext.Request.Method.Equals("POST")
89 || !httpContext.Request.HasFormContentType))
90 {
91 context.Fail();
92 return;
93 }
94 context.Succeed(requirement);
95 }
96 }
97 }
View Code

JwtToken.cs

 1 using System;
 2 using System.IdentityModel.Tokens.Jwt;
 3 using System.Security.Claims;
 4 
 5 namespace Ocelot.JWTAuthorizePolicy
 6 {
 7 /// <summary>
 8 /// JWTToken生成類
 9 /// </summary>
10 public class JwtToken
11 {
12 /// <summary>
13 /// 獲取基於JWT的Token
14 /// </summary>
15 /// <param name="username"></param>
16 /// <returns></returns>
17 public static dynamic BuildJwtToken(Claim[] claims, PermissionRequirement permissionRequirement)
18 {
19 var now = DateTime.UtcNow;
20 var jwt = new JwtSecurityToken(
21 issuer: permissionRequirement.Issuer,
22 audience: permissionRequirement.Audience,
23 claims: claims,
24 notBefore: now,
25 expires: now.Add(permissionRequirement.Expiration),
26 signingCredentials: permissionRequirement.SigningCredentials
27 );
28 var encodedJwt = new JwtSecurityTokenHandler().WriteToken(jwt);
29 var responseJson = new
30 {
31 Status = true,
32 access_token = encodedJwt,
33 expires_in = permissionRequirement.Expiration.TotalMilliseconds,
34 token_type = "Bearer"
35 };
36 return responseJson;
37 }
38 }
39 }
View Code

OcelotJwtBearerExtension.cs,本類型中的方法分別用於網關,web服務,和驗證服務,請參看註釋

  1 using Microsoft.AspNetCore.Authentication;
  2 using Microsoft.AspNetCore.Authorization;
  3 using Microsoft.Extensions.DependencyInjection;
  4 using Microsoft.IdentityModel.Tokens;
  5 using System;
  6 using System.Collections.Generic;
  7 using System.Security.Claims;
  8 using System.Text;
  9 
 10 namespace Ocelot.JWTAuthorizePolicy
 11 {
 12 /// <summary>
 13 /// Ocelot下JwtBearer擴展
 14 /// </summary>
 15 public static class OcelotJwtBearerExtension
 16 {
 17 /// <summary>
 18 /// 註入Ocelot下JwtBearer,在ocelot網關的Startup的ConfigureServices中調用
 19 /// </summary>
 20 /// <param name="services">IServiceCollection</param>
 21 /// <param name="issuer">發行人</param>
 22 /// <param name="audience">訂閱人</param>
 23 /// <param name="secret">密鑰</param>
 24 /// <param name="defaultScheme">預設架構</param>
 25 /// <param name="isHttps">是否https</param>
 26 /// <returns></returns>
 27 public static AuthenticationBuilder AddOcelotJwtBearer(this IServiceCollection services, string issuer, string audience, string secret, string defaultScheme, bool isHttps = false)
 28 {
 29 var keyByteArray = Encoding.ASCII.GetBytes(secret);
 30 var signingKey = new SymmetricSecurityKey(keyByteArray);
 31 var tokenValidationParameters = new TokenValidationParameters
 32 {
 33 ValidateIssuerSigningKey = true,
 34 IssuerSigningKey = signingKey,
 35 ValidateIssuer = true,
 36 ValidIssuer = issuer,//發行人
 37 ValidateAudience = true,
 38 ValidAudience = audience,//訂閱人
 39 ValidateLifetime = true,
 40 ClockSkew = TimeSpan.Zero,
 41 RequireExpirationTime = true,
 42 };
 43 return services.AddAuthentication(options =>
 44 {
 45 options.DefaultScheme = defaultScheme;
 46 })
 47 .AddJwtBearer(defaultScheme, opt =>
 48 {
 49 //不使用https
 50 opt.RequireHttpsMetadata = isHttps;
 51 opt.TokenValidationParameters = tokenValidationParameters;
 52 });
 53 }
 54 
 55 /// <summary>
 56 /// 註入Ocelot jwt策略,在業務API應用中的Startup的ConfigureServices調用
 57 /// </summary>
 58 /// <param name="services">IServiceCollection</param>
 59 /// <param name="issuer">發行人</param>
 60 /// <param name="audience">訂閱人</param>
 61 /// <param name="secret">密鑰</param>
 62 /// <param name="defaultScheme">預設架構</param>
 63 /// <param name="policyName">自定義策略名稱</param>
 64 /// <param name="deniedUrl">拒絕路由</param>
 65 /// <param name="isHttps">是否https</param>
 66 /// <returns></returns>
 67 public static AuthenticationBuilder AddOcelotPolicyJwtBearer(this IServiceCollection services, string issuer, string audience, string secret, string defaultScheme, string policyName, string deniedUrl, bool isHttps = false)
 68 {
 69 
 70 var keyByteArray = Encoding.ASCII.GetBytes(secret);
 71 var signingKey = new SymmetricSecurityKey(keyByteArray);
 72 var tokenValidationParameters = new TokenValidationParameters
 73 {
 74 ValidateIssuerSigningKey = true,
 75 IssuerSigningKey = signingKey,
 76 ValidateIssuer = true,
 77 ValidIssuer = issuer,//發行人
 78 ValidateAudience = true,
 79 ValidAudience = audience,//訂閱人
 80 ValidateLifetime = true,
 81 ClockSkew = TimeSpan.Zero,
 82 RequireExpirationTime = true,
 83 
 84 };
 85 var signingCredentials = new SigningCredentials(signingKey, SecurityAlgorithms.HmacSha256);
 86 //如果第三個參數,是ClaimTypes.Role,上面集合的每個元素的Name為角色名稱,如果ClaimTypes.Name,即上面集合的每個元素的Name為用戶名
 87 var permissionRequirement = new PermissionRequirement(
 88 deniedUrl,
 89 ClaimTypes.Role,
 90 issuer,
 91 audience,
 92 signingCredentials,
 93 expiration: TimeSpan.FromHours(10)
 94 );
 95 //註入授權Handler
 96 services.AddSingleton<IAuthorizationHandler, PermissionHandler>();
 97 services.AddSingleton(permissionRequirement);
 98 return services.AddAuthorization(options =>
 99 {
100 options.AddPolicy(policyName,
101 policy => policy.Requirements.Add(permissionRequirement));
102 
103 })
104 .AddAuthentication(options =>
105 {
106 options.DefaultScheme = defaultScheme;
107 })
108 .AddJwtBearer(defaultScheme, o =>
109 {
110 //不使用https
111 o.RequireHttpsMetadata = isHttps;
112 o.TokenValidationParameters = tokenValidationParameters;
113 });
114 }
115 /// <summary>
116 /// 註入Token生成器參數,在token生成項目的Startup的ConfigureServices中使用
117 /// </summary>
118 /// <param name="services">IServiceCollection</param>
119 /// <param name="issuer">發行人</param>
120 /// <param name="audience">訂閱人</param>
121 /// <param name="secret">密鑰</param>
122 /// <param name="deniedUrl">拒絕路由</param>
123 /// <returns></returns>
124 public static IServiceCollection AddJTokenBuild(this IServiceCollection services, string issuer, string audience, string secret, string deniedUrl)
125 {
126 var signingCredentials = new SigningCredentials(new SymmetricSecurityKey(Encoding.ASCII.GetBytes(secret)), SecurityAlgorithms.HmacSha256);
127 //如果第三個參數,是ClaimTypes.Role,上面集合的每個元素的Name為角色名稱,如果ClaimTypes.Name,即上面集合的每個元素的Name為用戶名
128 var permissionRequirement = new PermissionRequirement(
129 deniedUrl,
130 ClaimTypes.Role,
131 issuer,
132 audience,
133 signingCredentials,
134 expiration: TimeSpan.FromHours(10)
135 );
136 return services.AddSingleton(permissionRequirement);
137 
138 }
139 
140 }
141 }
View Code

接下來看AuthenticationAPI項目:

appsettings.json

{
"Logging": {
"IncludeScopes": false,
"Debug": {
"LogLevel": {
"Default": "Information"
}
},
"Console": {
"LogLevel": {
"Default": "Information"
}
}
},
"Audience": {
"Secret": "ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890",
"Issuer": "gsw",
"Audience": "everone"
}
}

Startup.cs

 1 using Microsoft.AspNetCore.Builder;
 2 using Microsoft.AspNetCore.Hosting;
 3 using Microsoft.Extensions.Configuration;
 4 using Microsoft.Extensions.DependencyInjection;
 5 using Ocelot.JWTAuthorizePolicy;
 6 
 7 namespace AuthenticationAPI
 8 {
 9 public class Startup
10 {
11 public Startup(IConfiguration configuration)
12 {
13 Configuration = configuration;
14 }
15 public IConfiguration Configuration { get; }
16 public void ConfigureServices(IServiceCollection services)
17 {
18 var audienceConfig = Configuration.GetSection("Audience");
19 //註入OcelotJwtBearer
20 services.AddJTokenBuild(audienceConfig["Issuer"], audienceConfig["Issuer"], audienceConfig["Secret"], "/api/denied");
21 services.AddMvc();
22 }
23 public void Configure(IApplicationBuilder app, IHostingEnvironment env)
24 {
25 if (env.IsDevelopment())
26 {
27 app.UseDeveloperExceptionPage();
28 }
29 app.UseMvc();
30 }
31 }
32 }
View Code

PermissionController.cs

 1 using System;
 2 using Microsoft.AspNetCore.Mvc;
 3 using Microsoft.AspNetCore.Authorization;
 4 using System.Security.Claims;
 5 using Microsoft.AspNetCore.Authentication.JwtBearer;
 6 using	   

您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 下麵有一個字元串陣列: 當你接到這個問題時,你是怎樣解決寫實現呢?直接寫代碼?還是運行面向對象的思維來開發呢?既然有此一問,下麵Insus.NET分享自己的實現方法:創建一個對象,即代字元串陣列中每一個元素的對象: class Item { private int _Index; public in ...
  • using System;using System.Collections.Generic;using System.ComponentModel;using System.Data;using System.Drawing;using System.Linq;using System.Text;u ...
  • 使用.net內置的壓縮解壓縮程式,解壓程式集嵌入的ZIP資源文件 ...
  • 小伙伴們在使用ICP提供的各種能力進行集成開發時常常會遇到一些技術上的困擾,例如ICP中很多介面是通過OCX控制項的方式提供的,如何調用這些介面,就成了一個不大不小的問題,畢竟開髮指南上可沒這些內容啊~彆著急,今天我就給大家介紹一下C#中調用OCX介面的常用方法。^_^y原文鏈接 http://dev... ...
  • 本文為原創文章、源代碼為原創代碼,如轉載/複製,請在網頁/代碼處明顯位置標明原文名稱、作者及網址,謝謝! 開發工具:VS2017 語言:C# DotNet版本:.Net FrameWork 4.0及以上 一、使用的WIN32 API有兩個,一個為ReleaseCapture,另外一個為SendMes ...
  • 按標題的要求將一個字元轉換為整數。實現此功能,也有好幾個方法方法一:Convert.ToInt32(string); 運行代碼: 方法二: int.Parse(object): 運行結果: 這個字元正好是數字的字元串,使用int.Parse()是沒有任何問題,但是如果這個是非數字的字元串呢? 運行時 ...
  • You'll have to perform a number of steps that are normally taken of automatically when you use the toolbox. First and foremost, you have to run the Ax... ...
  • 網關的作用之一,就是有統一的數據出入口,基於這個功能,我們可以在網關上配置監控,從而把所有web服務的請求應答基本數據捕獲並展顯出來。 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...