网关其实也是一个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 有效性, 更多细则应该在实例层去做