ocelot+consul+identity4的使用demo

Ocelot网关搭建

  • 搭建core控制台项目 本demo采用2.1版本 命名为APPIGateWay
  • 在Nuget包中添加Ocelot引用 选用8.0.0版本
  • 添加Ocelot.json 文件 内容为:
{
  "ReRoutes": [
    {
      "DownstreamPathTemplate": "/api/{url}",//下游地址万能模板
      "DownstreamScheme": "http",
//下游地址以及端口号 
//配置多个是为了实现负载均衡功能 
//注:最好使用IP 而不是localhost 
      "DownstreamHostAndPorts": [
        {
          "Host": "192.168.1.100",
          "Port": 21001
        },
        {
          "Host": "192.168.1.100",
          "Port": 21002
        }
      ],
      "UpstreamPathTemplate": "/api/{url}",//上游地址万能模板
      "UpstreamHttpMethod": [ "Get", "POST" ],//转发的请求类型
      "LoadBalancer": "LeastConnection",//负载均衡模式 
//服务名称 需要和consul中配置的服务名称一致
      "ServiceName": "TestService",
      "UseServiceDiscovery": true,//是否启用服务发现
//身份验证 所需属性 不验证可去除
      "AuthenticationOptions": {
        "AuthenticationProviderKey": "usergateway",//自定义key
        "AllowScopes": [ "TestService" ]//服务名称
      }
    },
//下面为身份验证服务配置
    {
      "DownstreamPathTemplate": "/connect/token",
      "DownstreamScheme": "http",
      "DownstreamHostAndPorts": [
        {
          "Host": "192.168.1.100",
          "Port": 5100
        }
      ],
      "UpstreamPathTemplate": "/connect/token",
      "UpstreamHttpMethod": [ "Get", "POST" ],
      "LoadBalancer": "LeastConnection",
      "ServiceName": "IdentityService",
      "UseServiceDiscovery": true,
      "AuthenticationOptions": {
      }
    }
  ],
//Ocelot全局配置
  "GlobalConfiguration": {
    "BaseUrl": "http://192.168.1.100:5000",//对外地址
//服务发现地址配置
    "ServiceDiscoveryProvider": {
      "Host": "192.168.1.100",
      "Port": 8500

    }

  }
}
View Code
  • 修改Program.cs
using Microsoft.AspNetCore;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Configuration;
using System;

namespace APPIGateWay
{
    class Program
    {
        static void Main(string[] args)
        {
            BuildWebHost(args).Run();
        }
        public static IWebHost BuildWebHost(string[] args) =>
            WebHost.CreateDefaultBuilder(args)
            .ConfigureAppConfiguration((hostingContext, builder) =>
            {
                builder
                .SetBasePath(hostingContext.HostingEnvironment.ContentRootPath)
                .AddJsonFile("Ocelot.json");//添加配置文件
            })
                .UseStartup<Startup>()
            .UseUrls("http://192.168.1.100:5000")//使用指定url
                .Build();
    }
}
View Code
  • 修改Startup.cs
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Ocelot.DependencyInjection;
using Ocelot.Middleware;
using System;
using System.Collections.Generic;
using System.Text;

namespace APPIGateWay
{
    public class Startup
    {
        public Startup(IConfiguration configuration)
        {
            Configuration = configuration;
        }

        public IConfiguration Configuration { get; }

        // This method gets called by the runtime. Use this method to add services to the container.
        public void ConfigureServices(IServiceCollection services)
        {
            //services.AddMvc(); -- no need MVC
            // Ocelot
            services.AddOcelot(Configuration);
            //添加验证逻辑
            services.AddAuthentication()
                .AddIdentityServerAuthentication("usergateway", options => {
                    options.Authority = "http://192.168.1.100:5100";
                    options.ApiName = "TestService";
                    options.SupportedTokens = IdentityServer4.AccessTokenValidation.SupportedTokens.Both;
                    options.ApiSecret = "test";
                    options.RequireHttpsMetadata = false;
                });
            //增加日志
            //.AddOpenTracing(option =>
            //{
            //    //this is the url that the butterfly collector server is running on...
            //    option.CollectorUrl = "http://localhost:9618";
            //    option.Service = "Ocelot";
            //});

        }

        // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
        public void Configure(IApplicationBuilder app, IHostingEnvironment env)
        {
            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
            }

            //app.UseMvc(); -- no need MVC
            // Ocelot
            app.UseOcelot().Wait();

        }
    }
}
View Code

至此 网关部分搭建完毕

添加Consul注册帮助类

  • 创建core 类库项目
  • 添加以下代码
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.NetworkInformation;
using System.Net.Sockets;

namespace ConsulRegisterHelper
{
    public class NetworkHelper
    {
        public static string LocalIPAddress
        {
            get
            {
                UnicastIPAddressInformation mostSuitableIp = null;
                var networkInterfaces = NetworkInterface.GetAllNetworkInterfaces();

                foreach (var network in networkInterfaces)
                {
                    if (network.OperationalStatus != OperationalStatus.Up)
                        continue;
                    var properties = network.GetIPProperties();
                    if (properties.GatewayAddresses.Count == 0)
                        continue;

                    foreach (var address in properties.UnicastAddresses)
                    {
                        if (address.Address.AddressFamily != AddressFamily.InterNetwork)
                            continue;
                        if (IPAddress.IsLoopback(address.Address))
                            continue;
                        return address.Address.ToString();
                    }
                }

                return mostSuitableIp != null
                    ? mostSuitableIp.Address.ToString()
                    : "";
            }
        }

        public static int GetRandomAvaliablePort(int minPort = 1024, int maxPort = 65535)
        {
            Random rand = new Random();
            while (true)
            {
                int port = rand.Next(minPort, maxPort);
                if (!IsPortInUsed(port))
                {
                    return port;
                }
            }
        }

        private static bool IsPortInUsed(int port)
        {
            IPGlobalProperties ipGlobalProps = IPGlobalProperties.GetIPGlobalProperties();
            IPEndPoint[] ipsTCP = ipGlobalProps.GetActiveTcpListeners();

            if (ipsTCP.Any(p => p.Port == port))
            {
                return true;
            }

            IPEndPoint[] ipsUDP = ipGlobalProps.GetActiveUdpListeners();
            if (ipsUDP.Any(p => p.Port == port))
            {
                return true;
            }

            TcpConnectionInformation[] tcpConnInfos = ipGlobalProps.GetActiveTcpConnections();
            if (tcpConnInfos.Any(conn => conn.LocalEndPoint.Port == port))
            {
                return true;
            }

            return false;
        }
    }
}
NetworkHelper.cs
using Consul;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using System;

namespace ConsulRegisterHelper
{
    public static class AppBuilderExtensions
    {
        public static IApplicationBuilder RegisterConsul(this IApplicationBuilder app, IApplicationLifetime lifetime, ServiceEntity serviceEntity)
        {
            var consulClient = new ConsulClient(x => x.Address = new Uri($"http://{serviceEntity.ConsulIP}:{serviceEntity.ConsulPort}"));//请求注册的 Consul 地址
            var httpCheck = new AgentServiceCheck()
            {
                DeregisterCriticalServiceAfter = TimeSpan.FromSeconds(5),//服务启动多久后注册
                Interval = TimeSpan.FromSeconds(3),//健康检查时间间隔,或者称为心跳间隔
                HTTP = $"http://{serviceEntity.IP}:{serviceEntity.Port}{serviceEntity.HealthUrl}",//健康检查地址
                Timeout = TimeSpan.FromSeconds(3)
            };

            // Register service with consul
            var registration = new AgentServiceRegistration()
            {
                Checks = new[] { httpCheck },
                ID = Guid.NewGuid().ToString(),
                Name = serviceEntity.ServiceName,
                Address = serviceEntity.IP,
                Port = serviceEntity.Port,
                Tags = new[] { $"urlprefix-/{serviceEntity.ServiceName}" }//添加 urlprefix-/servicename 格式的 tag 标签,以便 Fabio 识别
            };

            consulClient.Agent.ServiceRegister(registration).Wait();//服务启动时注册,内部实现其实就是使用 Consul API 进行注册(HttpClient发起)
            lifetime.ApplicationStopping.Register(() =>
            {
                consulClient.Agent.ServiceDeregister(registration.ID).Wait();//服务停止时取消注册
            });

            return app;
        }
    }
}
Register.cs
using System;
using System.Collections.Generic;
using System.Text;

