我一直在为使用Spring Boot Security刷新令牌而苦苦挣扎.

在此之前,我已经使用JWT完成了工作身份验证,但现在当我创建这个刷新系统时,它不能再登录了.表示"JWT签名与本地计算的签名不匹配.无法断言JWT有效性,也不应信任它."我试图通过在这里和谷歌找到的不同主题来解决这个问题.

现在,我不能理解这种情况,错误来自哪里.I在JWT验证方法上崩溃:

JwtUtils.java

package com.testapp.springbooot.security.jwt;

import java.security.Key;
import java.util.Date;

import com.testapp.springbooot.security.services.UserDetailsImpl;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.core.Authentication;
import org.springframework.stereotype.Component;

import io.jsonwebtoken.*;
import io.jsonwebtoken.security.Keys;

@Component
public class JwtUtils {
  private static final Logger logger = LoggerFactory.getLogger(JwtUtils.class);

  @Value("${testapp.app.jwtSecret}")
  private String jwtSecret;

  @Value("${testapp.app.jwtExpirationMs}")
  private int jwtExpirationMs;

  public String generateJwtToken(Authentication authentication) {

    UserDetailsImpl userPrincipal = (UserDetailsImpl) authentication.getPrincipal();

    return Jwts.builder()
        .setId("" + userPrincipal.getId())
        .setIssuedAt(new Date())
        .setExpiration(new Date((new Date()).getTime() + jwtExpirationMs))
        .signWith(key(), Signature算法rithm.HS512)
        .compact();
  }

  private Key key() {
    return Keys.secretKeyFor(Signature算法rithm.HS512);
  }

  public String getUserNameFromJwtToken(String token) {
    return Jwts.parserBuilder().setSigningKey(key()).build()
               .parseClaimsJws(token).getBody().getSubject();
  }

  public String getEmailFromJwtToken(String token) {
    return Jwts.parserBuilder().setSigningKey(key()).build()
            .parseClaimsJws(token).getBody().getSubject();
  }

  public Date getExpirationFromJwtToken(String token) {
    return Jwts.parserBuilder().setSigningKey(key()).build()
            .parseClaimsJws(token).getBody().getExpiration();
  }

  public String getUserIdFromJwtToken(String token) {
    return Jwts.parserBuilder().setSigningKey(key()).build()
            .parseClaimsJws(token).getBody().getId();
  }

  public boolean isJWTExpired(String authToken) {
    Date expiresAt = getExpirationFromJwtToken(authToken);
    return expiresAt.before(new Date());
  }

  public boolean validateJwtToken(String authToken) {
    try {
      Jwts.parserBuilder().setSigningKey(key()).build().parse(authToken);
      return true;
    } catch (MalformedJwtException e) {
      logger.error("Invalid JWT token: {}", e.getMessage());
    } catch (ExpiredJwtException e) {
      logger.error("JWT token is expired: {}", e.getMessage());
    } catch (UnsupportedJwtException e) {
      logger.error("JWT token is unsupported: {}", e.getMessage());
    } catch (IllegalArgumentException e) {
      logger.error("JWT claims string is empty: {}", e.getMessage());
    }

    return false;
  }
}

以及登录认证控制器:

@PostMapping("/signin")
  public ResponseEntity<?> authenticateUser(@Valid @RequestBody LoginRequest loginRequest) {

    Authentication authentication = authenticationManager
        .authenticate(new UsernamePasswordAuthenticationToken(loginRequest.getEmail(), loginRequest.getPassword()));

    SecurityContextHolder.getContext().setAuthentication(authentication);
    String jwt = jwtUtils.generateJwtToken(authentication);

    UserDetailsImpl userDetails = (UserDetailsImpl) authentication.getPrincipal();
    List<String> roles = userDetails.getAuthorities().stream().map(item -> item.getAuthority())
        .collect(Collectors.toList());

    User completeUser = userRepository.findById(userDetails.getId()).orElseThrow(() -> new ObjectNotFoundException(userDetails.getId(), "user"));

    RefreshToken refreshToken = refreshTokenService.createRefreshToken(userDetails.getId());

    return ResponseEntity
        .ok(new JwtResponse(jwt, refreshToken.getToken(), userDetails.getEmail(), roles, completeUser.getFirstName(), completeUser.getLastName(), completeUser.getHeight(), completeUser.getSex()));
  }

这个错误让我头疼得要命.就是找不到解决办法.try 了几个解决方案,但没有奏效.仍然说着同样的错误.

推荐答案

基本上,应该使用相同的键来生成JWT令牌并验证相同的JWT.

在令牌生成(generateJwtToken)和验证(validateJwtToken)期间,您似乎使用了不同的密钥来签署JWT.在generateJwtToken中,您每次使用Keys.secretKeyFor(Signature算法rithm.HS512)来生成一个新的密钥,而在validateJwtToken中,您使用的是key(),它使用相同的算法生成新的密钥.若要解决此问题,您应该使用相同的密钥进行签名和验证.实现这一点的一种方法是将密钥作为字段存储在JwtUtils组件中并重用它.

Java相关问答推荐

为什么Java中的两个日期有差异?

Java取消任务运行Oracle查询通过JDBC—连接中断,因为SQLSTATE(08006),错误代码(17002)IO错误:套接字读取中断

为什么我们仍然需要实现noArgsConstructor如果Java默认提供一个非参数化的构造函数?''

@ IdClass with @ Inheritance(策略= InheritanceType. SINGLE_TABLE)

为什么在枚举中分支预测比函数调用快?

使用联接和分页的SpringBoot Spring数据JPA

通过合并Akka Streams中的多个慢源保持订购

如何使用Maven和Spring Boot将构建时初始化、跟踪类初始化正确传递到本机编译

SpringBoot+Java 17@Valid未验证POJO

把一条整型短裤和两条短裤装成一条长的

如何让JVM在SIGSEGV崩溃后快速退出?

SonarLint:只能有条件地调用方法(S)

Android应用程序为错误的显示类型 Select 尺寸文件

如何使这两种方法合二为一?

如何根据配置动态创建N个bean

项目react 堆中doOnComplete()和Subscribe()的第三个参数之间的差异

在Oracle db中,当我们提供字符串而不是数字时,比较是如何工作的?

使用Java线程进行并行编程

带有提取器的JavaFXObservableList会根据侦听器的存在而改变行为

如何转换Vector<;对象>;转换为int?