axios 中定义的标头内容类型不起作用

发布于 2025-01-09 06:33:13 字数 13206 浏览 0 评论 0原文

我在将登录前端逻辑(Vue3 + Axios)集成到我的 Java API(使用 Spring Security)时遇到了一些麻烦。

我收到以下错误:

com.fasterxml.jackson.databind.exc.MismatchedInputException: No content to map due to end-of-input
 at [Source: (org.apache.catalina.connector.CoyoteInputStream); line: 1, column: 0]
    at com.fasterxml.jackson.databind.exc.MismatchedInputException.from(MismatchedInputException.java:59) ~[jackson-databind-2.10.2.jar:2.10.2]
    at com.fasterxml.jackson.databind.ObjectMapper._initForReading(ObjectMapper.java:4344) ~[jackson-databind-2.10.2.jar:2.10.2]
    at com.fasterxml.jackson.databind.ObjectMapper._readMapAndClose(ObjectMapper.java:4189) ~[jackson-databind-2.10.2.jar:2.10.2]
    at com.fasterxml.jackson.databind.ObjectMapper.readValue(ObjectMapper.java:3242) ~[jackson-databind-2.10.2.jar:2.10.2]
    at br.com.preferencialsaude.app.JWTLoginFilter.attemptAuthentication(JWTLoginFilter.java:35) ~[classes/:na]
    at org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter.doFilter(AbstractAuthenticationProcessingFilter.java:212) ~[spring-security-web-5.2.1.RELEASE.jar:5.2.1.RELEASE]
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334) ~[spring-security-web-5.2.1.RELEASE.jar:5.2.1.RELEASE]
    at org.springframework.security.web.authentication.logout.LogoutFilter.doFilter(LogoutFilter.java:116) ~[spring-security-web-5.2.1.RELEASE.jar:5.2.1.RELEASE]
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334) ~[spring-security-web-5.2.1.RELEASE.jar:5.2.1.RELEASE]
    at org.springframework.security.web.header.HeaderWriterFilter.doHeadersAfter(HeaderWriterFilter.java:92) ~[spring-security-web-5.2.1.RELEASE.jar:5.2.1.RELEASE]
    at org.springframework.security.web.header.HeaderWriterFilter.doFilterInternal(HeaderWriterFilter.java:77) ~[spring-security-web-5.2.1.RELEASE.jar:5.2.1.RELEASE]
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119) ~[spring-web-5.2.3.RELEASE.jar:5.2.3.RELEASE]
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334) ~[spring-security-web-5.2.1.RELEASE.jar:5.2.1.RELEASE]
    at org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter(SecurityContextPersistenceFilter.java:105) ~[spring-security-web-5.2.1.RELEASE.jar:5.2.1.RELEASE]
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334) ~[spring-security-web-5.2.1.RELEASE.jar:5.2.1.RELEASE]
    at org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter.doFilterInternal(WebAsyncManagerIntegrationFilter.java:56) ~[spring-security-web-5.2.1.RELEASE.jar:5.2.1.RELEASE]
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119) ~[spring-web-5.2.3.RELEASE.jar:5.2.3.RELEASE]
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334) ~[spring-security-web-5.2.1.RELEASE.jar:5.2.1.RELEASE]
    at org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:215) ~[spring-security-web-5.2.1.RELEASE.jar:5.2.1.RELEASE]
    at org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:178) ~[spring-security-web-5.2.1.RELEASE.jar:5.2.1.RELEASE]

调试时,我发现我的 HttpServletRequest 中不存在“Content-Type: application/json”标头,但问题是我实际上正在设置它 在我的 axios 客户端中。

当我从邮递员发出请求时,它工作正常,但是当我尝试从前端应用程序发出请求时,我收到了之前的错误。

我以为这可能是浏览器的问题,但在任何浏览器中都会出现同样的可怕错误。我什至尝试使用 JS Fecth API 发出请求,但行为保持不变。

当我从浏览器发出请求时的 MimeHeaderFields:

