假定你有两个程序,认证的Key都一样,需要在服务A调用服务B的接口,要想通过接口认证,你可能想在服务A的请求中将Authorization从请求头中解析出来,并且在call服务B的请求时将token再次添加。
其实没必要这么麻烦,巨硬已经想到了我们的需求并实现了。
以下demo为了方便,所有数据均采用hardcode方式
创建服务A,开放两个接口,一个用来生成JWT,一个用来call服务B
创建服务B,只做一件事情,就是将服务A 的请求头原封不动的返回
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Options;
using Microsoft.IdentityModel.Tokens;
using System.IdentityModel.Tokens.Jwt;
using System.Security.Claims;
using System.Text;
namespace ellisServiceA.Controllers
{
[Route("api/[controller]/[action]")]
[ApiController]
public class EllisController : ControllerBase
{
private readonly IHttpClientFactory _httpClientFactory;
public EllisController(IHttpClientFactory httpClientFactory)
{
_httpClientFactory = httpClientFactory;
}
[HttpGet]
[Authorize]
public async Task<string> testHeader ()
{
HttpClient httpClient = _httpClientFactory.CreateClient("ellisServiceB");
var response = await httpClient.GetAsync("/api/test/get");
return await response.Content.ReadAsStringAsync();
}
[HttpPost]
public async Task<string> GenerateJWTToken([FromBody] User user)
{
string token = await GenerateJSONWebToken(user);
return token;
}
private async Task<string> GenerateJSONWebToken(User userInfo)
{
var securityKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes("thisisasecrettestkey"));
var credentials = new SigningCredentials(securityKey, SecurityAlgorithms.HmacSha256);
var claims = new List<Claim>{
new Claim(ClaimTypes.Name, userInfo.name),
new Claim(ClaimTypes.Email,userInfo.email),
new Claim(JwtRegisteredClaimNames.Jti, Guid.NewGuid().ToString())
};
var token = new JwtSecurityToken("ellis.com",
"ellis.com",
claims,
expires: DateTime.Now.AddMinutes(120),
signingCredentials: credentials);
return new JwtSecurityTokenHandler().WriteToken(token);
}
}
}
GenerateJWTToken 是用来生成token的
创建服务B
using Microsoft.AspNetCore.Mvc;
// For more information on enabling Web API for empty projects, visit https://go.microsoft.com/fwlink/?LinkID=397860
namespace ellisServiceB.Controllers
{
[Route("api/[controller]/[action]")]
[ApiController]
public class TestController : ControllerBase
{
// GET: api/<TestController>
[HttpGet]
public IHeaderDictionary Get()
{
return Request.Headers;
}
}
}
此时请求服务A 的testHeader 接口,可以看到服务B并没有接收到JWT
添加Nuget 包 Microsoft.AspNetCore.HeaderPropagation
并添加如下配置
builder.Services.AddHeaderPropagation(options => options.Headers.Add("Authorization"));
builder.Services.AddHttpClient("ellisServiceB", options => options.BaseAddress = new Uri("http://localhost:5181/")).AddHeaderPropagation();
app.UseHeaderPropagation();
修改后的program.cs 如下
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.IdentityModel.Tokens;
using System.Text;
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();
builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme).AddJwtBearer(opt =>
{
opt.TokenValidationParameters = new Microsoft.IdentityModel.Tokens.TokenValidationParameters
{
ValidateIssuer = true,//是否验证Issuer
ValidateAudience = true,//是否验证Audience
ValidateLifetime = true,//是否验证失效时间
ClockSkew = TimeSpan.FromSeconds(30),
ValidateIssuerSigningKey = true,//是否验证SecurityKey
ValidIssuer = "ellis.com",
ValidAudience = "ellis.com",
IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes("thisisasecrettestkey"))//拿到SecurityKey
};
});
builder.Services.AddHeaderPropagation(options => options.Headers.Add("Authorization"));
builder.Services.AddHttpClient("ellisServiceB", options => options.BaseAddress = new Uri("http://localhost:5181/")).AddHeaderPropagation();
var app = builder.Build();
// Configure the HTTP request pipeline.
if (app.Environment.IsDevelopment())
{
app.UseSwagger();
app.UseSwaggerUI();
}
app.UseHeaderPropagation();
app.UseAuthentication();
app.UseAuthorization();
app.MapControllers();
app.Run();
再次测试就完成了