zoukankan      html  css  js  c++  java
  • .net core使用ocelot---第二篇 身份验证

    简介原文链接

          .net core使用ocelot---第一篇 简单使用

             接上文,我将继续介绍使用asp.net core 创建API网关,主要介绍身份验证(authentication )相关内容。

             API服务是需要保护的资源,我们应该尽可能的保证他们的安全。

             通常,我们会使用aspnet security 来保证我们项目的安全,aspnet security代码库是为asp.net core 设计的安全和授权中间件。已经让事情变得简单。

             那么我们在项目中引入API网关会不会导致巨大的改变?答案是,不会。我们的修改微乎其微,但是却让安全和授权变得简单。

             先看下面的截图。

      截图显示,当我们访问我们的服务,API网关会让我们首先访问其授权模块。我们必须访问授权服务获得访问令牌(access token),然后用访问令牌访问受保护的服务。

             可能你倾向将授权服务独立,这意味客户端得先访问授权服务获得访问令牌。然后携带令牌访问API网关。毫无疑问这样做没问题,但是我建议将授权服务和其他服务放在一起。

             APIGateway是我们所有服务的入口,对于身份未验证的客户端仅可以访问授权服务。

             OK,开始我们的表演。

             我会使用上一个demo的部分内容,便于理解。

    Step1

    项目名称

    项目类型

    描述

    APIGateway

    ASP.NET Core Empty

    示例的入口

    CustomersAPIServices

    ASP.NET Core Web API

    API 服务处理消费者的操作

    AuthServer

    ASP.NET Core Web API

    API 服务处理授权操作

    ClientApp

    Console App

    控制台程序模拟客户端

      APIGateway和CustomerAPIServices和上篇文章的例子一样,你可以在APIGatewayBasicDemo获得。

    Step2

             创建AuthServer,AuthServer主要是为request请求生成访问令牌(access token),我们需要添加一个方法处理。

    [HttpGet]  
    public IActionResult Get(string name, string pwd)  
    {  
        //just hard code here.  
        if (name == "catcher" && pwd == "123")  
        {  
            var now = DateTime.UtcNow;  
      
            var claims = new Claim[]  
            {  
                new Claim(JwtRegisteredClaimNames.Sub, name),  
                new Claim(JwtRegisteredClaimNames.Jti, Guid.NewGuid().ToString()),  
                new Claim(JwtRegisteredClaimNames.Iat, now.ToUniversalTime().ToString(), ClaimValueTypes.Integer64)  
            };  
      
            var signingKey = new SymmetricSecurityKey(Encoding.ASCII.GetBytes(_settings.Value.Secret));  
            var tokenValidationParameters = new TokenValidationParameters  
            {  
                ValidateIssuerSigningKey = true,  
                IssuerSigningKey = signingKey,  
                ValidateIssuer = true,  
                ValidIssuer = _settings.Value.Iss,  
                ValidateAudience = true,  
                ValidAudience = _settings.Value.Aud,  
                ValidateLifetime = true,  
                ClockSkew = TimeSpan.Zero,  
                RequireExpirationTime = true,  
      
            };  
      
            var jwt = new JwtSecurityToken(  
                issuer: _settings.Value.Iss,  
                audience: _settings.Value.Aud,  
                claims: claims,  
                notBefore: now,  
                expires: now.Add(TimeSpan.FromMinutes(2)),  
                signingCredentials: new SigningCredentials(signingKey, SecurityAlgorithms.HmacSha256)  
            );  
            var encodedJwt = new JwtSecurityTokenHandler().WriteToken(jwt);  
            var responseJson = new  
            {  
                access_token = encodedJwt,  
                expires_in = (int)TimeSpan.FromMinutes(2).TotalSeconds  
            };  
      
            return Json(responseJson);  
        }  
        else  
        {  
            return Json("");  
        }  
    }  

      在验证用户时。我使用硬编码将用户名写死,因为对于本文这个不是那么重要。

      这样我们就完成了授权服务,现在跑起来。

    Step3

             回到CustomersAPIServices项目,我们应该保护这个服务。

             修改Startup,我们可以使用授权。在这我用JwtBearer进行授权,我会给TestKey设置默认的授权方案。TestKey我将在下面提到。

    public void ConfigureServices(IServiceCollection services)  
    {  
        var audienceConfig = Configuration.GetSection("Audience");  
      
        var signingKey = new SymmetricSecurityKey(Encoding.ASCII.GetBytes(audienceConfig["Secret"]));  
        var tokenValidationParameters = new TokenValidationParameters  
        {  
            ValidateIssuerSigningKey = true,  
            IssuerSigningKey = signingKey,  
            ValidateIssuer = true,  
            ValidIssuer = audienceConfig["Iss"],  
            ValidateAudience = true,  
            ValidAudience = audienceConfig["Aud"],  
            ValidateLifetime = true,  
            ClockSkew = TimeSpan.Zero,  
            RequireExpirationTime = true,  
        };  
      
        services.AddAuthentication()  
                .AddJwtBearer("TestKey", x =>  
                 {  
                     x.RequireHttpsMetadata = false;  
                     x.TokenValidationParameters = tokenValidationParameters;  
                 });  
      
        services.AddMvc();  
    }  
    public void Configure(IApplicationBuilder app)  
    {              
        app.UseAuthentication();  
        app.UseMvc();  
    } 

      接下来,对需要保护的方法,添加Authorize。

    [Authorize]  
    [HttpGet]  
    public IEnumerable<string> Get()  
    {  
        return new string[] { "Catcher Wong", "James Li" };  
    }  

    注意

             该项目基于asp.net core 2.0. 如果你的项目是1.X,可能有些不同,建议用迁移迁移到2.0.以上。接下来就是见证奇迹的时候了。

    Step4

             最重要的步骤来了,在APIGateway中配置授权。

    public void ConfigureServices(IServiceCollection services)  
    {  
        var audienceConfig = Configuration.GetSection("Audience");  
      
        var signingKey = new SymmetricSecurityKey(Encoding.ASCII.GetBytes(audienceConfig["Secret"]));  
        var tokenValidationParameters = new TokenValidationParameters  
        {  
            ValidateIssuerSigningKey = true,  
            IssuerSigningKey = signingKey,  
            ValidateIssuer = true,  
            ValidIssuer = audienceConfig["Iss"],  
            ValidateAudience = true,  
            ValidAudience = audienceConfig["Aud"],  
            ValidateLifetime = true,  
            ClockSkew = TimeSpan.Zero,  
            RequireExpirationTime = true,  
        };  
      
        services.AddAuthentication()  
                .AddJwtBearer("TestKey", x =>  
                 {  
                     x.RequireHttpsMetadata = false;  
                     x.TokenValidationParameters = tokenValidationParameters;  
                 });  
      
        services.AddOcelot(Configuration);  
    }  

      这个配置的大部分代码和Customer Service一样。

      当Ocelot启动,它会查看ReRoutes 》AuthenticationOptions 》AuthenticationProviderKey 的值,

    检查该值是否被授权服务注册,如果没有,Ocelot不会启动,如果有,Ocelot在执行时使用授权服务。

             所以,我们得修改configuration.json,我们需要添加新的节点,并将其值赋为在Startup 类中定义的一样。

    {  
        "DownstreamPathTemplate": "/api/customers",  
        "DownstreamScheme": "http",  
        "DownstreamHost": "localhost",  
        "DownstreamPort": 9001,  
        "UpstreamPathTemplate": "/customers",  
        "UpstreamHttpMethod": [ "Get" ],  
        "AuthenticationOptions": {  
            "AuthenticationProviderKey": "TestKey",  
            "AllowedScopes": []  
        }  
    }  

      启动服务。

     

    注意

             当你启动项目时遇到下面的错误,你应该检查你的代码,查看AddJwtBearer 方法是否指明授权方案。

            Unhandled Exception: System.InvalidOperationException: Scheme already exists: Bearer

    Step5

             我们已经准备完毕,我们用我们的客户端模拟APIGateway的某些请求。

             我们先添加获得访问令牌的方法。

    private static string GetJwt()  
    {  
        HttpClient client = new HttpClient();  
        client.BaseAddress = new Uri( "http://localhost:9000");  
        client.DefaultRequestHeaders.Clear();  
        var res2 = client.GetAsync("/api/auth?name=catcher&pwd=123").Result;  
        dynamic jwt = JsonConvert.DeserializeObject(res2.Content.ReadAsStringAsync().Result);  
        return jwt.access_token;  
    } 

     接下来,编写通过APIGateway访问Customer Service方法的代码。

    static void Main(string[] args)  
    {  
        HttpClient client = new HttpClient();  
          
        client.DefaultRequestHeaders.Clear();  
        client.BaseAddress = new Uri("http://localhost:9000");  
          
        // 1. without access_token will not access the service  
        //    and return 401 .  
        var resWithoutToken = client.GetAsync("/customers").Result;  
          
        //print something here   
          
        //2. with access_token will access the service  
        //   and return result.  
        client.DefaultRequestHeaders.Clear();  
        var jwt = GetJwt();  
          
        client.DefaultRequestHeaders.Add("Authorization", $"Bearer {jwt}");  
        var resWithToken = client.GetAsync("/customers").Result;  
          
        //print something here   
          
        //3. visit no auth service   
        client.DefaultRequestHeaders.Clear();  
        var res = client.GetAsync("/customers/1").Result;  
          
        //print something here   
          
        Console.Read();  
    }  

    运行结果。

     

      完工。

      源码在此

    总结

             没啥。

  • 相关阅读:
    java如何计算对象的大小
    java多线程实现主线程等待子线程执行完问题
    再次理解多线程线程安全问题(理解java内存模型后)
    关于局部变量在循环里的生存法则
    【CSS3】transform-origin原点旋转
    面向对象编程(本章小结)
    引入在线编程和编译站点
    关于获取素数 一个小程序
    C++ I/O
    HDU2571
  • 原文地址:https://www.cnblogs.com/xlxr45/p/11321134.html
Copyright © 2011-2022 走看看