host, connection, accept, access-control-request-method, access-control-request-headers,
origin,user-agent, sec-fetch-mode, sec-fetch-site, sec-fetch-dest, referer,
accept-encoding, accept-language

如您所见,没有 Content-Type,但当我从邮递员发出请求时它会出现。

这是我的客户端代码:

async handleSubmit () {
    const response = await axios.post('http://localhost:8080/ws/login',
      { username: this.login, password: this.senha }, { 
        headers: { 
          'Content-Type': 'application/json',
        }
      });

    console.log(response.data)
    localStorage.setItem('token', response.data.token);
}

这是我的后端 Java 过滤器:

import java.io.IOException;
import java.util.Collections;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;

import com.fasterxml.jackson.databind.ObjectMapper;

import br.com.preferencialsaude.app.model.AccountCredentials;
import br.com.preferencialsaude.app.service.TokenAuthenticationService;

public class JWTLoginFilter extends AbstractAuthenticationProcessingFilter {

    protected JWTLoginFilter(String url, AuthenticationManager authManager) {
        super(new AntPathRequestMatcher(url));
        setAuthenticationManager(authManager);
    }

    @Override
    public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response)
            throws AuthenticationException, IOException, ServletException {

        //here is where I get the error, due to the lack of Content-Type header
        AccountCredentials credentials = new ObjectMapper().readValue(request.getInputStream(), AccountCredentials.class);

        UsernamePasswordAuthenticationToken userAuthData =
            new UsernamePasswordAuthenticationToken(credentials.getUsername(), credentials.getPassword(), Collections.emptyList());

        return getAuthenticationManager().authenticate(userAuthData);
    }

这是我在邮递员中得到的结果:

{"token":"eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiJ0aGFseXMiLCJleHAiOjE2NDYzMzM2OTB9.5wYyYs6jwhIsxob99Ubx4b64jIIMjVKXf0bZ_ZS_zhkPtrK0KOgKxOgy0HgxlEdV_F5DTwOeDooqVRouEuAqEA"}

status 代码 200

这是我的 WebSecurityConfig 类:

package br.com.preferencialsaude.app;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpMethod;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.builders.WebSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;

import br.com.preferencialsaude.app.service.MyUserDetailsService;

@Configuration
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter{
    
    private MyUserDetailsService userDetailsService;
    
    public WebSecurityConfig(MyUserDetailsService userDetailsService) {
        this.userDetailsService = userDetailsService;
    }
    
    public BCryptPasswordEncoder passwordEncoder() {
        BCryptPasswordEncoder bCryptPasswordEncoder = new BCryptPasswordEncoder();
        return bCryptPasswordEncoder;
    }
    
    @Autowired
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.userDetailsService(userDetailsService).passwordEncoder(passwordEncoder());
    }
    
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.csrf().disable().authorizeRequests()
            .antMatchers("/", "/login").permitAll()
            .antMatchers(HttpMethod.POST, "/ws/login").permitAll()
            .anyRequest().authenticated()
            .and()
            .addFilterBefore(new JWTLoginFilter("/ws/login", authenticationManager()), UsernamePasswordAuthenticationFilter.class)
            .addFilterBefore(new JWTAuthenticationFilter(), UsernamePasswordAuthenticationFilter.class)
            .formLogin()
                .loginPage("/login")
                .failureUrl("/login?error=true")
                .defaultSuccessUrl("/gerenciador/home", true)
                .usernameParameter("usuario")
                .passwordParameter("senha")
                .and()
            .logout()
                .logoutRequestMatcher(new AntPathRequestMatcher("/gerenciador/logout"))
                .logoutSuccessUrl("/gerenciador/login").and().exceptionHandling()
                .accessDeniedPage("/error");
    }
    
    @Override
    public void configure(WebSecurity web) throws Exception {
        web.ignoring().antMatchers(
           "/resources/**", "/static/**", "/css/**", "/js/**", "/imagens/**",
            "/webfonts/**", "/jasper/**", "/contratos/**",
            "/v2/api-docs", "/swagger-resources/**", "/configuration/ui", "/swagger-ui.html", "/webjars/**",
            "/procedimento/**", "/procedimento/**/**", "/credenciamento/empresa/**", "/credenciamento/pessoa/**",
            "/credenciamento/farmacia/**", "/buscaCep", "/plano/**", "/contrato/empresa/**",
            "/contrato/pessoa-fisica/**", "/rede-credenciada/**", "/ws/rede-credenciada/**", "/ws/endereco/**",
            "/ws/procedimentos/**", "/ws/recuperar-senha/**", "/api/cupons-venda/**", "/atendimento/**",
            "/termos", "/convenio/**", "/ws/agendamento/**", "/ws/consulta/**", "/ws/notificacoes/**", "/ws/avaliacao/**",
            "/ws/imagens/**", "/actuator/**", "/api/enderecos/**", "/api/cadastros-clientes/**", "/api/cidades/**",
            "/api/planos/**", "/api/especialidades-saude/consultas/**", "/api/rede-atendimento/**"
        );
    }
}

