请选择 进入手机版 | 继续访问电脑版

马上加入IBC程序猿 各种源码随意下,各种教程随便看! 注册 每日签到 加入编程讨论群

C#教程 ASP.NET教程 C#视频教程程序源码享受不尽 C#技术求助 ASP.NET技术求助

【源码下载】 社群合作 申请版主 程序开发 【远程协助】 每天乐一乐 每日签到 【承接外包项目】 面试-葵花宝典下载

官方一群:

官方二群:

.net core使用ocelot---第二篇 身份验证

[复制链接]
查看2027 | 回复0 | 2019-8-13 18:15:22 | 显示全部楼层 |阅读模式
<p><strong>简介</strong>原文链接</p>
<p>      .net core使用ocelot---第一篇 简单使用</p>
<p>         接上文,我将继续介绍使用asp.net core 创建API网关,重要介绍身份验证(authentication )相关内容。</p>
<p>         API服务是需要保护的资源,我们应该尽可能的保证他们的安全。</p>
<p>         通常,我们会使用aspnet security 来保证我们项目的安全,aspnet security代码库是为asp.net core 设计的安全和授权中间件。已经让事情变得简单。</p>
<p>         那么我们在项目中引入API网关会不会导致巨大的改变?答案是,不会。我们的修改微乎其微,但是却让安全和授权变得简单。</p>
<p>         先看下面的截图。</p>
<p><div align="center"> 182006h2zjsrjeix27dn7d.png </div></p>
<p>  截图显示,当我们访问我们的服务,API网关会让我们首先访问其授权模块。我们必须访问授权服务获得访问令牌(access token),然后用访问令牌访问受保护的服务。</p>
<p>         可能你倾向将授权服务独立,这意味客户端得先访问授权服务获得访问令牌。然后携带令牌访问API网关。毫无疑问这样做没问题,但是我建议将授权服务和其他服务放在一起。</p>
<p>         APIGateway是我们所有服务的入口,对于身份未验证的客户端仅可以访问授权服务。</p>
<p>         OK,开始我们的表演。</p>
<p>         我会使用上一个demo的部分内容,便于理解。</p>
<p><strong>Step1</strong></p>
<table style="width: 100%;" border="1" cellspacing="0" cellpadding="0">
<tbody>
<tr>
<td>
<p><strong>项目名称</strong></p>
</td>
<td>
<p><strong>项目类型</strong></p>
</td>
<td>
<p>描述</p>
</td>
</tr>
<tr>
<td>
<p>APIGateway</p>
</td>
<td>
<p>ASP.NET Core Empty</p>
</td>
<td>
<p>示例的入口</p>
</td>
</tr>
<tr>
<td>
<p>CustomersAPIServices</p>
</td>
<td>
<p>ASP.NET Core Web API</p>
</td>
<td>
<p>API 服务处理消费者的操作</p>
</td>
</tr>
<tr>
<td>
<p>AuthServer</p>
</td>
<td>
<p>ASP.NET Core Web API</p>
</td>
<td>
<p>API 服务处理授权操作</p>
</td>
</tr>
<tr>
<td>
<p>ClientApp</p>
</td>
<td>
<p>Console App</p>
</td>
<td>
<p>控制台程序模拟客户端</p>
</td>
</tr>
</tbody>
</table>
<p>  APIGateway和CustomerAPIServices和上篇文章的例子一样,你可以在APIGatewayBasicDemo获得。</p>
<p><strong>Step2</strong></p>
<p>         创建AuthServer,AuthServer重要是为request请求生成访问令牌(access token),我们需要添加一个方法处理。</p>
  1. [HttpGet]  
  2. public IActionResult Get(string name, string pwd)  
  3. {  
  4.     //just hard code here.  
  5.     if (name == "catcher" && pwd == "123")  
  6.     {  
  7.         var now = DateTime.UtcNow;  
  8.   
  9.         var claims = new Claim[]  
  10.         {  
  11.             new Claim(JwtRegisteredClaimNames.Sub, name),  
  12.             new Claim(JwtRegisteredClaimNames.Jti, Guid.NewGuid().ToString()),  
  13.             new Claim(JwtRegisteredClaimNames.Iat, now.ToUniversalTime().ToString(), ClaimValueTypes.Integer64)  
  14.         };  
  15.   
  16.         var signingKey = new SymmetricSecurityKey(Encoding.ASCII.GetBytes(_settings.Value.Secret));  
  17.         var tokenValidationParameters = new TokenValidationParameters  
  18.         {  
  19.             ValidateIssuerSigningKey = true,  
  20.             IssuerSigningKey = signingKey,  
  21.             ValidateIssuer = true,  
  22.             ValidIssuer = _settings.Value.Iss,  
  23.             ValidateAudience = true,  
  24.             ValidAudience = _settings.Value.Aud,  
  25.             ValidateLifetime = true,  
  26.             ClockSkew = TimeSpan.Zero,  
  27.             RequireExpirationTime = true,  
  28.   
  29.         };  
  30.   
  31.         var jwt = new JwtSecurityToken(  
  32.             issuer: _settings.Value.Iss,  
  33.             audience: _settings.Value.Aud,  
  34.             claims: claims,  
  35.             notBefore: now,  
  36.             expires: now.Add(TimeSpan.FromMinutes(2)),  
  37.             signingCredentials: new SigningCredentials(signingKey, SecurityAlgorithms.HmacSha256)  
  38.         );  
  39.         var encodedJwt = new JwtSecurityTokenHandler().WriteToken(jwt);  
  40.         var responseJson = new  
  41.         {  
  42.             access_token = encodedJwt,  
  43.             expires_in = (int)TimeSpan.FromMinutes(2).TotalSeconds  
  44.         };  
  45.   
  46.         return Json(responseJson);  
  47.     }  
  48.     else  
  49.     {  
  50.         return Json("");  
  51.     }  
  52. }  
