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();  
    }  

    运行结果。

     

      完工。

      源码在此

    总结

             没啥。

  • 相关阅读:
    RN-Android构建失败:Caused by: org.gradle.api.ProjectConfigurationException: A problem occurred configuring root project 'AwesomeProject'.
    Android更新包下载成功后不出现安装界面
    真机调试: The application could not be installed: INSTALL_FAILED_TEST_ONLY
    react native 屏幕尺寸转换
    Android Studio生成签名文件,自动签名,以及获取SHA1和MD5值
    React Native安卓真机调试
    git提交代码报错Permission denied, please try again
    The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.
    命令行设置快捷命令
    Linux 常用指令
  • 原文地址:https://www.cnblogs.com/xlxr45/p/11321134.html
Copyright © 2011-2022 走看看