这是我的 JWTLoginFilter:

package br.com.preferencialsaude.app;

import java.io.IOException;
import java.util.Collections;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;

import com.fasterxml.jackson.databind.ObjectMapper;

import br.com.preferencialsaude.app.model.AccountCredentials;
import br.com.preferencialsaude.app.service.TokenAuthenticationService;

public class JWTLoginFilter extends AbstractAuthenticationProcessingFilter {

    protected JWTLoginFilter(String url, AuthenticationManager authManager) {
        super(new AntPathRequestMatcher(url));
        setAuthenticationManager(authManager);
    }

    @Override
    public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response)
            throws AuthenticationException, IOException, ServletException {

        AccountCredentials credentials = new ObjectMapper().readValue(request.getInputStream(), AccountCredentials.class);

        UsernamePasswordAuthenticationToken userAuthData =
            new UsernamePasswordAuthenticationToken(credentials.getUsername(), credentials.getPassword(), Collections.emptyList());

        return getAuthenticationManager().authenticate(userAuthData);
    }
    
    @Override
    protected void successfulAuthentication(HttpServletRequest request, HttpServletResponse response,
                                            FilterChain filterChain, Authentication auth) throws IOException, ServletException {
        TokenAuthenticationService.addAuthentication(response, auth.getName());
    }
    
    @Override
    protected void unsuccessfulAuthentication(HttpServletRequest request, HttpServletResponse response,
                                              AuthenticationException failed) throws IOException, ServletException {
        SecurityContextHolder.clearContext();
        TokenAuthenticationService.failAuthentication(response);
    }
}

您是否遇到过类似的问题?我很感激任何帮助!

I'm having a little trouble to integrate my login frontend logics (Vue3 + Axios) to my Java API (with Spring Security).

I'm getting the following error:

com.fasterxml.jackson.databind.exc.MismatchedInputException: No content to map due to end-of-input
 at [Source: (org.apache.catalina.connector.CoyoteInputStream); line: 1, column: 0]
    at com.fasterxml.jackson.databind.exc.MismatchedInputException.from(MismatchedInputException.java:59) ~[jackson-databind-2.10.2.jar:2.10.2]
    at com.fasterxml.jackson.databind.ObjectMapper._initForReading(ObjectMapper.java:4344) ~[jackson-databind-2.10.2.jar:2.10.2]
    at com.fasterxml.jackson.databind.ObjectMapper._readMapAndClose(ObjectMapper.java:4189) ~[jackson-databind-2.10.2.jar:2.10.2]
    at com.fasterxml.jackson.databind.ObjectMapper.readValue(ObjectMapper.java:3242) ~[jackson-databind-2.10.2.jar:2.10.2]
    at br.com.preferencialsaude.app.JWTLoginFilter.attemptAuthentication(JWTLoginFilter.java:35) ~[classes/:na]
    at org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter.doFilter(AbstractAuthenticationProcessingFilter.java:212) ~[spring-security-web-5.2.1.RELEASE.jar:5.2.1.RELEASE]
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334) ~[spring-security-web-5.2.1.RELEASE.jar:5.2.1.RELEASE]
    at org.springframework.security.web.authentication.logout.LogoutFilter.doFilter(LogoutFilter.java:116) ~[spring-security-web-5.2.1.RELEASE.jar:5.2.1.RELEASE]
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334) ~[spring-security-web-5.2.1.RELEASE.jar:5.2.1.RELEASE]
    at org.springframework.security.web.header.HeaderWriterFilter.doHeadersAfter(HeaderWriterFilter.java:92) ~[spring-security-web-5.2.1.RELEASE.jar:5.2.1.RELEASE]
    at org.springframework.security.web.header.HeaderWriterFilter.doFilterInternal(HeaderWriterFilter.java:77) ~[spring-security-web-5.2.1.RELEASE.jar:5.2.1.RELEASE]
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119) ~[spring-web-5.2.3.RELEASE.jar:5.2.3.RELEASE]
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334) ~[spring-security-web-5.2.1.RELEASE.jar:5.2.1.RELEASE]
    at org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter(SecurityContextPersistenceFilter.java:105) ~[spring-security-web-5.2.1.RELEASE.jar:5.2.1.RELEASE]
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334) ~[spring-security-web-5.2.1.RELEASE.jar:5.2.1.RELEASE]
    at org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter.doFilterInternal(WebAsyncManagerIntegrationFilter.java:56) ~[spring-security-web-5.2.1.RELEASE.jar:5.2.1.RELEASE]
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119) ~[spring-web-5.2.3.RELEASE.jar:5.2.3.RELEASE]
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334) ~[spring-security-web-5.2.1.RELEASE.jar:5.2.1.RELEASE]
    at org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:215) ~[spring-security-web-5.2.1.RELEASE.jar:5.2.1.RELEASE]
    at org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:178) ~[spring-security-web-5.2.1.RELEASE.jar:5.2.1.RELEASE]

While debugging I've found out that no "Content-Type: application/json" header is present in my HttpServletRequest, but the problem is that I'm actually setting it in my axios client.

When I make the request from postman, it works fine, but when I try to make from my frontend app, I get the previous error.

I thought it could be the browser, but it ends up in the same freaking error in any browser. I've even tried to make the request with JS Fecth API, but the behavior remains the same.

The MimeHeaderFields when I make the request from browser:

host, connection, accept, access-control-request-method, access-control-request-headers,
origin,user-agent, sec-fetch-mode, sec-fetch-site, sec-fetch-dest, referer,
accept-encoding, accept-language

As you can see, there's no Content-Type, but it is present when I make request from postman.

Here is my client-side code:

async handleSubmit () {
    const response = await axios.post('http://localhost:8080/ws/login',
      { username: this.login, password: this.senha }, { 
        headers: { 
          'Content-Type': 'application/json',
        }
      });

    console.log(response.data)
    localStorage.setItem('token', response.data.token);
}

And here is my backend Java filter:

import java.io.IOException;
import java.util.Collections;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;

import com.fasterxml.jackson.databind.ObjectMapper;

import br.com.preferencialsaude.app.model.AccountCredentials;
import br.com.preferencialsaude.app.service.TokenAuthenticationService;

public class JWTLoginFilter extends AbstractAuthenticationProcessingFilter {

    protected JWTLoginFilter(String url, AuthenticationManager authManager) {
        super(new AntPathRequestMatcher(url));
        setAuthenticationManager(authManager);
    }

    @Override
    public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response)
            throws AuthenticationException, IOException, ServletException {

        //here is where I get the error, due to the lack of Content-Type header
        AccountCredentials credentials = new ObjectMapper().readValue(request.getInputStream(), AccountCredentials.class);

        UsernamePasswordAuthenticationToken userAuthData =
            new UsernamePasswordAuthenticationToken(credentials.getUsername(), credentials.getPassword(), Collections.emptyList());

        return getAuthenticationManager().authenticate(userAuthData);
    }

