首页 > 解决方案 > Io.jsonwebtoken.security.SignatureException:JWT 签名与本地计算的签名不匹配

问题描述

大家好,我需要帮助。

我正在学习Spring WebFluxjwt 身份验证,所以我正在做一个 REST 服务来练习,但是这个错误不会让我继续,我不知道如何修复它。

错误:

io.jsonwebtoken.security.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:411) ~[jjwt-impl-0.11.1.jar:0.11.1]
    Suppressed: reactor.core.publisher.FluxOnAssembly$OnAssemblyException: 
Error has been observed at the following site(s):
    |_ checkpoint ⇢ org.springframework.security.web.server.authorization.AuthorizationWebFilter [DefaultWebFilterChain]
    |_ checkpoint ⇢ org.springframework.security.web.server.authorization.ExceptionTranslationWebFilter [DefaultWebFilterChain]
    |_ checkpoint ⇢ org.springframework.security.web.server.authentication.logout.LogoutWebFilter [DefaultWebFilterChain]
    |_ checkpoint ⇢ org.springframework.security.web.server.savedrequest.ServerRequestCacheWebFilter [DefaultWebFilterChain]
    |_ checkpoint ⇢ org.springframework.security.web.server.context.SecurityContextServerWebExchangeWebFilter [DefaultWebFilterChain]
    |_ checkpoint ⇢ org.springframework.security.web.server.context.ReactorContextWebFilter [DefaultWebFilterChain]
    |_ checkpoint ⇢ org.springframework.security.web.server.header.HttpHeaderWriterWebFilter [DefaultWebFilterChain]
    |_ checkpoint ⇢ org.springframework.security.config.web.server.ServerHttpSecurity$ServerWebExchangeReactorContextWebFilter [DefaultWebFilterChain]
    |_ checkpoint ⇢ org.springframework.security.web.server.WebFilterChainProxy [DefaultWebFilterChain]
    |_ checkpoint ⇢ HTTP GET "/api/v1/character/users" [ExceptionHandlingWebHandler]
Stack trace:
        at io.jsonwebtoken.impl.DefaultJwtParser.parse(DefaultJwtParser.java:411) ~[jjwt-impl-0.11.1.jar:0.11.1]
        at io.jsonwebtoken.impl.DefaultJwtParser.parse(DefaultJwtParser.java:541) ~[jjwt-impl-0.11.1.jar:0.11.1]
        at io.jsonwebtoken.impl.DefaultJwtParser.parseClaimsJws(DefaultJwtParser.java:601) ~[jjwt-impl-0.11.1.jar:0.11.1]
        at com.rostenross.webflux.configuration.JWTUtil.getClaimsFromToken(JWTUtil.java:53) ~[classes/:na]
        at com.rostenross.webflux.configuration.JWTUtil.getUsernameFromToken(JWTUtil.java:58) ~[classes/:na]
        at com.rostenross.webflux.configuration.AuthenticationManager.authenticate(AuthenticationManager.java:32) ~[classes/:na]
        at com.rostenross.webflux.configuration.SecurityContextRepository.lambda$3(SecurityContextRepository.java:55) ~[classes/:na]
        at reactor.core.publisher.MonoFlatMap$FlatMapMain.onNext(MonoFlatMap.java:125) ~[reactor-core-3.4.1.jar:3.4.1]
        at reactor.core.publisher.Operators$MonoSubscriber.complete(Operators.java:1784) ~[reactor-core-3.4.1.jar:3.4.1]
        at reactor.core.publisher.MonoFlatMap$FlatMapMain.onNext(MonoFlatMap.java:151) ~[reactor-core-3.4.1.jar:3.4.1]
        at reactor.core.publisher.FluxMapFuseable$MapFuseableSubscriber.onNext(FluxMapFuseable.java:127) ~[reactor-core-3.4.1.jar:3.4.1]
        at reactor.core.publisher.FluxFilterFuseable$FilterFuseableSubscriber.onNext(FluxFilterFuseable.java:118) ~[reactor-core-3.4.1.jar:3.4.1]
        at reactor.core.publisher.Operators$ScalarSubscription.request(Operators.java:2346) ~[reactor-core-3.4.1.jar:3.4.1]
        at reactor.core.publisher.FluxFilterFuseable$FilterFuseableSubscriber.request(FluxFilterFuseable.java:191) ~[reactor-core-3.4.1.jar:3.4.1]
        at reactor.core.publisher.FluxMapFuseable$MapFuseableSubscriber.request(FluxMapFuseable.java:169) ~[reactor-core-3.4.1.jar:3.4.1]
        at reactor.core.publisher.MonoFlatMap$FlatMapMain.onSubscribe(MonoFlatMap.java:110) ~[reactor-core-3.4.1.jar:3.4.1]
        at reactor.core.publisher.FluxMapFuseable$MapFuseableSubscriber.onSubscribe(FluxMapFuseable.java:96) ~[reactor-core-3.4.1.jar:3.4.1]
        at 