复制代码

<p>  在验证用户时。我使用硬编码将用户名写死,由于对于本文这个不是那么重要。</p>
<p>  这样我们就完成了授权服务,现在跑起来。</p>
<p><div align="center"> 182007p6cluc6p5luypl0r.jpg </div></p>
<p><strong>Step3</strong></p>
<p>         回到CustomersAPIServices项目,我们应该保护这个服务。</p>
<p>         修改Startup,我们可以使用授权。在这我用JwtBearer进行授权,我会给TestKey设置默认的授权方案。TestKey我将在下面提到。</p>
  1. public void ConfigureServices(IServiceCollection services)  
  2. {  
  3.     var audienceConfig = Configuration.GetSection("Audience");  
  4.   
  5.     var signingKey = new SymmetricSecurityKey(Encoding.ASCII.GetBytes(audienceConfig["Secret"]));  
  6.     var tokenValidationParameters = new TokenValidationParameters  
  7.     {  
  8.         ValidateIssuerSigningKey = true,  
  9.         IssuerSigningKey = signingKey,  
  10.         ValidateIssuer = true,  
  11.         ValidIssuer = audienceConfig["Iss"],  
  12.         ValidateAudience = true,  
  13.         ValidAudience = audienceConfig["Aud"],  
  14.         ValidateLifetime = true,  
  15.         ClockSkew = TimeSpan.Zero,  
  16.         RequireExpirationTime = true,  
  17.     };  
  18.   
  19.     services.AddAuthentication()  
  20.             .AddJwtBearer("TestKey", x =>  
  21.              {  
  22.                  x.RequireHttpsMetadata = false;  
  23.                  x.TokenValidationParameters = tokenValidationParameters;  
  24.              });  
  25.   
  26.     services.AddMvc();  
  27. }  
  28. public void Configure(IApplicationBuilder app)  
  29. {              
  30.     app.UseAuthentication();  
  31.     app.UseMvc();  
  32. }
复制代码

<p>  接下来,对需要保护的方法,添加Authorize。</p>
  1. [Authorize]  
  2. [HttpGet]  
  3. public IEnumerable<string> Get()  
  4. {  
  5.     return new string[] { "Catcher Wong", "James Li" };  
  6. }  
复制代码

<p><strong>注意</strong></p>
<p>         该项目基于asp.net core 2.0. 如果你的项目是1.X,可能有些不同,建议用迁移迁移到2.0.以上。接下来就是见证奇迹的时候了。</p>
<p><div align="center"> 182007bxo2qo6qxlzs9ns8.jpg </div></p>
<p><strong>Step4</strong></p>
<p>         最重要的步骤来了,在APIGateway中配置授权。</p>
  1. public void ConfigureServices(IServiceCollection services)  
  2. {  
  3.     var audienceConfig = Configuration.GetSection("Audience");  
  4.   
  5.     var signingKey = new SymmetricSecurityKey(Encoding.ASCII.GetBytes(audienceConfig["Secret"]));  
  6.     var tokenValidationParameters = new TokenValidationParameters  
  7.     {  
  8.         ValidateIssuerSigningKey = true,  
  9.         IssuerSigningKey = signingKey,  
  10.         ValidateIssuer = true,  
  11.         ValidIssuer = audienceConfig["Iss"],  
  12.         ValidateAudience = true,  
  13.         ValidAudience = audienceConfig["Aud"],  
  14.         ValidateLifetime = true,  
  15.         ClockSkew = TimeSpan.Zero,  
  16.         RequireExpirationTime = true,  
  17.     };  
  18.   
  19.     services.AddAuthentication()  
  20.             .AddJwtBearer("TestKey", x =>  
  21.              {  
  22.                  x.RequireHttpsMetadata = false;  
  23.                  x.TokenValidationParameters = tokenValidationParameters;  
  24.              });  
  25.   
  26.     services.AddOcelot(Configuration);  
  27. }  