And this is the result I get in postman:

{"token":"eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiJ0aGFseXMiLCJleHAiOjE2NDYzMzM2OTB9.5wYyYs6jwhIsxob99Ubx4b64jIIMjVKXf0bZ_ZS_zhkPtrK0KOgKxOgy0HgxlEdV_F5DTwOeDooqVRouEuAqEA"}

with status code 200

Here is my WebSecurityConfig class:

package br.com.preferencialsaude.app;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpMethod;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.builders.WebSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;

import br.com.preferencialsaude.app.service.MyUserDetailsService;

@Configuration
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter{
    
    private MyUserDetailsService userDetailsService;
    
    public WebSecurityConfig(MyUserDetailsService userDetailsService) {
        this.userDetailsService = userDetailsService;
    }
    
    public BCryptPasswordEncoder passwordEncoder() {
        BCryptPasswordEncoder bCryptPasswordEncoder = new BCryptPasswordEncoder();
        return bCryptPasswordEncoder;
    }
    
    @Autowired
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.userDetailsService(userDetailsService).passwordEncoder(passwordEncoder());
    }
    
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.csrf().disable().authorizeRequests()
            .antMatchers("/", "/login").permitAll()
            .antMatchers(HttpMethod.POST, "/ws/login").permitAll()
            .anyRequest().authenticated()
            .and()
            .addFilterBefore(new JWTLoginFilter("/ws/login", authenticationManager()), UsernamePasswordAuthenticationFilter.class)
            .addFilterBefore(new JWTAuthenticationFilter(), UsernamePasswordAuthenticationFilter.class)
            .formLogin()
                .loginPage("/login")
                .failureUrl("/login?error=true")
                .defaultSuccessUrl("/gerenciador/home", true)
                .usernameParameter("usuario")
                .passwordParameter("senha")
                .and()
            .logout()
                .logoutRequestMatcher(new AntPathRequestMatcher("/gerenciador/logout"))
                .logoutSuccessUrl("/gerenciador/login").and().exceptionHandling()
                .accessDeniedPage("/error");
    }
    
    @Override
    public void configure(WebSecurity web) throws Exception {
        web.ignoring().antMatchers(
           "/resources/**", "/static/**", "/css/**", "/js/**", "/imagens/**",
            "/webfonts/**", "/jasper/**", "/contratos/**",
            "/v2/api-docs", "/swagger-resources/**", "/configuration/ui", "/swagger-ui.html", "/webjars/**",
            "/procedimento/**", "/procedimento/**/**", "/credenciamento/empresa/**", "/credenciamento/pessoa/**",
            "/credenciamento/farmacia/**", "/buscaCep", "/plano/**", "/contrato/empresa/**",
            "/contrato/pessoa-fisica/**", "/rede-credenciada/**", "/ws/rede-credenciada/**", "/ws/endereco/**",
            "/ws/procedimentos/**", "/ws/recuperar-senha/**", "/api/cupons-venda/**", "/atendimento/**",
            "/termos", "/convenio/**", "/ws/agendamento/**", "/ws/consulta/**", "/ws/notificacoes/**", "/ws/avaliacao/**",
            "/ws/imagens/**", "/actuator/**", "/api/enderecos/**", "/api/cadastros-clientes/**", "/api/cidades/**",
            "/api/planos/**", "/api/especialidades-saude/consultas/**", "/api/rede-atendimento/**"
        );
    }
}

And here is my JWTLoginFilter:

package br.com.preferencialsaude.app;

import java.io.IOException;
import java.util.Collections;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;

import com.fasterxml.jackson.databind.ObjectMapper;

import br.com.preferencialsaude.app.model.AccountCredentials;
import br.com.preferencialsaude.app.service.TokenAuthenticationService;

public class JWTLoginFilter extends AbstractAuthenticationProcessingFilter {

