在将我的登录前端逻辑(Vue3 + Axios)集成到Java (与Spring安全)上时,我遇到了一些小麻烦。
我得到了以下错误:
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: application/json”标题,但问题是,我实际上在axios客户端中将其设置为。
当我向邮递员发出请求时,它工作得很好,但是当我试图从我的前端应用程序中发出请求时,我得到了前面的错误。
我以为可能是浏览器,但在任何浏览器中都会出现同样的错误。我甚至尝试使用JS粪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);
}
}你曾经遇到过类似的问题吗?我很感激你的帮助!
发布于 2022-02-23 19:01:42
我想出了如何通过在我的WebSecurityConfig文件中添加一些CORS配置来解决这个问题。
问题不在于内容类型头,而是阻止选项请求的Security。
这是我为解决这个问题而添加的代码。
@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() with addAllowedOrigin("*"),因为我配置它的方式,如上面的代码所示,我不能从postman或任何其他来源登录,除非我定义了这些来源。
https://stackoverflow.com/questions/71213788
复制相似问题