我正在构建一个服务器端REST服务应用程序。我对JWT身份验证令牌有问题。签到后,我可以很容易地拿到钱(这里我用邮递员)。

但是,当我试图验证使用相同令牌访问受保护的REST控制器的请求时,我会得到以下错误:

代码语言:javascript运行复制io.jsonwebtoken.SignatureException: JWT signature does not match locally computed signature. JWT validity cannot be asserted and should not be trusted.

at io.jsonwebtoken.impl.DefaultJwtParser.parse(DefaultJwtParser.java:354)

at io.jsonwebtoken.impl.DefaultJwtParser.parse(DefaultJwtParser.java:481)

at io.jsonwebtoken.impl.DefaultJwtParser.parseClaimsJws(DefaultJwtParser.java:541)

at com.configuration.jwt.JwtTokenUtil.extractClaims(JwtTokenUtil.java:104)

at com.configuration.jwt.JwtTokenUtil.getUsernameFromToken(JwtTokenUtil.java:39)

at com.configuration.jwt.JwtAuthenticationFilter.doFilterInternal(JwtAuthenticationFilter.java:44)

at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)

...这就好像应用程序不记得它生成的令牌。下面是生成此错误的Postman的get请求:

我想异常的来源是我的类extractClaims的JwtTokenUtil方法。

代码语言:javascript运行复制@Component

public final class JwtTokenUtil {

public static final int EXPIRATION_IN_SECONDS = 120;

private static final String JWT_SECRET = "Some$ecretKey";

private Clock clock = DefaultClock.INSTANCE;

@Value("${jwt.secret}")

private String secret;

@Value("${jwt.expiration}")

private Long expiration;

private JwtTokenUtil() {

// Hide default constructor

}

public String getUsernameFromToken(String token) {

return extractClaims(token).getSubject();

}

public Boolean validateToken(String token, UserDetails userDetails) {

UserDetailsImp user = (UserDetailsImp) userDetails;

final String username = getUsernameFromToken(token);

return (username.equals(user.getUsername()) && !isTokenExpired(token));

}

public Date getIssuedAtDateFromToken(String token) {

return extractClaims(token).getIssuedAt();

}

public String generateToken(UserDetails userDetails) {

Map claims = new HashMap();

return doGenerateToken(claims, userDetails.getUsername());

}

private String doGenerateToken(Map claims, String subject) {

final Date createdDate = clock.now();

final Date expirationDate = calculateExpirationDate(createdDate);

return Jwts.builder().setClaims(claims).setSubject(subject).setIssuedAt(createdDate)

.setExpiration(expirationDate).signWith(SignatureAlgorithm.HS512, secret).compact();

}

private Date calculateExpirationDate(Date createdDate) {

return new Date(createdDate.getTime() + expiration * 1000);

}

public static String createToken(String username, Date issueDate) {

String jwtToken = Jwts.builder().setSubject(username).setIssuedAt(issueDate)

.setExpiration(new Date(issueDate.getTime() + EXPIRATION_IN_SECONDS))

.signWith(SignatureAlgorithm.HS512, JWT_SECRET).compact();

return jwtToken;

}

public static String getSubject(String token) {

Claims claims = extractClaims(token);

return claims.getSubject();

}

public static String refreshToken(String token, long expirationInSeconds) {

final Claims claims = extractClaims(token);

Date now = new Date();

claims.setIssuedAt(now);

claims.setExpiration(new Date(now.getTime() + EXPIRATION_IN_SECONDS));

return createTokenFromClaims(claims);

}

public static boolean isTokenExpired(String token) {

final Claims claims = extractClaims(token);

Date now = new Date();

return now.after(claims.getExpiration());

}

private static String createTokenFromClaims(Claims claims) {

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

}

private static Claims extractClaims(String token) {

return Jwts.parser().setSigningKey(JWT_SECRET).parseClaimsJws(token).getBody();

}

}这是我的JwtAuthenticationFilter课程:

代码语言:javascript运行复制public class JwtAuthenticationFilter extends OncePerRequestFilter {

@Autowired

private UserDetailsService userDetailsService;

@Autowired

private JwtTokenUtil jwtTokenUtil;

@Override

protected void doFilterInternal(HttpServletRequest req, HttpServletResponse res, FilterChain chain)

throws IOException, ServletException {

String header = req.getHeader("Authorization");

String username = null;

String authToken = null;

if (header != null && header.startsWith("Bearer ")) {

authToken = header.replace("Bearer ", "");

try {

username = jwtTokenUtil.getUsernameFromToken(authToken);

} catch (IllegalArgumentException e) {

logger.error("an error occured during getting username from token", e);

} catch (ExpiredJwtException e) {

logger.warn("the token is expired and not valid anymore", e);

}

} else {

logger.warn("couldn't find bearer string, will ignore the header");

}

if (username != null && SecurityContextHolder.getContext().getAuthentication() == null) {

UserDetails userDetails = userDetailsService.loadUserByUsername(username);

if (jwtTokenUtil.validateToken(authToken, userDetails)) {

String role = "";

role = userDetails.getAuthorities().size() > 1 ? "ROLE_ADMIN" : "ROLE_TOURIST";

UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken(

userDetails, null, Arrays.asList(new SimpleGrantedAuthority(role)));

authentication.setDetails(new WebAuthenticationDetailsSource().buildDetails(req));

logger.info("authenticated user " + username + ", setting security context");

SecurityContextHolder.getContext().setAuthentication(authentication);

}

}

chain.doFilter(req, res);

}

}我不知道控制器的登录是否与这个问题有关,但这是它的代码:

代码语言:javascript运行复制@PostMapping(value = "/signin")

public ResponseEntity signin(@Valid @RequestBody LoginForm loginForm) throws AuthenticationException {

final Authentication authentication = authenticationManager.authenticate(

new UsernamePasswordAuthenticationToken(loginForm.getUsername(), loginForm.getPassword()));

SecurityContextHolder.getContext().setAuthentication(authentication);

final UserDetails user = userService.loadUserByUsername(loginForm.getUsername());

final String token = jwtTokenUtil.generateToken(user);

return ResponseEntity.ok(new JwtResponse(token, user.getUsername(), user.getAuthorities()));

}我希望有人能帮忙。