Boa noite a todos,
Estou com problema para realizar a autenticação via token JWT, as requisições GET funcionam os POSTs esta dando acesso negado.
As tecnologias usadas são Spring Boot e Kotlin, em um api rest.
Consigo realizar a solicitação e obter o login.
As solicitações GET, passam corretamente pelos filtros de autenticação.
As solicitações POST, retornam um Exception falando que não existe autorização
Criei um filtro para rastrear, e o header “Authorization” é sim enviado para o servidor tanto nas solicitações GET, quanto na POST
As solicitações POST nunca chegam a passar pela classe JWTAuthorizationFilter, enquanto as GET sim.
Alguma luz, pode ser em java a resposta.
Se precisar de mais alguma informação.
Exception
org.springframework.security.authentication.InsufficientAuthenticationException: Full authentication is required to access this resource
at org.springframework.security.web.access.ExceptionTranslationFilter.handleSpringSecurityException(ExceptionTranslationFilter.java:189)
at org.springframework.security.web.access.ExceptionTranslationFilter.doFilter(ExceptionTranslationFilter.java:140)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334)
at org.springframework.security.web.session.SessionManagementFilter.doFilter(SessionManagementFilter.java:137)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334)
at org.springframework.security.web.authentication.AnonymousAuthenticationFilter.doFilter(AnonymousAuthenticationFilter.java:111)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334)
at org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter.doFilter(SecurityContextHolderAwareRequestFilter.java:158)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334)
at org.springframework.security.web.savedrequest.RequestCacheAwareFilter.doFilter(RequestCacheAwareFilter.java:63)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:103)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334)
at org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter.doFilter(AbstractAuthenticationProcessingFilter.java:200)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334)
at org.springframework.security.web.authentication.logout.LogoutFilter.doFilter(LogoutFilter.java:116)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:103)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:103)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:103)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334)
at org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter(SecurityContextPersistenceFilter.java:105)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:103)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334)
at org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:215)
at org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:178)
at org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:358)
at org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:271)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
at org.apache.catalina.core.ApplicationDispatcher.invoke(ApplicationDispatcher.java:712)
at org.apache.catalina.core.ApplicationDispatcher.processRequest(ApplicationDispatcher.java:461)
at org.apache.catalina.core.ApplicationDispatcher.doForward(ApplicationDispatcher.java:384)
at org.apache.catalina.core.ApplicationDispatcher.forward(ApplicationDispatcher.java:312)
at org.apache.catalina.core.StandardHostValve.custom(StandardHostValve.java:394)
at org.apache.catalina.core.StandardHostValve.status(StandardHostValve.java:253)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:175)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:92)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:74)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:343)
at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:367)
at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:65)
at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:860)
at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1591)
at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49)
at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128)
at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628)
at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
at java.base/java.lang.Thread.run(Thread.java:834)
Seguem as classes
JWTAuthenticationFilter
package com.arda.asincor.config
import com.arda.asincor.model.sistema.Usuario
import com.arda.asincor.objects.Credentials
import com.arda.asincor.service.Constantes
import com.fasterxml.jackson.databind.ObjectMapper
import io.jsonwebtoken.Jwts
import io.jsonwebtoken.SignatureAlgorithm
import io.jsonwebtoken.security.Keys
import org.slf4j.LoggerFactory
import org.springframework.security.authentication.AuthenticationManager
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken
import org.springframework.security.core.Authentication
import org.springframework.security.core.GrantedAuthority
import org.springframework.security.core.userdetails.UsernameNotFoundException
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter
import java.nio.charset.Charset
import java.util.*
import java.util.stream.Collectors
import javax.servlet.FilterChain
import javax.servlet.http.HttpServletRequest
import javax.servlet.http.HttpServletResponse
class JWTAuthenticationFilter : UsernamePasswordAuthenticationFilter
{
private val ardaLogger = LoggerFactory.getLogger(JWTAuthenticationFilter::class.java)
constructor(authenticationManager: AuthenticationManager) : super()
{
this.authenticationManager = authenticationManager
}
override fun attemptAuthentication(request: HttpServletRequest, response: HttpServletResponse?): Authentication?
{
ardaLogger.info("Antes da autenticação")
val (username, password) = try
{
ObjectMapper().readValue(request.inputStream, Credentials::class.java)
} catch (ex: Exception)
{
ardaLogger.error("Usuário e/ou senha não encontrados: ${ex.message}", ex)
throw throw UsernameNotFoundException("Usuário e/ou senha não encontrados!")
}
try
{
val token = UsernamePasswordAuthenticationToken(username, password)
return authenticationManager.authenticate(token)
} catch (ex: Exception)
{
ardaLogger.error("Usuário e/ou senha inválidos: ${ex.message}", ex)
throw UsernameNotFoundException("Usuário e/ou senha inválidos")
}
}
override fun successfulAuthentication(request: HttpServletRequest?, response: HttpServletResponse, chain: FilterChain?, authResult: Authentication)
{
ardaLogger.info("Autenticação")
val user = authResult.principal as Usuario
val roles = user.authorities.stream().map(GrantedAuthority::getAuthority).collect(Collectors.toList())
val signingKey = Constantes.SECRET_KEY.toByteArray(Charset.forName("UTF-8"))
ardaLogger.info("Chave: $signingKey")
val token = Jwts.builder()
.signWith(Keys.hmacShaKeyFor(signingKey), SignatureAlgorithm.HS256)
.setHeaderParam("typ", Constantes.TOKEN_TYPE)
.setIssuer(Constantes.TOKEN_ISSUER)
.setAudience(Constantes.TOKEN_AUDIENCE)
.setSubject(user.username)
.setExpiration(Date(System.currentTimeMillis() + 300000))
.claim("rol", roles)
.compact()
response.addHeader(Constantes.AUTHORIZATION, "${Constantes.BEARER} $token")
}
}
JWTAuthorizationFilter
package com.arda.asincor.config
import com.arda.asincor.service.Constantes
import io.jsonwebtoken.ExpiredJwtException
import io.jsonwebtoken.Jwts
import io.jsonwebtoken.MalformedJwtException
import io.jsonwebtoken.UnsupportedJwtException
import io.jsonwebtoken.security.SignatureException
import org.slf4j.LoggerFactory
import org.springframework.security.authentication.AuthenticationManager
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken
import org.springframework.security.core.GrantedAuthority
import org.springframework.security.core.context.SecurityContextHolder
import org.springframework.security.web.authentication.www.BasicAuthenticationFilter
import java.nio.charset.Charset
import java.util.stream.Collectors
import javax.servlet.FilterChain
import javax.servlet.http.HttpServletRequest
import javax.servlet.http.HttpServletResponse
class JWTAuthorizationFilter : BasicAuthenticationFilter
{
private val ardaLogger = LoggerFactory.getLogger(JWTAuthorizationFilter::class.java)
private var authManager: AuthenticationManager
constructor(authenticationManager: AuthenticationManager) : super(authenticationManager)
{
this.authManager = authenticationManager
}
override fun doFilterInternal(request: HttpServletRequest, response: HttpServletResponse, chain: FilterChain)
{
ardaLogger.info("Filtro autenticação")
val authentication = getAuthentication(request)
if (authentication != null)
{
SecurityContextHolder.getContext().authentication = authentication
}
chain.doFilter(request, response)
}
private fun getAuthentication(request: HttpServletRequest): UsernamePasswordAuthenticationToken?
{
ardaLogger.info("Verificando autenticação")
val authorizationHeader = request.getHeader(Constantes.AUTHORIZATION)
if (authorizationHeader.isNullOrBlank())
{
return null
} else
{
val token = authorizationHeader.replace("Bearer ", "")
if (token.isNullOrBlank())
{
return null
} else
{
try
{
val signingKey = Constantes.SECRET_KEY.toByteArray(Charset.forName("UTF-8"))
val parsedToken = Jwts.parser().setSigningKey(signingKey).parseClaimsJws(token)
val username = parsedToken.body.subject
val authoritiesList = parsedToken.body["rol"] as List<*>
val authorities = authoritiesList.stream().map { authority -> GrantedAuthority { authority as String } }.collect(Collectors.toList())
if (username.isNullOrBlank())
{
return null
} else
{
return UsernamePasswordAuthenticationToken(username, null, authorities)
}
} catch (ex: ExpiredJwtException)
{
ardaLogger.error("Token expirado: ${ex.message}", ex)
} catch (ex: UnsupportedJwtException)
{
ardaLogger.error("Jwt não suportado: ${ex.message}", ex)
} catch (ex: MalformedJwtException)
{
ardaLogger.error("Token inválido: ${ex.message}", ex)
} catch (ex: SignatureException)
{
ardaLogger.error("Assinatura inválida: ${ex.message}", ex)
} catch (ex: Exception)
{
ardaLogger.error("Erro desconhecido ou token vazio: ${ex.message}", ex)
}
return null
}
}
}
}
WebSecurityConfig
override fun configure(http: HttpSecurity)
{
http.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
http.cors().configurationSource(corsConfiguration())
http.authorizeRequests().antMatchers(HttpMethod.OPTIONS).permitAll()
http.addFilter(JWTAuthenticationFilter(authenticationManager()))
http.addFilter(JWTAuthorizationFilter(authenticationManager()))
http.authorizeRequests().antMatchers("/admin/user/**").permitAll()
http.authorizeRequests().antMatchers("/asincor").permitAll()
http.authorizeRequests().antMatchers("/asincor/**").permitAll()
val regras = regraRepository.findAll()
if (regras.isNotEmpty())
{
for (regra in regras)
{
http.authorizeRequests().antMatchers(regra.nome).hasAuthority(regra.role)
}
}
http.authorizeRequests().anyRequest().authenticated()
http.exceptionHandling().authenticationEntryPoint(ardaEntryPoint)
}