    protected JWTLoginFilter(String url, AuthenticationManager authManager) {
        super(new AntPathRequestMatcher(url));
        setAuthenticationManager(authManager);
    }

    @Override
    public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response)
            throws AuthenticationException, IOException, ServletException {

        AccountCredentials credentials = new ObjectMapper().readValue(request.getInputStream(), AccountCredentials.class);

        UsernamePasswordAuthenticationToken userAuthData =
            new UsernamePasswordAuthenticationToken(credentials.getUsername(), credentials.getPassword(), Collections.emptyList());

        return getAuthenticationManager().authenticate(userAuthData);
    }
    
    @Override
    protected void successfulAuthentication(HttpServletRequest request, HttpServletResponse response,
                                            FilterChain filterChain, Authentication auth) throws IOException, ServletException {
        TokenAuthenticationService.addAuthentication(response, auth.getName());
    }
    
    @Override
    protected void unsuccessfulAuthentication(HttpServletRequest request, HttpServletResponse response,
                                              AuthenticationException failed) throws IOException, ServletException {
        SecurityContextHolder.clearContext();
        TokenAuthenticationService.failAuthentication(response);
    }
}

Have you ever faced a similar problem? I appreciate any help!

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

久伴你 2025-01-16 06:33:13

我想出了如何通过在 WebSecurityConfig 文件中添加一些 CORS 配置来解决此问题。

问题根本不在于 Content-Type 标头,而在于 Spring Security 阻止了 OPTIONS 请求。

这是我添加的用于解决问题的代码片段

@Bean
public FilterRegistrationBean processCorsFilter() {     
    final UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
    final CorsConfiguration config = new CorsConfiguration();
    config.setAllowCredentials(true);
    config.setAllowedOrigins(Arrays.asList("http://localhost:8080", "http://localhost:8081",
                "https://site.preferencialsaude.com.br", "https://site-hmlg.preferencialsaude.com.br"));
    config.addAllowedHeader("*");
    config.addAllowedMethod("*");
    source.registerCorsConfiguration("/ws/login", config);
    source.registerCorsConfiguration("/api/**", config);


    final FilterRegistrationBean bean = new FilterRegistrationBean(new CorsFilter(source));
    bean.setOrder(Ordered.HIGHEST_PRECEDENCE);
    return bean;
}

在此 CORS 配置教程内的评论中找到了此代码: https://spring.io/blog/2015/06/08/cors-support-in-spring-framework

如果您想接受来自所有来源的请求,只需将 setAllowedOrigins() 替换为 addAllowedOrigin("*") 即可,因为按照我配置它的方式(如上面的代码所示),我无法从邮递员或除我定义的来源之外的任何其他来源登录。

I figured it out how to resolve this by adding some CORS configuration in my WebSecurityConfig file.

The problem wasn't the Content-Type Header at all, but Spring Security that was blocking OPTIONS requests.

This is the piece of code I added to solve the issue

@Bean
public FilterRegistrationBean processCorsFilter() {     
    final UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
    final CorsConfiguration config = new CorsConfiguration();
    config.setAllowCredentials(true);
    config.setAllowedOrigins(Arrays.asList("http://localhost:8080", "http://localhost:8081",
                "https://site.preferencialsaude.com.br", "https://site-hmlg.preferencialsaude.com.br"));
    config.addAllowedHeader("*");
    config.addAllowedMethod("*");
    source.registerCorsConfiguration("/ws/login", config);
    source.registerCorsConfiguration("/api/**", config);


    final FilterRegistrationBean bean = new FilterRegistrationBean(new CorsFilter(source));
    bean.setOrder(Ordered.HIGHEST_PRECEDENCE);
    return bean;
}

Found this code in a comment inside this CORS configuration tutorial: https://spring.io/blog/2015/06/08/cors-support-in-spring-framework

If you want to accept requests from all origins, just replace the setAllowedOrigins() with addAllowedOrigin("*"), since the way I configured it, as in the code above, I cannot login from postman, or any other origins except the ones I defined.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文