ASP.NET Core Ocelot+Consul+Nginx+JWT 构建微服务鉴权中心

目录

ASP.NET Core Ocelot+Consul+Nginx+JWT 构建微服务鉴权中心

  1. 构建鉴权中心 通过webapi的形式给微服务颁发可以登录的有效JWT Token
  2. 构建用户微服务 管理用户信息
  3. 构建测试用微服务
  4. 构建网关层,对微服务进行转发和鉴权
  5. 使用Consul 进行服务的注册 发现

访问流程:

Nginx=>3个鉴权中心集群=》访问问User 微服务验证用户正确性=》验证成功鉴权中心颁发有效Token

Nginx=>(网管层)Ocelot 鉴权=》Consul(服务注册发现)=》测试微服务

鉴权中心 Common.AuthenticationCenter

Controllers文件

AuthenticationController.cs

通过访问用户微服务的登录接口,如果登录成功就颁发JWT Token

[Route(api/[controller])] [ApiController] public class AuthenticationController : ControllerBase     {         #region MyRegion          private ILogger<AuthenticationController> _logger = null;         private IJWTService _iJWTService = null;         private readonly IConfiguration _iConfiguration;         private HttpHelperService _HttpHelperService = null;          public AuthenticationController(ILoggerFactory factory,             ILogger<AuthenticationController> logger,             IConfiguration configuration             , IJWTService service             , HttpHelperService httpHelperService)         {             this._logger = logger;             this._iConfiguration = configuration;             this._iJWTService = service;             _HttpHelperService = httpHelperService;         }          #endregion MyRegion          [Route(Get)]         [HttpGet]         public IEnumerable<int> Get()         {             return new List<int>() { 1, 2, 3, 4, 6, 7 };         }          [Route(GetKey)]         [HttpGet]         public string GetKey()         {             string keyDir = Directory.GetCurrentDirectory();             if (RSAHelper.TryGetKeyParameters(keyDir, false, out RSAParameters keyParams) == false)             {                 keyParams = RSAHelper.GenerateAndSaveKey(keyDir, false);             }              return JsonConvert.SerializeObject(keyParams);             //return ;         }          [Route(Login)]         [HttpPost]         public HttpJsonResponse Login([FromForm] string username, [FromForm] string password)         {             User user = _HttpHelperService.VerifyUser(username, password);             if (user is not null)//应该数据库             {                 string token = this._iJWTService.GetToken(username, password, user);                 return HttpJsonResponse.SuccessResult(token);             }             else             {                 return HttpJsonResponse.FailedResult(校验失败);             }         }     } 

Utility 文件夹

Model 文件夹

User.cs

用户微服务的 Model 抽象

public class User     {         /// <summary>         /// 主键ID         /// </summary>         public long Id { get; set; }          /// <summary>         /// 创建时间         /// </summary>         public DateTime CreateTime { get; set; } = DateTime.Now;          /// <summary>         /// 修改时间         /// </summary>         public DateTime UpdateTime { get; set; } = DateTime.Now;          /// <summary>         /// 用户名         /// </summary>         public string UserName { get; set; } = string.Empty;          /// <summary>         /// 密码         /// </summary>         public string Password { get; set; } = string.Empty;          /// <summary>         /// 用户昵称         /// </summary>         public string NickName { get; set; } = string.Empty;          /// <summary>         /// 用户部门ID         /// </summary>         public long DepartmentId { get; set; } = -1;          /// <summary>         /// 用户头像         /// </summary>         public string Avatar { get; set; } = string.Empty;          /// <summary>         /// 是否是老师         /// </summary>         public bool IsTeacher { get; set; } = false;          /// <summary>         /// 用户规则ID 测试期间 方便测试暂不关联规则表 -1表示普通用户具有查询权限 0代表管理员具有增加 删除 修改权限         /// </summary>         public long RoleId { get; set; } = -1;     } 

RSA 文件夹

RSAHelper.cs

public class RSAHelper     {         /// <summary>         /// 从本地文件中读取用来签发 Token 的 RSA Key         /// </summary>         /// <param name=filePath>存放密钥的文件夹路径</param>         /// <param name=withPrivate></param>         /// <param name=keyParameters></param>         /// <returns></returns>         public static bool TryGetKeyParameters(string filePath, bool withPrivate, out RSAParameters keyParameters)         {             string filename = withPrivate ? key.json : key.public.json;             string fileTotalPath = Path.Combine(filePath, filename);             keyParameters = default(RSAParameters);             if (!File.Exists(fileTotalPath))             {                 return false;             }             else             {                 keyParameters = JsonConvert.DeserializeObject<RSAParameters>(File.ReadAllText(fileTotalPath));                 return true;             }         }          /// <summary>         /// 生成并保存 RSA 公钥与私钥         /// </summary>         /// <param name=filePath>存放密钥的文件夹路径</param>         /// <returns></returns>         public static RSAParameters GenerateAndSaveKey(string filePath, bool withPrivate = true)         {             RSAParameters publicKeys, privateKeys;             using (var rsa = new RSACryptoServiceProvider(2048))//即时生成             {                 try                 {                     privateKeys = rsa.ExportParameters(true);                     publicKeys = rsa.ExportParameters(false);                 }                 finally                 {                     rsa.PersistKeyInCsp = false;                 }             }             File.WriteAllText(Path.Combine(filePath, key.json), JsonConvert.SerializeObject(privateKeys));             File.WriteAllText(Path.Combine(filePath, key.public.json), JsonConvert.SerializeObject(publicKeys));             return withPrivate ? privateKeys : publicKeys;         }          //public static string GenerateAndSaveKey(string filePath, bool withPrivate = true)         //{         //    //RSAParameters publicKeys, privateKeys;         //    using (var rsa = new RSACryptoServiceProvider(2048))//即时生成         //    {         //        try         //        {         //            //privateKeys = rsa.ExportParameters(true);         //            //publicKeys = rsa.ExportParameters(false);          //            //rsa.ExportRSAPublicKey();         //            //rsa.ExportRSAPrivateKey();          //            string publicKey = rsa.ToXmlString(false);//publickey         //            string privateKey = rsa.ToXmlString(true);//privateKey         //            File.WriteAllText(Path.Combine(filePath, key.json), privateKey);         //            File.WriteAllText(Path.Combine(filePath, key.public.json), publicKey);         //            return withPrivate ? privateKey : publicKey;         //        }         //        finally         //        {         //            rsa.PersistKeyInCsp = false;         //        }         //    }          //}     } 

ConfigInformation.cs

public class ConfigInformation     {         public string RootUrl { get; set; }          public string UserUrl { get; set; }          public JWTTokenOptions JWTTokenOptions { get; set; }     } 

HttpHelperService.cs

/// <summary> /// 就是去调用服务的---暂时没有Consul---ToDo /// </summary> public class HttpHelperService     {         #region Option注入          private readonly ConfigInformation _ConfigInformation;          public HttpHelperService(IOptionsMonitor<ConfigInformation> configInformation)         {             this._ConfigInformation = configInformation.CurrentValue;         }          #endregion Option注入          public User VerifyUser(string name, string password)         {             string requestUrl = ${_ConfigInformation.RootUrl}{_ConfigInformation.UserUrl}?username={name}&password={password};             Console.WriteLine(requestUrl);              HttpResponseMessage sResult = this.HttpRequest(requestUrl, HttpMethod.Get, null);             if (sResult.IsSuccessStatusCode)             {                 string content = sResult.Content.ReadAsStringAsync().Result;                 HttpJsonResponse response = JsonConvert.DeserializeObject<HttpJsonResponse>(content);                 User user = JsonConvert.DeserializeObject<User>(JsonConvert.SerializeObject(response.Data));                 return user;             }             else             {                 return null;             }         }          public HttpResponseMessage HttpRequest(string url, HttpMethod httpMethod, Dictionary<string, string> parameter)         {             using (HttpClient httpClient = new HttpClient())             {                 HttpRequestMessage message = new HttpRequestMessage()                 {                     Method = httpMethod,                     RequestUri = new Uri(url)                 };                 if (parameter != null)                 {                     var encodedContent = new FormUrlEncodedContent(parameter);                     message.Content = encodedContent;                 }                 return httpClient.SendAsync(message).Result;             }         }     } 

IJWTService.cs

/// <summary> /// 封装注入 /// </summary> public interface IJWTService     {         /// <summary>         /// 获取Token         /// </summary>         /// <param name=UserName>账号</param>         /// <param name=password>密码</param>         /// <param name=user>用户信息</param>         /// <returns></returns>         string GetToken(string UserName, string password, User user);     } 

JWTHSService.cs

public class JWTHSService : IJWTService     {         #region Option注入          private readonly JWTTokenOptions _JWTTokenOptions;          public JWTHSService(IOptionsMonitor<ConfigInformation> configInformation)         {             this._JWTTokenOptions = configInformation.CurrentValue.JWTTokenOptions;         }          #endregion Option注入          public string GetToken(string UserName, string password, User user)         {             var claims = new[]             {                  new Claim(username, user.UserName),                  new Claim(id, user.Id.ToString()),                  new Claim(ClaimTypes.Role,user.RoleId.ToString())             };              var key = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(this._JWTTokenOptions.SecurityKey));             var creds = new SigningCredentials(key, SecurityAlgorithms.HmacSha256);             var token = new JwtSecurityToken(                 issuer: this._JWTTokenOptions.Issuer,                 audience: this._JWTTokenOptions.Audience,                 claims: claims,                 expires: DateTime.Now.AddMinutes(60),//5分钟有效期                 notBefore: DateTime.Now.AddMilliseconds(5),//1分钟后有效                 signingCredentials: creds);             string returnToken = new JwtSecurityTokenHandler().WriteToken(token);             return returnToken;         }     } 

JWTRSService.cs

public class JWTRSService : IJWTService     {         #region Option注入          private readonly JWTTokenOptions _JWTTokenOptions;          public JWTRSService(IOptionsMonitor<ConfigInformation> configInformation)         {             this._JWTTokenOptions = configInformation.CurrentValue.JWTTokenOptions;         }          #endregion Option注入          public string GetToken(string userName, string password, User user)         {             string jtiCustom = Guid.NewGuid().ToString();//用来标识 Token             var claims = new[]             {                    new Claim(ClaimTypes.Name, user.UserName),                    new Claim(id, user.Id.ToString()),                    new Claim(ClaimTypes.Role,user.RoleId.ToString())             };             string keyDir = Directory.GetCurrentDirectory();             if (RSAHelper.TryGetKeyParameters(keyDir, true, out RSAParameters keyParams) == false)             {                 keyParams = RSAHelper.GenerateAndSaveKey(keyDir);             }             var credentials = new SigningCredentials(new RsaSecurityKey(keyParams), SecurityAlgorithms.RsaSha256Signature);              #region XML              //string privateKey = RSAHelper.GenerateAndSaveKey(keyDir);             //var  RSA = new RSACryptoServiceProvider();             //RSA.FromXmlString(privateKey);             //var credentials = new SigningCredentials(new RsaSecurityKey(RSA), SecurityAlgorithms.RsaSha256Signature);              #endregion XML              var token = new JwtSecurityToken(                issuer: this._JWTTokenOptions.Issuer,                audience: this._JWTTokenOptions.Audience,                claims: claims,                expires: DateTime.Now.AddMinutes(60),//5分钟有效期                signingCredentials: credentials);             var handler = new JwtSecurityTokenHandler();             string tokenString = handler.WriteToken(token);             return tokenString;         }     } 

JWTTokenOptions.cs

public class JWTTokenOptions     {         public string Audience         {             get;             set;         }          public string SecurityKey         {             get;             set;         }          //public SigningCredentials Credentials         //{         //    get;         //    set;         //}          public string Issuer         {             get;             set;         }     } 

appsettings.json

{   Logging: {     LogLevel: {       Default: Information,       Microsoft: Warning,       Microsoft.Hosting.Lifetime: Information     }   },   AllowedHosts: *,   ConfigInformation: {     RootUrl: http://localhost:10091, //服务调用     UserUrl: /api/userapi/User/validate,     JWTTokenOptions: {       Audience: http://localhost:8761,       Issuer: http://localhost:8761,       SecurityKey: MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDI2a2EJ7m872v0afyoSDJT2o1+SitIeJSWtLJU8/Wz2m7gStexajkeD+Lka6DSTy8gt9UwfgVQo6uKjVLG5Ex7PiGOODVqAEghBuS7JzIYU5RvI543nNDAPfnJsas96mSA7L/mD7RTE2drj6hf3oZjJpMPZUQI/B1Qjb5H3K3PNwIDAQAB     }   } } 

key.json

{D:ayJEcDAFTdAjKtn/wUvAe0z0RtXcOFENJm55PaTbDV8QAKfKKENY5K+nvU36uSi3qh2xP6NVoo3H3rDlk6X8AEuAOQs+arGfHQ/aL4Ob3skuEioHWszXScJ2KTzrrsolOik9SybNLRSMIgQKyZY5URk3BhLqSvMDwBQ2Nht/mlx+eQi1GpPgiJFH77BlRt3O/LKafAtgS292RxeKUJn3Q4dsn1PtJX+PMPT+bn+9PZXpQtSI8r8yUtrFja61WcGN8aJrG47EfT5wa3J/mcfhEK+4hU2uI3ycW+TaNjuxDZ+nAD4k3pcNT6a1ldSi3CnZKR2p/MUh07oazmx2QEg54Q==,DP:t58aASvJT2+mQCi9EN5RksOXrgzGNB2U6PeS8NJ9ht6HiA78+fZKrfbxXxz8i/069Tyg7dkzYeKFd93q9FhFKqsOGE67gqjelKIXFTN2s2DFiJ7neFHkIhPisdS/a+SzHziFsxYHJbWobuHlrDw2QcoYGDsgS1Crbatn7t90Hfs=,DQ:dzpHSw7DD1vwy+mOX5nRJLVniSmcIX8MMWtCXlmzj6CdUddyiGSGFhTB+hjVHLPxsJAzoV4zBFRt1s+CHGlgjhfD6ct58i7bDVG/6OVUI4v95iYiA7kPB44DlOzVjuhlGmTm5Tw5eTwjA3s/5FUuif0DShzt4jam7f+jlTvkXaM=,Exponent:AQAB,InverseQ:MTykln8IgIQ2DwhC4d0d/RXNk5/PvKXSY8goldKfxCiAwTmArivvuxfHC01oKFlZkZbPRVvh0rM9QkM4pX9ITfKd4+VoxmDtMMx5oEkbxKMbJQkUvJeADmtcy/zfXq8ZNSNcIkAI4setydA6tOvRZKuudJ5tEpXOxwTel8U5ltM=,Modulus:o0jSDb5OYfSTPFPjZS67yovVQLEA5OIrey/1mBCH8Xxvo1zLwKPYzWwkRjzSLURZ19V9AeKAiP+JxDtGRzmUflqXY3e7vKeEosk5MoUj4MlBvxVxDL3bdghJaqhARaqsuXQ1dvOGABsDIogBmvCJyJOBHXISLl+hDGIOQSpHqtMFz4UHAF5v62x82oMYT8O4lTfoTSF1+jMH31rCCERXFEz2DUngdsT8gwQncTMrVTS2dIdacvkWmN0yvzLmMqZetv12p10O7jjuN61hlhhccAibGeU3X1veOHS4L9TzQ0rLPK/yTm3QlShWZD8oiLBnNXGhS0m/RTk3Uc7IrvvaqQ==,P:0daJpBirbZIUYZyqeXW6csoy2eKDO81G4DAe0gzyZUk7ZQ97H3sIRdKU05lmeR0KuEtp71LOaljx2MJ1vawF4zoJ3MQEjzQYQS0Gq5zLPrX/Q+Sy/7Brb9oYlfwDzlyszlZqjSyJjupNOAlpkTkytt6a5g6LtD44mo2A9XCteTM=,Q:xzSFkOTiJGyTNatXO8pAxZyGg4qjAweJOL5wv5dGqFF7fWx92uJrMcGy6kda5A3aCE0KG0441fWjGPjzb6GvoTzwADRx4mNhOcVV0gx/lbKydc15KaBNEX29TkmYbG4dRQ5wOs+FBm0PAHcQgK64AFYhobG4w8VZBLxCXdwndLM=} 

Program.cs

var builder = WebApplication.CreateBuilder(args);  // Add services to the container. builder.Services.Configure<ConfigInformation>(builder.Configuration.GetSection(ConfigInformation)); builder.Services.AddTransient<HttpHelperService>(); builder.Services.AddControllers();  #region HS256  builder.Services.AddScoped<IJWTService, JWTHSService>(); //builder.Services.Configure<JWTTokenOptions>(builder.Configuration.GetSection(JWTTokenOptions));  #endregion HS256  #region RS256  //builder.Services.AddScoped<IJWTService, JWTRSService>(); //builder.Services.Configure<JWTTokenOptions>(builder.Configuration.GetSection(JWTTokenOptions));  #endregion RS256  // Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle builder.Services.AddEndpointsApiExplorer(); builder.Services.AddSwaggerGen(); builder.Services.AddCors(options => {     options.AddPolicy(default, policy =>     {         policy.AllowAnyOrigin()             .AllowAnyHeader()             .AllowAnyMethod();     }); }); var app = builder.Build();  // Configure the HTTP request pipeline.  app.UseSwagger(); app.UseSwaggerUI();  app.UseAuthorization(); app.UseCors(default); app.MapControllers();  app.Run(); 

网关 Common.OcelotGateway

appsettings.json

{   Logging: {     LogLevel: {       Default: Information,       Microsoft.AspNetCore: Warning     }   },   AllowedHosts: *,   JWTTokenOptions: {     Audience: http://localhost:8761,     Issuer: http://localhost:8761,     SecurityKey: MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDI2a2EJ7m872v0afyoSDJT2o1+SitIeJSWtLJU8/Wz2m7gStexajkeD+Lka6DSTy8gt9UwfgVQo6uKjVLG5Ex7PiGOODVqAEghBuS7JzIYU5RvI543nNDAPfnJsas96mSA7L/mD7RTE2drj6hf3oZjJpMPZUQI/B1Qjb5H3K3PNwIDAQAB   } } 

OcelotConfiguration.json

{   Routes: [         {       UpstreamPathTemplate: /api/lessonapi/{url},       UpstreamHttpMethod: [         Get,         Post,         Put,         Patch,         Delete,         Options       ],       UserServiceDIscovery: true,       ServiceName: LessonCenter,       LoadBalancerOptions: {         Type: RoundRobin       },       DownstreamPathTemplate: /api/lessonapi/{url},       DownstreamScheme: http,       DownstreamHeaderTransform: {         Access-Control-Allow-Origin: *,         Access-Control-Allow-Methods: *,         Access-Control-Allow-Headers: *       },       AuthenticationOptions: {         AuthenticationProviderKey: UserGatewayKey,         AllowedScopes: []       }     },     {       UpstreamPathTemplate: /lesson/swagger/v1/swagger.json,       UpstreamHttpMethod: [         Get       ],       UseServiceDiscovery: true,       ServiceName: LessonCenter,       LoadBalancerOptions: {         Type: RoundRobin       },       DownstreamPathTemplate: /swagger/v1/swagger.json,       DownstreamScheme: http,       RateLimitOptions: {         ClientWhiteList: [           ajun816,           superhero         ],         EnableRateLimiting: true,         Period: 5m,         PeriodTimespan: 30,         Limit: 5       }     },     {       UpstreamPathTemplate: /api/userapi/{url},       UpstreamHttpMethod: [         Get,         Post,         Put,         Patch,         Delete,         Options       ],       UserServiceDIscovery: true,       ServiceName: UserCenter,       LoadBalancerOptions: {         Type: RoundRobin       },       DownstreamPathTemplate: /api/userapi/{url},       DownstreamScheme: http,       DownstreamHeaderTransform: {         Access-Control-Allow-Origin: *,         Access-Control-Allow-Methods: *,         Access-Control-Allow-Headers: *       }     },     {       UpstreamPathTemplate: /user/swagger/v1/swagger.json,       UpstreamHttpMethod: [         Get       ],       UseServiceDiscovery: true,       ServiceName: UserCenter,       LoadBalancerOptions: {         Type: RoundRobin       },       DownstreamPathTemplate: /swagger/v1/swagger.json,       DownstreamScheme: http,       RateLimitOptions: {         ClientWhiteList: [           ajun816,           superhero         ],         EnableRateLimiting: true,         Period: 5m,         PeriodTimespan: 30,         Limit: 5       }     },    GlobalConfiguration: {     BaseUrl: http://127.0.0.1:8070, //网关对外地址     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     }   } } 

Program.cs

var builder = WebApplication.CreateBuilder(args);  // Add services to the container.  builder.Services.AddControllers(); // Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle builder.Services.AddEndpointsApiExplorer(); builder.Services.AddSwaggerGen(c => {     c.SwaggerDoc(v1, new OpenApiInfo { Title = Common.OcelotGateway, Version = v1 }); });  builder.Host.ConfigureAppConfiguration((hostingContext, config) => {     config.AddJsonFile(OcelotConfiguration.json, optional: true, reloadOnChange: true); });  #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 JWT检验 HS  builder.Services.AddOcelot()                 .AddConsul()                 .AddPolly();  var app = builder.Build();  // Configure the HTTP request pipeline.  app.UseSwagger(); app.UseSwaggerUI(c => {     c.SwaggerEndpoint(/lesson/swagger/v1/swagger.json, 课程 API V1);     c.SwaggerEndpoint(/user/swagger/v1/swagger.json, 用户 API V1); });  app.UseOcelot().Wait();  app.Run(); 

用户微服务 UserMicroservice

Controllers文件夹

UserController.cs

[Route(api/userapi/[controller])] [ApiController] public class UserController : ControllerBase     {         private readonly IUserService? _userService;          public UserController(IUserService? userService)         {             _userService = userService;         }          [HttpGet(all)]         public HttpJsonResponse GetAll()         {             try             {                 var data = _userService?.GetAll<SysUser>();                 return HttpJsonResponse.SuccessResult(data);             }             catch             {                 return HttpJsonResponse.FailedResult();             }         }          [Route(validate)]         [HttpGet]         public HttpJsonResponse ValidateUser(string username, string password)         {             try             {                 var accountInfo = _userService?.ValidateUser(username, password);                 return HttpJsonResponse.SuccessResult(accountInfo);             }             catch (Exception ex)             {                 return HttpJsonResponse.FailedResult(ex.Message);             }         }          [HttpPost(regist)]         public HttpJsonResponse CreateUser(RegisterModel registerModel)         {             try             {                 var accountInfo = _userService?.CreateUser(registerModel);                 return HttpJsonResponse.SuccessResult(accountInfo);             }             catch (Exception ex)             {                 return HttpJsonResponse.FailedResult(ex.Message);             }         }          [HttpPut(update)]         public HttpJsonResponse UpdateUser(RegisterModel registerModel)         {             try             {                 var accountInfo = _userService?.UpdateUser(registerModel);                 return HttpJsonResponse.SuccessResult(accountInfo);             }             catch (Exception ex)             {                 return HttpJsonResponse.FailedResult(ex.Message);             }         }          [HttpDelete(delete/{id})]         public HttpJsonResponse DeleteUser([FromRoute] long id)         {             bool success = _userService?.Delete<SysUser>(id) ?? false;             return success ? HttpJsonResponse.SuccessResult(删除成功) :                 HttpJsonResponse.FailedResult(删除失败);         }     } 

appsettings.json

{   Logging: {     LogLevel: {       Default: Information,       Microsoft.AspNetCore: Warning     }   },   AllowedHosts: *,   ConnectionStrings: {     MySqlConn: Server=111.44.222.111;Database=db_user;Uid=root;Pwd=111111;SslMode=none;   },   CodeFirstSettings: {     Migrate: true, //是否开启同步(是否进行codefirst创建表)     Backup: true, //是否进行备份     ModelPath: UserModel //要进行同步的Model程序集路径   },   SqlSugarSnowFlakeSettings: {     WorkerId: 1   },   ConsulClientOption: {     IP: 111.44.222.111,     Port: 18500,     Datacenter: dc1   },   ConsulRegisterOption: {     IP: 111.44.222.111,     Port: 8761,     GroupName: UserCenter,     HealthCheckUrl: http://111.44.222.111:8761/Health,     Interval: 10,     Timeout: 5,     DergisterCriticalServiceAfter: 20,     Tag: 13   } } 

Program.cs

var builder = WebApplication.CreateBuilder(args);  // 配置牛顿库,让json解析的时候使用我们自定义的解析器 这个解析器不会造成long类型数据的精度损失 builder.Services.AddControllers().AddNewtonsoftJson(options => {     options.SerializerSettings.DateFormatString = yyyy'-'MM'-'dd' 'HH':'mm':'ss;     options.SerializerSettings.ContractResolver = new CustomerJsonResolver(); });  // Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle builder.Services.AddEndpointsApiExplorer(); builder.Services.AddSwaggerGen();  // SqlSugar配置 builder.Services.AddSqlSugarSetup(builder.Configuration); // SqlSugar的雪花ID配置 builder.Services.AddSqlSugarSonwFlakeSetup(builder.Configuration); // SqlSugarCodeFirst设置 builder.Services.AddCodeFirstSetup(builder.Configuration, typeof(BaseModel));  builder.Services.AddTransient<IUserService, UserService>();  var app = builder.Build();  // Configure the HTTP request pipeline. app.UseSwagger(); app.UseSwaggerUI(c => c.SwaggerEndpoint(/swagger/v1/swagger.json, UserMicroservice V1));  app.UseAuthorization();  app.UsePerOptionsRequest();  app.UseHealthCheckMiddleware();  app.MapControllers();  app.UseConsulConfiguration(builder.Configuration).Wait();  app.Run(); 

课程微服务 LessonMicroservice

Controllers文件夹

LessonController.cs

[Route(api/lessonapi/[controller])] [ApiController] public class LessonController : ControllerBase     {         #region 服务注入          private readonly ILessonService? _lessonService;          public LessonController(ILessonService? lessonService)         {             _lessonService = lessonService;         }          #endregion 服务注入          /// <summary>         /// 分页获取数据         /// </summary>         /// <param name=pageIndex></param>         /// <param name=pageSize></param>         /// <returns></returns>         [HttpGet(page)]         public HttpJsonResponse GetPaged(int pageIndex = 1, int pageSize = 10)         {             var data = _lessonService?.GetLessons(pageIndex, pageSize, l => l.CreateTime);             return HttpJsonResponse.SuccessResult(data);         }          /// <summary>         /// 创建课程         /// </summary>         /// <param name=lesson></param>         /// <returns></returns>         [HttpPost(create)]         [Authorize(Roles = 0)]         public HttpJsonResponse Create(Lesson lesson)         {             var data = _lessonService?.CreateLesson(lesson);             return HttpJsonResponse.SuccessResult(data);         }          /// <summary>         /// 按条件筛选数据         /// </summary>         /// <param name=filter></param>         /// <returns></returns>         [HttpPost(filter)]         public HttpJsonResponse GetPagedByFilter([FromBody] LessonFilter filter)         {             var data = _lessonService?.PagedLessonsByFilter(filter.GetFilterExpression(),                 filter.CategoryId, filter.PageIndex, filter.PageSize);             return HttpJsonResponse.SuccessResult(data);         }          /// <summary>         /// 按照Id删除数据         /// </summary>         /// <param name=id></param>         /// <returns></returns>         [HttpDelete(delete/{id})]         [Authorize(Roles = 0)]         public HttpJsonResponse DeleteById([FromRoute] long id)         {             bool success = _lessonService?.DeleteLessonById(id) ?? false;             return success ?                 HttpJsonResponse.SuccessResult(success) :                 HttpJsonResponse.FailedResult(删除课程失败!);         }          /// <summary>         /// 更新数据         /// </summary>         /// <param name=lesson></param>         /// <returns></returns>         [HttpPut(update)]         [Authorize(Roles = 0)]         public HttpJsonResponse Update(Lesson lesson)         {             var data = _lessonService?.Update<Lesson>(lesson);             return HttpJsonResponse.SuccessResult(data);         }     } 

appsettings.json

{   Logging: {     LogLevel: {       Default: Information,       Microsoft.AspNetCore: Warning     }   },   AllowedHosts: *,   ConnectionStrings: {     MySqlConn: Server=111.44.222.111;Database=db_Lesson;Uid=root;Pwd=111111;SslMode=none;   },   CodeFirstSettings: {     Migrate: true, //是否开启同步(是否进行codefirst创建表)     Backup: true, //是否进行备份     ModelPath: LessonModel //要进行同步的Model程序集路径   },   SqlSugarSnowFlakeSettings: {     WorkerId: 1   },   JWTTokenOptions: {     Audience: http://localhost:8761,     Issuer: http://localhost:8761,     SecurityKey: MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDI2a2EJ7m872v0afyoSDJT2o1+SitIeJSWtLJU8/Wz2m7gStexajkeD+Lka6DSTy8gt9UwfgVQo6uKjVLG5Ex7PiGOODVqAEghBuS7JzIYU5RvI543nNDAPfnJsas96mSA7L/mD7RTE2drj6hf3oZjJpMPZUQI/B1Qjb5H3K3PNwIDAQAB   },   //ConsulClientOption: {   //  IP: 111.44.222.111,   //  Port: 18500,   //  Datacenter: dc1   //},   //ConsulRegisterOption: {   //  IP: 111.44.222.111,   //  Port: 8761,   //  GroupName: LessonCenter,   //  HealthCheckUrl: http://111.44.222.111:8761/Health,   //  Interval: 10,   //  Timeout: 5,   //  DergisterCriticalServiceAfter: 20,   //  Tag: 13   //},    //本地测试ConsulClientOption    ConsulClientOption: {     IP: localhost,     Port: 8500,     Datacenter: dc1   },   ConsulRegisterOption: {     IP: localhost,     Port: 8761,     GroupName: LessonCenter,     HealthCheckUrl: http://localhost:8761/Health,     Interval: 10,     Timeout: 5,     DergisterCriticalServiceAfter: 20,     Tag: 13   } } 

Program.cs

var builder = WebApplication.CreateBuilder(args);  // Add services to the container. // 配置牛顿库,让json解析的时候使用我们自定义的解析器 这个解析器不会造成long类型数据的精度损失 builder.Services.AddControllers().AddNewtonsoftJson(options => {     options.SerializerSettings.DateFormatString = yyyy'-'MM'-'dd' 'HH':'mm':'ss;     options.SerializerSettings.ContractResolver = new CustomerJsonResolver(); });  // Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle builder.Services.AddEndpointsApiExplorer(); builder.Services.AddSwaggerGen();  // SqlSugar设置 builder.Services.AddSqlSugarSetup(builder.Configuration); // SqlSugar CodeFirst设置 builder.Services.AddCodeFirstSetup(builder.Configuration, typeof(BaseModel)); // SqlSugar 雪花ID设置 builder.Services.AddSqlSugarSonwFlakeSetup(builder.Configuration);  // 服务注入 builder.Services.AddTransient<ILessonService, LessonService>();  #region jwt校验  HS  JWTTokenOptions tokenOptions = new JWTTokenOptions(); builder.Configuration.Bind(JWTTokenOptions, tokenOptions);  builder.Services .AddAuthentication(JwtBearerDefaults.AuthenticationScheme)//Bearer Scheme .AddJwtBearer(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 jwt校验  HS  var app = builder.Build();  // Configure the HTTP request pipeline.  app.UseSwagger(); app.UseSwaggerUI(c => c.SwaggerEndpoint(/swagger/v1/swagger.json, CommentMicroService V1));  app.UsePerOptionsRequest();  app.UseHealthCheckMiddleware();  app.UseAuthentication(); app.UseAuthorization();  app.MapControllers();  app.UseConsulConfiguration(builder.Configuration).Wait();  app.Run();