源码及系列文章目录
Git 源码 :https://github.com/tangsong1995/TS.Microservices
CSDN 资源 :https://download.csdn.net/download/qq_33649351/34675095
系列文章目录 :https://blog.csdn.net/qq_33649351/article/details/120998558
什么是 BFF
BFF,即 Backend For Frontend(服务于前端的后端),也就是服务器设计 API 时会考虑前端的使用,并在服务端直接进行业务逻辑的处理。主要是负责服务聚合,便于前端使用。
网关
网关架构类型
直连模式:
在直连模式下,客户端直接连接微服务,类似于面向服务架构。
共享网关模式:
客户端通过网关来调用微服务,统一入口。
共享网关+聚合服务模式:
聚合服务负责跨服务件的数据组装。
专用网关模式:
在专用网关模式下,为每个客户端提供专用的网关;并且能够根据不同的客户端业务提供对应的接口,便于分类管理、故障隔离等。
基于 Ocelot 打造网关
首先需要 nuget 添加 Ocelot 包:
配置路由策略:
"Routes": [
{
"DownstreamPathTemplate": "/api/{everything}",
"DownstreamScheme": "http",
"DownstreamHostAndPorts": [
{
"Host": "localhost",
"Port": 5004
}
],
"UpstreamPathTemplate": "/mobileAgg/api/{everything}",
"UpstreamHttpMethod": []
},
{
"DownstreamPathTemplate": "/api/{everything}",
"DownstreamScheme": "http",
"DownstreamHostAndPorts": [
{
"Host": "localhost",
"Port": 5000
}
],
"UpstreamPathTemplate": "/mobile/api/{everything}",
"UpstreamHttpMethod": []
}
]
以上规则的作用是将 /mobileAgg/api 路由至 http://localhost:5004 ,将 /mobile/api 路由至 http://localhost:5000 。
配置还有很多属性,例如:
- Priority :定义匹配的顺序,数值越大,优先级越高
- RouteIsCaseSensitive:路由匹配区分大小写,为 true 时区分,默认 false 不区分
- … …
注册 Ocelot :
services.AddOcelot(Configuration);
在 Startup 的 Configure 方法中最后添加:
app.UseOcelot().Wait();
到此 Ocelot 就配置完成了,让我们来测试一下。
添加测试代码:
namespace TS.Microservices.WebApi.Controllers
{
[Route("api/[controller]/[action]")]
[ApiController]
public class TestController : ControllerBase
{
[HttpGet]
public IActionResult TestOcelot()
{
return Content("TestOcelot TS.Microservices.WebApi");
}
}
}
namespace TS.Microservices.Mobile.ApiAggregator.Controllers
{
[Route("api/[controller]/[action]")]
[ApiController]
public class TestController : ControllerBase
{
[HttpGet]
public IActionResult TestOcelot()
{
return Content("TestOcelot TS.Microservices.Mobile.ApiAggregator");
}
}
}
namespace TS.Microservices.Mobile.Gateway.Controllers
{
[Route("api/[controller]/[action]")]
[ApiController]
public class TestController : ControllerBase
{
[HttpGet]
public IActionResult TestOcelot()
{
return Content("TestOcelot TS.Microservices.Mobile.Gateway");
}
}
}
启动项目并分别请求以下 URL ,可以看到 Ocelot 配置生效:
https://localhost:5003/api/test/TestOcelot
https://localhost:5003/mobileAgg/api/test/TestOcelot
https://localhost:5003/mobile/api/test/TestOcelot
JWT
JWT:JSON Web Tokens,是一种无状态 JSON 格式网络令牌。
JWT 数据结构
- Header,令牌类型、加密类型等信息
- Payload,表示令牌内容,预定义了部分字段信息,支持自定义
- Signature,根据 Header、Payload 和 私有密钥计算出来的签名
使用 JWT 实现身份认证与授权
添加包:Microsoft.AspNetCore.Authentication.JwtBearer
配置身份认证:
public void ConfigureServices(IServiceCollection services)
{
var secrityKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(Configuration["SecurityKey"]));
services.AddSingleton(secrityKey);
services.AddAuthentication(options =>
{
options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
options.DefaultScheme = JwtBearerDefaults.AuthenticationScheme;
}).AddJwtBearer(JwtBearerDefaults.AuthenticationScheme, options =>
{
options.TokenValidationParameters = new TokenValidationParameters
{
ValidateIssuer = true,//是否验证Issuer
ValidateAudience = true,//是否验证Audience
ValidateLifetime = true,//是否验证失效时间
ClockSkew = TimeSpan.FromSeconds(30),//失效时间的偏离时间,在失败后的指定时间内有效
ValidateIssuerSigningKey = true,//是否验证SecurityKey
ValidAudience = "localhost",//Audience
ValidIssuer = "localhost",//Issuer
IssuerSigningKey = secrityKey//拿到SecurityKey
};
});
}
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
app.UseHttpsRedirection();
app.UseRouting();
app.UseAuthentication();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
});
app.UseOcelot().Wait();
}
添加 Account 控制器:
[ApiController]
[Route("account/[action]")]
public class AccountController : Controller
{
public async Task<string> Login()
{
return await Task.FromResult("请先登录");
}
public async Task<IActionResult> JwtLogin([FromServices] SymmetricSecurityKey securityKey, string userName)
{
List<Claim> claims = new List<Claim>();
claims.Add(new Claim("Name", userName));
var creds = new SigningCredentials(securityKey, SecurityAlgorithms.HmacSha256);
var token = new JwtSecurityToken(
issuer: "localhost",
audience: "localhost",
claims: claims,
expires: DateTime.Now.AddMinutes(30),
signingCredentials: creds);
var t = new JwtSecurityTokenHandler().WriteToken(token);
return Content(t);
}
}
使用 [Authorize] 标签注明接口需要认证:
[HttpGet]
[Authorize]
public IActionResult TestJwt()
{
return Content(User.FindFirst("Name").Value);
}
[HttpGet]
[Authorize(AuthenticationSchemes = JwtBearerDefaults.AuthenticationScheme)]
public IActionResult TestJwt1()
{
return Content(User.FindFirst("Name").Value);
}
注意事项
- Payload 信息不宜过大
- Payload 不宜存储敏感信息