现在,这是我的代码

**JWTUtil:**

@Component
public class JWTUtil {
    private Logger log = LoggerFactory.getLogger(JWTUtil.class);

    private String secrete = "RostenRoss35689682_Nestor_Matias_Costantini_16/04/1991_programador-universitario_profesor-de-quimica";
    private String expireTimeInMilliSec="30000";

    public String generateToken(User user) {
        Date now =new Date();
        Map<String, Object> claim = new HashMap<>();
        claim.put("alg", "HS256");
        claim.put("typ", "JWT");
        
        return Jwts.builder()
                .signWith(SignatureAlgorithm.HS256,Base64.getEncoder().encode(secrete.getBytes()))
                .setClaims(claim)
                .setSubject(user.getUsername())
                .setExpiration(new Date(System.currentTimeMillis() + 864000000))
                .claim("rol", user.getAuthorities().stream().collect(Collectors.toList()))
                .compact();
    }
    
    public Claims getClaimsFromToken(String token) {
        return Jwts.parser().setSigningKey(Base64.getEncoder().encodeToString(secrete.getBytes()))
                .parseClaimsJws(token.replace("Bearer ", ""))
                .getBody();
    }
    
    public String getUsernameFromToken(String token) {
        return getClaimsFromToken(token).getSubject();
    }
    
    public Date getExpirationDate(String token) {
        return getClaimsFromToken(token).getExpiration();
    }
    
    public Boolean isTokenExpired(String token) {
        Date expirationDate = getExpirationDate(token);
        log.info("isTokenExpired: "+expirationDate.before(new Date()));
        return expirationDate.before(new Date());
    }
    
    public Boolean isTokenValidated(String token) {
        return !isTokenExpired(token);
    }
}

**SecurityContextRepository:**

    @Component
public class SecurityContextRepository implements ServerSecurityContextRepository {
    
    private Logger log = LoggerFactory.getLogger(SecurityContextRepository.class);
    
    @Autowired
    private AuthenticationManager authenticationManager;

    @Override
    public Mono<Void> save(ServerWebExchange exchange, SecurityContext context) {
        // TODO Auto-generated method stub
        return Mono.empty();
    }

    @Override
    public Mono<SecurityContext> load(ServerWebExchange exchange  ) {
        String bearer = "Bearer ";
        return Mono.justOrEmpty(exchange.getRequest().getHeaders().getFirst(HttpHeaders.AUTHORIZATION))
                .filter(b -> b.startsWith(bearer))
                .map(subs -> {
                    log.info("Substring: "+subs.substring(7));
                    return subs.substring(7);
                    }
                )
                .flatMap(token ->
                    Mono.just(
                            new UsernamePasswordAuthenticationToken(token,
                                                                    token
                                                                    ,Collections.singletonList(new SimpleGrantedAuthority("ROLE_USER"))
                            )       
                    )
                )
                .flatMap(auth -> authenticationManager.authenticate(auth).map(SecurityContextImpl::new));
    }   
}

**身份验证管理器:**

@Component
public class AuthenticationManager implements ReactiveAuthenticationManager{