复制代码

<p> </p>
<p>  这个配置的大部分代码和Customer Service一样。</p>
<p>  当Ocelot启动,它会检察ReRoutes 》AuthenticationOptions 》AuthenticationProviderKey 的值,</p>
<p>检查该值是否被授权服务注册,如果没有,Ocelot不会启动,如果有,Ocelot在实行时使用授权服务。</p>
<p>         所以,我们得修改configuration.json,我们需要添加新的节点,并将其值赋为在Startup 类中定义的一样。</p>
  1. {  
  2.     "DownstreamPathTemplate": "/api/customers",  
  3.     "DownstreamScheme": "http",  
  4.     "DownstreamHost": "localhost",  
  5.     "DownstreamPort": 9001,  
  6.     "UpstreamPathTemplate": "/customers",  
  7.     "UpstreamHttpMethod": [ "Get" ],  
  8.     "AuthenticationOptions": {  
  9.         "AuthenticationProviderKey": "TestKey",  
  10.         "AllowedScopes": []  
  11.     }  
  12. }  
复制代码

<p>  启动服务。</p>
<p  style="margin-left: 18.0pt;"> </p>
<p><div align="center"> 182008f3uw4wezz56dauw6.jpg </div></p>
<p ><strong>注意</strong></p>
<p >         当你启动项目时遇到下面的错误,你应该检查你的代码,检察AddJwtBearer 方法是否指明授权方案。</p>
<p ><em>        Unhandled Exception: System.InvalidOperationException: Scheme already exists: Bearer</em></p>
<p ><em>Step5</em></p>
<p >         我们已经准备完毕,我们用我们的客户端模拟APIGateway的某些请求。</p>
<p> </p>
<p >         我们先添加获得访问令牌的方法。</p>
  1. private static string GetJwt()  
  2. {  
  3.     HttpClient client = new HttpClient();  
  4.     client.BaseAddress = new Uri( "http://localhost:9000");  
  5.     client.DefaultRequestHeaders.Clear();  
  6.     var res2 = client.GetAsync("/api/auth?name=catcher&pwd=123").Result;  
  7.     dynamic jwt = JsonConvert.DeserializeObject(res2.Content.ReadAsStringAsync().Result);  
  8.     return jwt.access_token;  
  9. }
复制代码

<p> </p>
<p  style="margin-left: 18.0pt;"> 接下来,编写通过APIGateway访问Customer Service方法的代码。</p>
  1. static void Main(string[] args)  
  2. {  
  3.     HttpClient client = new HttpClient();  
  4.       
  5.     client.DefaultRequestHeaders.Clear();  
  6.     client.BaseAddress = new Uri("http://localhost:9000");  
  7.       
  8.     // 1. without access_token will not access the service  
  9.     //    and return 401 .  
  10.     var resWithoutToken = client.GetAsync("/customers").Result;  
  11.       
  12.     //print something here   
  13.       
  14.     //2. with access_token will access the service  
  15.     //   and return result.  
  16.     client.DefaultRequestHeaders.Clear();  
  17.     var jwt = GetJwt();  
  18.       
  19.     client.DefaultRequestHeaders.Add("Authorization", $"Bearer {jwt}");  
  20.     var resWithToken = client.GetAsync("/customers").Result;  
  21.       
  22.     //print something here   
  23.       
  24.     //3. visit no auth service   
  25.     client.DefaultRequestHeaders.Clear();  
  26.     var res = client.GetAsync("/customers/1").Result;  
  27.       
  28.     //print something here   
  29.       
  30.     Console.Read();  
  31. }  
复制代码

<p> </p>
<p  style="margin-left: 18.0pt;">运行结果。</p>
<p  style="margin-left: 18.0pt;"><div align="center"> 182008dzc2mh8hhhnmy1nm.jpg </div></p>
<p  style="margin-left: 18.0pt;"> </p>
<p>  完工。</p>
<p>  源码在此。</p>
<p><strong>总结</strong></p>
<p>         没啥。</p>
<p> </p><br>来源:<a href="https://www.cnblogs.com/xlxr45/p/11321134.html" target="_blank">https://www.cnblogs.com/xlxr45/p/11321134.html</a><br>免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!
*滑块验证:
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则