namespace ConsulRegisterHelper
{
    public class ServiceEntity
    {
        public ServiceEntity()
        {
            HealthUrl = "/api/health";
        }
        /// <summary>
        /// 服务IP
        /// </summary>
        public string IP { get; set; }
        /// <summary>
        /// 服务端口号
        /// </summary>
        public int Port { get; set; }
        /// <summary>
        /// 服务名称
        /// </summary>
        public string ServiceName { get; set; }
        /// <summary>
        /// 服务发现地址
        /// </summary>
        public string ConsulIP { get; set; }
        /// <summary>
        /// 服务发现端口号
        /// </summary>
        public int ConsulPort { get; set; }
        /// <summary>
        /// 健康检查地址默认为/api/health
        /// </summary>
        public string HealthUrl { get; set; }
    }
}
ServiceEntity.cs

至此帮助类搭建完毕 该帮助类主要是为了方便服务注册使用

身份验证服务搭建

  • 新建空web core项目 命名IdentityService
  • 下载Quickstart 发布版放入 
  • 添加配置文件 appsettings.json
{
  "Service": {
    "Name": "IdentityService",
    "Port": "5100"
  },
  "Consul": {
    "IP": "localhost",
    "Port": "8500"
  },
  "Logging": {
    "IncludeScopes": false,
    "Debug": {
      "LogLevel": {
        "Default": "Warning"
      }
    },
    "Console": {
      "LogLevel": {
        "Default": "Warning"
      }
    }
  }
}
appsettings.json
  • 添加健康检查控制器
  • 添加以下文件
using IdentityServer4.Models;
using IdentityServer4.Test;
using Microsoft.Extensions.Configuration;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;

namespace IdentityService
{
//测试使用内容
    public class InMemoryConfiguration
    {
        public static IConfiguration Configuration { get; set; }
        /// <summary>
        /// Define which APIs will use this IdentityServer
        /// </summary>
        /// <returns></returns>
        public static IEnumerable<ApiResource> GetApiResources()
        {
            return new[]
            {
                new ApiResource("TestService", "测试服务1"),
                new ApiResource("TestService2", "测试服务2")
            };
        }

        /// <summary>
        /// Define which Apps will use thie IdentityServer
        /// </summary>
        /// <returns></returns>
        public static IEnumerable<Client> GetClients()
        {
            return new[]
            {
                new Client
                {
                    ClientId = "c1",
                    ClientSecrets = new [] { new Secret("secret1".Sha256()) },
                    AllowedGrantTypes = GrantTypes.ResourceOwnerPasswordAndClientCredentials,
                    AllowedScopes = new [] { "TestService", "TestService2" }
                },
                new Client
                {
                    ClientId = "c-low",
                    ClientSecrets = new [] { new Secret("clowsecret".Sha256()) },
                    AllowedGrantTypes = GrantTypes.ResourceOwnerPasswordAndClientCredentials,
                    AllowedScopes = new [] { "TestService" }
                }
            };
        }
    }
}
InMemoryConfiguration.cs
using IdentityServer4.Models;
using IdentityServer4.Services;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;

namespace IdentityService
{
    public class ProfileService : IProfileService
    {
        public async Task GetProfileDataAsync(ProfileDataRequestContext context)
        {
            var claims = context.Subject.Claims.ToList();
            context.IssuedClaims = claims.ToList();
        }

        public async Task IsActiveAsync(IsActiveContext context)
        {
            context.IsActive = true;
        }
    }
}
ProfileService.cs
using IdentityServer4.Models;
using IdentityServer4.Validation;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Security.Claims;
using System.Threading.Tasks;

namespace IdentityService
{
    public class ResourceOwnerPasswordValidator : IResourceOwnerPasswordValidator
    {
        public Task ValidateAsync(ResourceOwnerPasswordValidationContext context)
        {
            //ToDo:验证自定义用户
            //LoginUser loginUser = null;
            bool isAuthenticated = context.UserName=="aaa"&&context.Password=="1"? true :false; //loginUserService.Authenticate(context.UserName, context.Password, out loginUser);
            if (!isAuthenticated)
            {
                context.Result = new GrantValidationResult(TokenRequestErrors.InvalidGrant, "账户名密码错误");
            }
            else
            {
                context.Result = new GrantValidationResult(
                    subject: context.UserName,
                    authenticationMethod: "custom",
                    claims: new Claim[] {
                        new Claim("Name", context.UserName),
                        new Claim("Id", ""),
                        new Claim("RealName", ""),
                        new Claim("Email", "")
                    }
                );
            }
            return Task.CompletedTask;
        }
    }
}
ResourceOwnerPasswordValidator.cs
  • 修改以下文件
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Logging;