    private final Logger log = LoggerFactory.getLogger(AuthenticationManager.class);
    
    @Autowired
    private JWTUtil jwtUtil;
    
    @Autowired
    private UserRepository userRepository;

    
    @Override
    public Mono<Authentication> authenticate(Authentication authentication) {
        // TODO Auto-generated method stub
        log.info("autenticaion inicio");
        String token =authentication.getCredentials().toString();
        String userName= jwtUtil.getUsernameFromToken(token);
        return userRepository.findByUsername(userName)
                .flatMap(userDetails -> {
                
                    log.info("role: "+userDetails.getAuthorities().toString());
                    if(userName.equals(userDetails.getUsername()) && jwtUtil.isTokenValidated(token)) {
                        return Mono.just(authentication);
                    }else {
                        log.info("userDetails: "+userDetails.toString());
                        return   Mono.just(authentication);
                    }
                });
    }
    
    
}

安全配置

@Configuration
@EnableWebFluxSecurity
public class SecurityConfig {
    private final Logger log = LoggerFactory.getLogger(SecurityConfig.class);
    
    @Autowired
    private UserRepository repo;
    @Autowired
    private AuthenticationManager authenticationManager;
    @Autowired
    private SecurityContextRepository securityContextRepository;
    
    
    @Bean
    ReactiveUserDetailsService userDdetailService() {
        return (name) -> repo.findByUsername(name);
    }
    
    
    @Bean
    public SecurityWebFilterChain securityWebFilterChain (ServerHttpSecurity http) {
        return http.authorizeExchange(
                authorizedExchangeSpec -> authorizedExchangeSpec
                    .pathMatchers("/api/v1/character/singin","/api/v1/character/login", "/api/v1/character/about","/api/v1/character/all","/api/v1/character/id=**","/api/v1/character/name=**")
                        .permitAll()
                    .anyExchange().authenticated()

        )
                .exceptionHandling()
                .authenticationEntryPoint((response, error) -> Mono.fromRunnable(()->{
                    response.getResponse().setStatusCode(HttpStatus.UNAUTHORIZED);
                })).accessDeniedHandler((response,error) -> Mono.fromRunnable(()->{
                    response.getResponse().setStatusCode(HttpStatus.FORBIDDEN);
                })).and()
                .httpBasic().disable()
                .formLogin().disable()
                .csrf().disable()
                .authenticationManager(authenticationManager)
                .securityContextRepository(securityContextRepository)
                .requestCache().requestCache(NoOpServerRequestCache.getInstance())
                .and()
                .build();
    
                
    }
}

** pom.xml:**

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.4.1</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.rostenross.webflux</groupId>
    <artifactId>CharactersAPI</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>CharactersAPI</name>
    <description>TV and comics charactes reactive API.</description>

    <properties>
        <java.version>11</java.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-webflux</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
            <scope>runtime</scope>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>io.projectreactor</groupId>
            <artifactId>reactor-test</artifactId>
            <scope>test</scope>
        </dependency>
        
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-mongodb-reactive</artifactId>
        </dependency>
        <dependency>
            <groupId>javax.validation</groupId>
            <artifactId>validation-api</artifactId>
            <version>1.0.0.GA</version>
        </dependency>
        
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-security</artifactId>
        </dependency>
        
        <dependency>
            <groupId>io.jsonwebtoken</groupId>
            <artifactId>jjwt-api</artifactId>
            <version>0.11.1</version>
        </dependency>
        
        <dependency>
            <groupId>io.jsonwebtoken</groupId>
            <artifactId>jjwt-impl</artifactId>
            <version>0.11.1</version>
            <scope>runtime</scope>
        </dependency>
        
        <dependency>
            <groupId>io.jsonwebtoken</groupId>
            <artifactId>jjwt-jackson</artifactId>
            <version>0.11.1</version>
            <scope>runtime</scope>
        </dependency>
                
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

</project>

如果您需要更多信息,请告诉我。我在网上到处找,一无所获。

提前谢谢你们。

标签: springspring-securityspring-webfluxbearer-tokenjwt-auth

解决方案


推荐阅读