JWT token com spring, para autenticação de usuários - Resolvido

Ao tentar validar este método: Jws parseClaimsJws = setSigningKey.parseClaimsJws(token);, ele mostra esta exceção na tela

JWT signature does not match locally computed signature. JWT validity cannot be asserted and should not be trusted.

Preciso de validar o token do usuário.

Debugando.

Ao fazer o login ele gera este token: eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiIwMjY3OTUwMDYzNiIsImV4cCI6MTUyMjI3NjMxOX0.XBLiwl94He0ffVkf5TpcBKUob6PotuleSni5Hc9y8anPsES6WSO6f8Ki441UU_HGicyRAXmZKLBXsfQ2okFAqw

Quando ele pesquisa por um país ele utiliza este token, Consulta feito segundos depois.
Bearer eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiIwMjY3OTUwMDYzNiIsImV4cCI6MTUyMjI3NjMxOX0.XBLiwl94He0ffVkf5TpcBKUob6PotuleSni5Hc9y8anPsES6WSO6f8Ki441UU_HGicyRAXmZKLBXsfQ2okFAqw

Estou a dias tentando e não consigo passar a diante… kkkk

Qual biblioteca JWT você está usando?

Esta dependência

	    <dependency>
			<groupId>io.jsonwebtoken</groupId>
			<artifactId>jjwt</artifactId>
			<version>0.9.0</version>
		</dependency>

Como está seu código? Você seguiu o quickstart desse link?

Não vi esta explicação, mas segui exemplos que vi funcionando por vídeo e códigos fontes liberados.

Mas analisando este link me passou.

Tenho as depedencias 2.x, do jackson:

<jackson-core.version>2.9.4</jackson-core.version>
<dependency>
     	<groupId>com.fasterxml.jackson.core</groupId>
     	<artifactId>jackson-databind</artifactId>
     	<version>${jackson-core.version}</version>
</dependency>
 
<dependency>
     	<groupId>com.fasterxml.jackson.module</groupId>
     	<artifactId>jackson-module-jaxb-annotations</artifactId>
     	<version>2.8.4</version>
</dependency>
 
<dependency>
     	<groupId>com.fasterxml.jackson.core</groupId>
     	<artifactId>jackson-core</artifactId>
     	<version>${jackson-core.version}</version>
</dependency>

Para gerar o token utilizo este metodo:

private String doGenerateToken(Map<String, Object> claims, String subject) {
	final Date createdDate = clock.now();
	final Date expirationDate = calculateExpirationDate(createdDate);
	return Jwts.builder().setSubject(subject).setClaims(claims).setIssuedAt(createdDate)
				.setExpiration(expirationDate)
				.signWith(SignatureAlgorithm.HS512, secret).compact();
}

Para recuperar utilizo este metodo:

private Claims getAllClaimsFromToken(String token) {
		Claims body = null;
		try {
			JwtParser parser = Jwts.parser();
			JwtParser setSigningKey = parser.setSigningKey(secret);
			Jws<Claims> parseClaimsJws = setSigningKey.parseClaimsJws(token);
			body = parseClaimsJws.getBody();
		} catch (Exception e) {
			e.printStackTrace();
		}
		return body;
	}

toda a classe:
package br.com.netsoft.configuracao.auth;

import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Clock;
import io.jsonwebtoken.Jws;
import io.jsonwebtoken.JwtParser;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import io.jsonwebtoken.impl.DefaultClock;

import java.io.Serializable;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.function.Function;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.stereotype.Component;

import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;

@Component

public class JwtTokenUtil implements Serializable {

	static final String CLAIM_KEY_USERNAME = "sub";
	static final String CLAIM_KEY_CREATED = "iat";
	private static final long serialVersionUID = -3301605591108950415L;

	@SuppressFBWarnings(value = "SE_BAD_FIELD", justification = "It's okay here")
	private Clock clock = DefaultClock.INSTANCE;

	@Value("${jwt.secret}")
	private String secret;

	@Value("${jwt.expiration}")
	private String expiration;

	public String getUsernameFromToken(String token) {
		return getClaimFromToken(token, Claims::getSubject);
	}

	public Date getIssuedAtDateFromToken(String token) {
		return getClaimFromToken(token, Claims::getIssuedAt);
	}

	public Date getExpirationDateFromToken(String token) {
		return getClaimFromToken(token, Claims::getExpiration);
	}

	public <T> T getClaimFromToken(String token,
			Function<Claims, T> claimsResolver) {
		final Claims claims = getAllClaimsFromToken(token);
		return claimsResolver.apply(claims);
	}

	private Claims getAllClaimsFromToken(String token) {
		Claims body = null;
		try {
			JwtParser parser = Jwts.parser();
			JwtParser setSigningKey = parser.setSigningKey(secret);
			Jws<Claims> parseClaimsJws = setSigningKey.parseClaimsJws(token);
			body = parseClaimsJws.getBody();
		} catch (Exception e) {
			e.printStackTrace();
		}
		return body;
	}

	private Boolean isTokenExpired(String token) {
		final Date expiration = getExpirationDateFromToken(token);
		return expiration.before(clock.now());
	}