namespace IdentityService
{
    public class Program
    {
        public static void Main(string[] args)
        {
            BuildWebHost(args).Run();
        }

        public static IWebHost BuildWebHost(string[] args) =>
            WebHost.CreateDefaultBuilder(args)
                .UseStartup<Startup>()
             .UseUrls("http://192.168.1.100:5100")
                .Build();
    }
}
Program.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using ConsulRegisterHelper;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using Microsoft.Extensions.PlatformAbstractions;

namespace IdentityService
{
    public class Startup
    {
        public Startup(IConfiguration configuration)
        {
            Configuration = configuration;
        }

        public IConfiguration Configuration { get; }

        // This method gets called by the runtime. Use this method to add services to the container.
        public void ConfigureServices(IServiceCollection services)
        {
           

            services.AddMvc();
            InMemoryConfiguration.Configuration = this.Configuration;
            services.AddIdentityServer()
           .AddDeveloperSigningCredential()//开发临时证书
            .AddInMemoryClients(InMemoryConfiguration.GetClients())
            .AddInMemoryApiResources(InMemoryConfiguration.GetApiResources())
            .AddResourceOwnerValidator<ResourceOwnerPasswordValidator>()//添加自定义验证
            .AddProfileService<ProfileService>();
        }

        // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
        public void Configure(IApplicationBuilder app, IHostingEnvironment env, IApplicationLifetime lifetime)
        {
            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
            }
            // authentication
            app.UseMvc();
            app.UseIdentityServer();
            //启用UI
            app.UseStaticFiles();
            app.UseMvcWithDefaultRoute();
            // register this service
            app.RegisterConsul(lifetime, new ServiceEntity
            {
                IP = NetworkHelper.LocalIPAddress,
                Port = Convert.ToInt32(Configuration["Service:Port"]),
                ServiceName = Configuration["Service:Name"],
                ConsulIP = Configuration["Consul:IP"],
                ConsulPort = Convert.ToInt32(Configuration["Consul:Port"])
            });
        }
    }
}
Startup.cs

身份验证服务搭建完毕

测试服务搭建

  • 创建TestService1 模板为coreAPi
  • 引用之前创建的ConsulRegisterHelper
  • 添加HealthController.cs 
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;

namespace TestService1.Controllers
{
    [Route("api/[controller]")]
    public class HealthController : Controller
    {
        // GET api/values
        [HttpGet]
        public string Get()
        {
            return "ok";
        }
    }
}
View Code
  • 修改Startup.cs
  public void Configure(IApplicationBuilder app, IHostingEnvironment env, IApplicationLifetime lifetime)
        {
            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
            }

            app.UseMvc();
            // register this service
            app.RegisterConsul(lifetime, new ServiceEntity
            {
                IP = NetworkHelper.LocalIPAddress,
                Port = Convert.ToInt32(Configuration["Service:Port"]),
                ServiceName = Configuration["Service:Name"],
                ConsulIP = Configuration["Consul:IP"],
                ConsulPort = Convert.ToInt32(Configuration["Consul:Port"])
            });
        }
View Code

搭建完毕

其他服务类似于此服务

搭建完毕后可用http://localhost:5000/connect/token 访问获取token 

需要传入 这些参数。

获取到token后 可访问 http://localhost:5000/api/values 获取方法内容

需要在headers中加入 Authorization 并附上定义的前缀+空格+token 即可请求到数据 

附上结果图

参考博客:

微服务系列博客

https://www.cnblogs.com/edisonchou/p/dotnetcore_microservice_foundation_blogs_index.html

token权限控制

https://www.cnblogs.com/jaycewu/p/7791102.html

Ocelot+identity

http://www.cnblogs.com/liyouming/p/9025084.html

猜你喜欢

转载自www.cnblogs.com/nontracey/p/9294692.html
今日推荐