[英]How to intercept request Token Jwt in Dotnet Core to Send to other API?
I'm trying to do a filter in Dotnet Core to validate a token JWT in other Api of Login(Java) that i did.我正在尝试在 Dotnet Core 中进行过滤,以验证我所做的 Login(Java) 的其他 Api 中的令牌 JWT。 The basic is, thus that received the token, the filter gets the token Jwt and send it to validate in other Api.基本的是,因此收到令牌,过滤器获取令牌 Jwt 并将其发送到其他 Api 进行验证。 I'm trying to do but i don't findind how to do this.我正在尝试做,但我不知道如何做到这一点。 I did make in alternate method but i don't know how to do the correct.我确实采用了替代方法,但我不知道如何做正确的。
Class SendEmailController.cs: Class 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:登录服务.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:启动.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();
}
}
}
How to do this validation without stay in the Controller, only in filter defined in startup.cs with filter like this class in Java?如何在不停留在 Controller 的情况下进行此验证,仅在 startup.cs 中定义的过滤器中使用 Java 中的类似 class 的过滤器?
Example:例子:
@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);
}
}
class LoginService.java: class 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();
}
}
Thanks谢谢
@RafaelRfs I tried to post this as a comment but it is longer than the supported so I posted that as an answer. @RafaelRfs 我尝试将此作为评论发布,但它比支持的要长,因此我将其发布为答案。
Once you read that if you don't consider an answer please let me know and I will delete that.一旦你读到,如果你不考虑答案,请告诉我,我会删除它。
Basically, you need a secret key and a type of signature (algorithm) to generate a JWT token.基本上,您需要一个密钥和一种签名(算法)来生成 JWT 令牌。
In your case, you generated that token on .NET Core, which is totally fine, and then you need to send this token to a Java API, which is supposed to be totally fine as well.在您的情况下,您在 .NET Core 上生成了该令牌,这完全没问题,然后您需要将此令牌发送到 Java API,这应该也完全没问题。
Technically if you use the same secret on both sites and the same expiration time ( .NET and Java ) a token generated on the .NET side is supposed to be totally usable on the Java side. Technically if you use the same secret on both sites and the same expiration time ( .NET and Java ) a token generated on the .NET side is supposed to be totally usable on the Java side.
I will do some suppositions based strictly in my opinion:我将严格按照我的观点做一些假设:
On the java side, you're supposed to use a middleware to receive that token and this middleware you do that processing for you (getting the token from the authorization header) and decrypting it with no big effort necessary.在 java 端,您应该使用中间件来接收该令牌,并且该中间件为您执行该处理(从授权标头获取令牌)并解密它而无需付出很大的努力。
I have a set of microservices that I have a JWT generated on my identity microservice and this JWT is used on all other microservices with no issues.我有一组微服务,在我的身份微服务上生成了一个 JWT,这个 JWT 用于所有其他微服务,没有问题。
Even having a .NET App generating that JWT you may consume that JWT on the Java App if you use the same secret key, the same algorithm and the same expiration time; Even having a .NET App generating that JWT you may consume that JWT on the Java App if you use the same secret key, the same algorithm and the same expiration time;
You should try to use middleware like that to implement the JWT on the Java side.您应该尝试使用这样的中间件在 Java 端实现 JWT。 The way you're doing you are writing a ton of code to do something that is done in several ways for Java: https://auth0.com/blog/implementing-jwt-authentication-on-spring-boot/您正在编写大量代码来执行 Java 的多种方式: https://auth0.com/blog/implementing-jwt-authentication-on-spring-boot/
All the best ways to implement JWT you will not see any logic on the controllers to decrypt the token and you will not have to write additional code for that.实现 JWT 的所有最佳方法,您不会在控制器上看到任何解密令牌的逻辑,并且您不必为此编写额外的代码。 You just set up some middleware at some point.您只是在某个时候设置了一些中间件。 If you in this case really need to code that you may follow this example (which have Claims. The same model can be found to .NET as well on Microsoft Identity Framework + OAuth): https://developer.okta.com/blog/2018/10/31/jwts-with-java如果您在这种情况下确实需要编写代码,您可以遵循此示例(有声明。在 Microsoft Identity Framework + OAuth 上也可以在 .NET 中找到相同的 model): Z5E056C500A1C4B6A7110B50D807BADE//blog. 2018/10/31/jwts-with-java
Additional:额外的:
What I to REST usually is:我对 REST 通常是:
Sorry for long explanation.抱歉,解释太长了。 Hope that helps.希望有帮助。
do you speak portuguese?你会说葡萄牙语吗? Thanks by the answer, i think that's correct i will try to implement the same token and secret key in my applications.感谢您的回答,我认为这是正确的,我将尝试在我的应用程序中实现相同的令牌和密钥。 I was thinking it was necessary to validate the token in the main application, thanks to your answer, now i know i don't need to send the token again to be validated in the login api.我认为有必要在主应用程序中验证令牌,感谢您的回答,现在我知道我不需要再次发送令牌以在登录 api 中进行验证。 I will try to implement it the way you said.我将尝试按照您所说的方式实施它。 Thank you very much for the reply, it was of great help!非常感谢您的回复,对您有很大帮助!
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.