如何在 Dotnet Core 中拦截请求 Token Jwt 以发送到其他 API?
Posted
技术标签:
【中文标题】如何在 Dotnet Core 中拦截请求 Token Jwt 以发送到其他 API?【英文标题】:How to intercept request Token Jwt in Dotnet Core to Send to other API? 【发布时间】:2020-09-09 22:35:11 【问题描述】:我正在尝试在 Dotnet Core 中进行过滤以验证其他登录 (Java) Api 中的令牌 JWT 我做到了。基本的是,因此接收到令牌,过滤器获取令牌 Jwt 并将其发送到验证 在其他 API。我正在尝试做,但我不知道如何做到这一点。我确实用另一种方法制作 但我不知道如何做正确的。
类 SendEmailController.cs:
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
[ApiController]
[Route("[controller]")]
public class SendEmailController: ControllerBase
private readonly IEmailSender emailSender;
public SendEmailController(IEmailSender emailSender)
this.emailSender = emailSender;
[HttpPost]
public async Task<ActionResult> SendEmail(GetEmailDto emailDto)
string header = Request.Headers["Authorization"];
string token = null;
if(header != null && header.Contains("Bearer"))
string [] aux = header.Split(" ");
token = aux.Length > 1 ? aux[1].Trim() : token;
if(token != null && await LoginService.ValidateToken(token) != null)
return Ok(this.emailSender.SendEmailAsync(emailDto));
else
return BadRequest("Email not sended >> ");
LoginService.cs:
using System;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Text;
using System.Threading.Tasks;
public class LoginService
public static async Task<string> ValidateToken(string token)
try
string tokenUrl = Environment.GetEnvironmentVariable("TOKEN_VALIDATE_URL");
HttpClient client = new HttpClient();
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.TryAddWithoutValidation("Content-Type", "application/json; charset=utf-8");
client.DefaultRequestHeaders.Authorization =
new AuthenticationHeaderValue("Bearer", token);
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
return await client.GetStringAsync(tokenUrl);
catch(Exception e)
Console.WriteLine("ERROR >> "+e.Message);
return null;
Startup.cs:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.HttpsPolicy;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using Microsoft.EntityFrameworkCore;
using AutoMapper;
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.IdentityModel.Tokens;
using System.Text;
using System.IdentityModel.Tokens.Jwt;
using System.Security.Claims;
namespace apiEmail
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.AddDbContext<DataContext>();
services.AddCors();
services.AddControllers();
services.AddAutoMapper(typeof(Startup));
services.AddScoped<IEmailService, EmailService>();
services.AddScoped<IAuthRepository, AuthRepository>();
services.AddTransient<IEmailSender, AuthMessageSender>();
services.AddMvc();
var key = Encoding.ASCII.GetBytes(Environment.GetEnvironmentVariable("SECRET_KEY")+" DOTNET DA DEPRESSAO");
services.AddAuthentication(x =>
x.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
x.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
)
.AddJwtBearer(options =>
options.RequireHttpsMetadata = false;
options.SaveToken = true;
options.TokenValidationParameters = new TokenValidationParameters
ValidateIssuerSigningKey = false,
IssuerSigningKey = new SymmetricSecurityKey(key),
ValidateIssuer = false,
ValidateAudience = false
;
);
private static void UpdateDatabase(IApplicationBuilder app)
using (var serviceScope = app.ApplicationServices
.GetRequiredService<IServiceScopeFactory>()
.CreateScope())
using (var context = serviceScope.ServiceProvider.GetService<DataContext>())
context.Database.Migrate();
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IWebHostEnvironment env, DataContext context)
UpdateDatabase(app);
if (env.IsDevelopment())
app.UseDeveloperExceptionPage();
//app.UseHttpsRedirection();
app.UseRouting();
app.UseCors(
options => options
.AllowAnyOrigin()
.AllowAnyMethod()
.AllowAnyHeader()
);
// app.UseAuthentication();
var options = new JwtBearerOptions
Audience = "...",
Authority = "...",
Events = new JwtBearerEvents
OnTokenValidated = context =>
// Add the access_token as a claim, as we may actually need it
var accessToken = context.SecurityToken as JwtSecurityToken;
if (accessToken != null)
Console.Write("Token >>", accessToken);
return Task.CompletedTask;
;
app.UseAuthentication();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
endpoints.MapControllers();
);
context.Database.EnsureCreated();
context.Database.Migrate();
如何在不停留在控制器中的情况下进行此验证,仅在定义的过滤器中进行 startup.cs 与 Java 中的此类过滤器类似?
例子:
@Slf4j
@Component
@AllArgsConstructor(onConstructor = @__(@Autowired))
public class JwtRequestFilter extends OncePerRequestFilter
private JwtUtil jwtUtil;
private LoginService login;
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain)
throws ServletException, IOException
final String authorizationHeader = request.getHeader("Authorization");
String username = null;
String jwt = null;
Users usr = null;
if (authorizationHeader != null && authorizationHeader.startsWith("Bearer "))
jwt = authorizationHeader.substring(7);
username = jwtUtil.extractUsername(jwt);
if (username != null && SecurityContextHolder.getContext().getAuthentication() == null)
if (jwtUtil.isTokenExpired(jwt))
throw new IOException("Token expirado ");
try
usr = login.verifyToken(jwt);
Authentication auth = new UsernamePasswordAuthenticationToken(usr.getEmail(), usr.getSenha());
Set authorities = new HashSet<>();
authorities.add(new SimpleGrantedAuthority(usr.getTipo().toString()));
UsernamePasswordAuthenticationToken usernamePasswordAuthenticationToken
= new UsernamePasswordAuthenticationToken(
auth.getName(), auth.getCredentials(), authorities);
usernamePasswordAuthenticationToken
.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
SecurityContextHolder.getContext().setAuthentication(usernamePasswordAuthenticationToken);
catch (Exception e)
log.error("Error >> ", e);
throw new IOException("Erro ao validar o Token");
chain.doFilter(request, response);
类LoginService.java:
public class LoginService
public Users verifyToken(String token)
RestTemplate restTemplate = new RestTemplate();
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON);
headers.set("Authorization", "Bearer "+token);
HttpEntity<String> entity = new HttpEntity<String>(headers);
return restTemplate.exchange(Assets.API_TOKEN_DATA, HttpMethod.PUT, entity, Users.class).getBody();
谢谢
【问题讨论】:
让我检查一下我是否理解这个问题:您在 .NET 上生成了一个 JWT,并且您希望将其验证为 Java JWT 应用程序,对吗? 我可能错过了一点,但我认为这不是 JWT 的工作方式。我的理解是——你应该得到一个签名的令牌,然后你获取发行者的公钥并在本地验证令牌签名——应该不需要进行更多的 API 调用。鉴于您已经使用AddJwtBearer
- 您可能只需要找到一种方法来让这些额外的颁发者验证工作
嗨@FelipeEsteves,不,我在 emailApi 中收到了一个令牌,我需要将它发送到 LoginApi 进行验证。我在申请标头中收到的令牌,并通过另一种方式在 Controller 中恢复。但是我搜索是否有可能在控制器之前恢复,比如java中的过滤器jwt,如果可能的话,如果可能的话,你能帮我找到方法吗???
嗨@timur,所以有一个登录api来验证令牌是否有效,负责emailApi,我只需要在申请前进行过滤器验证。
这是项目:github.com/RafaelRfs/apiDotnetCoreEmail
【参考方案1】:
@RafaelRfs 我尝试将此作为评论发布,但它比支持的要长,因此我将其发布为答案。
一旦你读到,如果你不考虑答案,请告诉我,我会删除它。
基本上,您需要一个密钥和一种签名(算法)来生成 JWT 令牌。
在您的情况下,您在 .NET Core 上生成了该令牌,这完全没问题,然后您需要将此令牌发送到 Java API,这也应该完全没问题。
从技术上讲,如果您在两个站点上使用相同的密钥和相同的到期时间(.NET 和 Java),那么在 .NET 端生成的令牌应该在 Java 端完全可用。
我会严格按照我的观点做一些假设:
在 java 端,您应该使用中间件来接收该令牌,并且该中间件为您执行该处理(从授权标头中获取令牌)并解密它而无需付出很大的努力。
我有一组微服务,我在我的身份微服务上生成了一个 JWT,这个 JWT 可用于所有其他微服务,没有任何问题。
即使有一个 .NET 应用程序生成该 JWT,如果您使用相同的密钥、相同的算法和相同的过期时间,您也可以在 Java 应用程序上使用该 JWT;
您应该尝试使用这样的中间件在 Java 端实现 JWT。您正在编写大量代码来执行 Java 以多种方式完成的操作:https://auth0.com/blog/implementing-jwt-authentication-on-spring-boot/
所有实现 JWT 的最佳方法,您都不会在控制器上看到任何解密令牌的逻辑,您也不必为此编写额外的代码。您只是在某个时候设置了一些中间件。如果您在这种情况下确实需要编写代码,您可以遵循此示例(具有声明。在 Microsoft Identity Framework + OAuth 上也可以在 .NET 中找到相同的模型):https://developer.okta.com/blog/2018/10/31/jwts-with-java
补充:
我对 REST 通常是:
安装 Swagger,这样我的所有 REST API 都会得到正确记录以供使用。 使用生成器读取 Swagger 开放文档以在端点上正确键入所有请求(在您的情况下,我将在两端使用 Swagger,而 .NET 端将具有来自 Java 端的映射。这将消除您在 .net 端编写的所有 WebClient 请求)。 正如您对中间件所做的那样,任何 JWT 中间件自然会返回 401 - 未经授权,以防“授权”标头不存在或带有无效或过期的不记名令牌。抱歉,解释太长了。希望对您有所帮助。
【讨论】:
以上是关于如何在 Dotnet Core 中拦截请求 Token Jwt 以发送到其他 API?的主要内容,如果未能解决你的问题,请参考以下文章
如何在 ASP .NET Core Web API 中映射回退,以便 Blazor WASM 应用程序仅拦截未发送到 API 的请求
DotNet Core:如何跨平台客户端证书 TLS 身份验证?
dotnet core webapi json-api 兼容查询字符串路由
如何在 dotnet core 中制作自定义身份验证过滤器,如 Iauthentication