	private Boolean isCreatedBeforeLastPasswordReset(Date created,
			Date lastPasswordReset) {
		return (lastPasswordReset != null && created.before(lastPasswordReset));
	}

	private Boolean ignoreTokenExpiration(String token) {
		// here you specify tokens, for that the expiration is ignored
		return false;
	}

	public String generateToken(UserDetails userDetails) {
		Map<String, Object> claims = new HashMap<>();
		return doGenerateToken(claims, userDetails.getUsername());
	}

	private String doGenerateToken(Map<String, Object> claims, String subject) {
		final Date createdDate = clock.now();
		final Date expirationDate = calculateExpirationDate(createdDate);
		return Jwts.builder().setSubject(subject).setClaims(claims)
				.setIssuedAt(createdDate).setExpiration(expirationDate)
				.signWith(SignatureAlgorithm.HS512, secret).compact();
	}

	public Boolean canTokenBeRefreshed(String token, Date lastPasswordReset) {
		final Date created = getIssuedAtDateFromToken(token);
		return !isCreatedBeforeLastPasswordReset(created, lastPasswordReset)
				&& (!isTokenExpired(token) || ignoreTokenExpiration(token));
	}

	public String refreshToken(String token) {
		final Date createdDate = clock.now();
		final Date expirationDate = calculateExpirationDate(createdDate);

		final Claims claims = getAllClaimsFromToken(token);
		claims.setIssuedAt(createdDate);
		claims.setExpiration(expirationDate);

		return Jwts.builder().setClaims(claims)
				.signWith(SignatureAlgorithm.HS512, secret).compact();
	}

	public Boolean validateToken(String token, UserDetails userDetails) {
		JwtUser user = (JwtUser) userDetails;
		final String username = getUsernameFromToken(token);
		final Date created = getIssuedAtDateFromToken(token);
		// final Date expiration = getExpirationDateFromToken(token);
		return (username.equals(user.getUsername()) && !isTokenExpired(token) && !isCreatedBeforeLastPasswordReset(
				created, user.getLastPasswordResetDate()));
	}

	private Date calculateExpirationDate(Date createdDate) {
		return new Date(createdDate.getTime() + Long.parseLong(expiration)
				* 1000);
	}
}

Fiz conforme o exemplo do link que você me passou.

Mesmo erro

para gerar o token

private String doGenerateToken(Map<String, Object> claims, String subject) {
      Key key = MacProvider.generateKey();
      String compactJws = Jwts.builder().setSubject("Joe").signWith(SignatureAlgorithm.HS512, key).compact();
      return compactJws;
}

para buscar o token:**

private Claims getAllClaimsFromToken(String token) {
	Claims body = null;
	Key key = MacProvider.generateKey();
	try {
		Jws<Claims> parseClaimsJws = Jwts.parser().setSigningKey(key)
				.parseClaimsJws(token);
		body = parseClaimsJws.getBody();
	} catch (SignatureException e) {
		e.printStackTrace();
	}
	return body;
}

Hoje fiz um debug até encontrar o problema, mas mesmo assim não consegui ajustar ou entender o que está acontecendo.

Ao debugar nas classes do jwt, ele dá erro nesta linha no método DefaultJwtSignatureValidator:

Então o jwt tem uma classe e métodos para ajustar e validar o token.

O problema é que ele está parando neste método nesta linha:

@Override
    public boolean isValid(String jwtWithoutSignature, String base64UrlEncodedSignature) {

        byte[] data = jwtWithoutSignature.getBytes(US_ASCII);

        byte[] signature = TextCodec.BASE64URL.decode(base64UrlEncodedSignature);

        return this.signatureValidator.isValid(data, signature);
    }

As variáveis data e signatureValidator estão diferentes.

Imagens:

A variável jwtWithoutSignature, que chega no metodo da jwt, não é o token gerado, somente uma parte.

A variável jwtWithoutSignature, que chega no metodo da jwt, não é o token gerado, somente uma parte.

Erro na validação pelo site https://jwt.io/

1 curtida

Acho que consegui resolver pois agora está com a mensagem que foi expirado.

io.jsonwebtoken.ExpiredJwtException: JWT expired at 2018-03-29T13:15:18Z. Current time: 2018-03-29T13:17:40Z, a difference of 142980 milliseconds. Allowed clock skew: 0 milliseconds.

Consegui sim.

Criando assim:

private String token(UsuarioEntity usuario) {
    String token = Jwts.builder().setSubject(usuario.getLogin()).signWith(SignatureAlgorithm.HS512, "usuarioLogado").setExpiration(new Date(System.currentTimeMillis() + 5 * 60 * 1000)).compact();
}

Buscando o token assim:

Claims body = null;
try {
	body = Jwts.parser().setSigningKey("usuarioLogado").parseClaimsJws(token).getBody();
} catch (Exception e) {
	e.printStackTrace();
}
return body;

Pelo que eu vi estava gerando de com um tipo e tentando buscar de outro.

Valeu pessoal

1 curtida