網關其實也是一個net core 應用程序,和其他鑒權方式一下,所以我們在prgram 的文件直接寫 鑒權方式
#region jwt校驗 HS JWTTokenOptions tokenOptions = new JWTTokenOptions(); builder.Configuration.Bind("JWTTokenOptions", tokenOptions); string authenticationProviderKey = "UserGatewayKey"; builder.Services .AddAuthentication(JwtBearerDefaults.AuthenticationScheme)//Bearer Scheme .AddJwtBearer(authenticationProviderKey, options => { options.TokenValidationParameters = new TokenValidationParameters { //JWT有一些默認的屬性,就是給鑒權時就可以篩選了 ValidateIssuer = true,//是否驗證Issuer ValidateAudience = true,//是否驗證Audience ValidateLifetime = true,//是否驗證失效時間---默認還添加了300s后才過期 ClockSkew = TimeSpan.FromSeconds(0),//token過期后立馬過期 ValidateIssuerSigningKey = true,//是否驗證SecurityKey ValidAudience = tokenOptions.Audience,//Audience,需要跟前面簽發jwt的設置一致 ValidIssuer = tokenOptions.Issuer,//Issuer,這兩項和前面簽發jwt的設置一致 IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(tokenOptions.SecurityKey)),//拿到SecurityKey }; }); #endregion
配置文件如下
//*****************************超時+限流+熔斷+降級+Consul+Polly******************************** { "Routes": [ { "DownstreamPathTemplate": "/api/{url}", //服務地址--url變量 "DownstreamScheme": "http", "UpstreamPathTemplate": "/T/{url}", //網關地址--url變量 "UpstreamHttpMethod": [ "Get", "Post" ], "UseServiceDiscovery": true, "ServiceName": "UserWebAPIService", //consul服務名稱 "LoadBalancerOptions": { "Type": "RoundRobin" //輪詢 LeastConnection-最少連接數的服務器 NoLoadBalance不負載均衡 }, "RateLimitOptions": { "ClientWhitelist": [ "1111", "2222" ], //白名單 ClientId 區分大小寫 "EnableRateLimiting": true, "Period": "5m", //1s, 5m, 1h, 1d "PeriodTimespan": 30, //多少秒之后客戶端可以重試 "Limit": 5 //統計時間段內允許的最大請求數量 }, "AuthenticationOptions": { "AuthenticationProviderKey": "UserGatewayKey", "AllowedScopes": [ "UserWebAPIService", "UserMinimalAPIService" ] }, "RouteClaimsRequirement": { "Role": "Assistant" }, "QoSOptions": { "ExceptionsAllowedBeforeBreaking": 3, //允許多少個異常請求 "DurationOfBreak": 10000, // 熔斷的時間,單位為ms "TimeoutValue": 2000 //單位ms 如果下游請求的處理時間超過多少則自如將請求設置為超時 默認90秒 }, "FileCacheOptions": { "TtlSeconds": 15, "Region": "UserCache" //可以調用Api清理 } } ], "GlobalConfiguration": { "BaseUrl": "http://127.0.0.1:6299", //網關對外地址 "ServiceDiscoveryProvider": { "Host": "127.0.0.1", "Port": 8500, "Type": "Consul" //由Consul提供服務發現 }, "RateLimitOptions": { "QuotaExceededMessage": "Too many requests, maybe later? 11", // 當請求過載被截斷時返回的消息 "HttpStatusCode": 666, // 當請求過載被截斷時返回的http status "ClientIdHeader": "client_id" // 用來識別客戶端的請求頭,默認是 ClientId } } }
UserGatewayKey 是指定一個key 來管理網關的配置文件的路由,來標識 哪些路由是需要鑒權授權的。
AllowedScopes 用來做資源區分的,在用戶信息里面指定這個claim 里面scopes
在生成token 的地方把值寫入進去
private string IssueToken(CurrentUserModel userModel, int second = 600) { var claims = new[] { new Claim("scope", "UserWebAPIService"),//為了微服務的Scope,必須小寫 new Claim(ClaimTypes.Name, userModel.Name), new Claim("EMail", userModel.EMail), new Claim("Account", userModel.Account), new Claim("Age", userModel.Age.ToString()), new Claim("Id", userModel.Id.ToString()), new Claim("Mobile", userModel.Mobile), new Claim(ClaimTypes.Role,userModel.Role), new Claim("Role", "Assistant"),//這個不能默認角色授權,動態角色授權 new Claim("Sex", userModel.Sex.ToString())//各種信息拼裝 }; var key = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(this._JWTTokenOptions.SecurityKey)); var creds = new SigningCredentials(key, SecurityAlgorithms.HmacSha256); /** * Claims (Payload) Claims 部分包含了一些跟這個 token 有關的重要信息。 JWT 標准規定了一些字段,下面節選一些字段: iss: The issuer of the token,token 是給誰的 sub: The subject of the token,token 主題 exp: Expiration Time。 token 過期時間,Unix 時間戳格式 iat: Issued At。 token 創建時間, Unix 時間戳格式 jti: JWT ID。針對當前 token 的唯一標識 除了規定的字段外,可以包含其他任何 JSON 兼容的字段。 * */ var token = new JwtSecurityToken( issuer: this._JWTTokenOptions.Issuer, audience: this._JWTTokenOptions.Audience, claims: claims, expires: DateTime.Now.AddSeconds(second),//10分鍾有效期 notBefore: DateTime.Now,//立即生效 DateTime.Now.AddMilliseconds(30),//30s后有效 signingCredentials: creds); string returnToken = new JwtSecurityTokenHandler().WriteToken(token); return returnToken; }
真實開發時,我們不可能把所有鑒權的規則都放在網關去做,網關不會太細仔的,網關層只檢查token 有效性, 更多細則應該在實例層去做