简体   繁体   English

如何在Dotnet Core中拦截请求令牌Jwt发送到其他API?

[英]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:我将严格按照我的观点做一些假设:

  1. 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 端,您应该使用中间件来接收该令牌,并且该中间件为您执行该处理(从授权标头获取令牌)并解密它而无需付出很大的努力。

  2. 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 用于所有其他微服务,没有问题。

  3. 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;

  4. 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/

  5. 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 通常是:

  • Install Swagger so all my REST APIs would get documented properly to be consumed.安装Swagger以便我所有的 REST API 将得到正确记录以供使用。
  • Use a generator to read the Swagger Open Documentation to get all the requested properly typed on the endpoint (in your case, I would have Swagger on both ends and the .NET side would have a mapping from the Java side. This would eliminate all that WebClient requests you have coded on the .net side). Use a generator to read the Swagger Open Documentation to get all the requested properly typed on the endpoint (in your case, I would have Swagger on both ends and the .NET side would have a mapping from the Java side. This would eliminate all that WebClient请求您在 .net 端编码)。
  • As you did with the middleware any JWT middleware would naturally return 401 - Unauthorized in case the "Authorization" header was not present or was with an invalid or expired bearer token.正如您对中间件所做的那样,任何 JWT 中间件自然会返回 401 - 未经授权,以防“授权”header 不存在或带有无效或过期的承载令牌。

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.

相关问题 Angular 8 + Jwt + [授权] + DotNet Core 2.1 Api + Chrome 发布请求失败,并出现 Z727183C8F28CA 错误 - Angular 8 + Jwt + [Authorize] + DotNet Core 2.1 Api + Chrome post request fails with cors error 如何在单击注销按钮时注销 jwt 令牌,并使用 dotnet core 在 c# 中单击 - how to logout the jwt token while click logout button click in c# using dotnet core Angular + Core API:如何拦截请求响应错误正文 - Angular + Core API: How to intercept request response error body 如何在aspnet.core web api中验证JWT令牌? - How to validate JWT Token in aspnet.core web api? 如何使用ASP.NET Core中的访问令牌向Twitter api发送请求? - How to send request to Twitter api using access token in ASP.NET core? .Net Core API JWT 令牌验证 - .Net Core API JWT Token Validation ASP.NET Core 2.1 API JWT 令牌 Session.id 在每次请求时都会更改 - ASP.NET Core 2.1 API JWT token Session.id changes on every request 如何使用.Net Core cookie中间件ticketdataformat将Jwt令牌从Api保存到C#中的cookie - How to save Jwt token from Api to cookie in c# using .Net Core cookie middleware ticketdataformat 如何使用 JWT 令牌检索 .NET Core API 中的当前用户数据? - How use a JWT token to retrieve current user data in .NET Core API? 如何在 asp.net 核心 api 的服务中获取 JWT 令牌信息? - How to get JWT token information in a Service in asp.net core api?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM