【问题标题】:Principal Object is null when jwt token is not valid当 jwt 令牌无效时,主体对象为空
【发布时间】:2020-09-08 19:26:25
【问题描述】:

我正在使用 Spring Security 使用 jwt 令牌对用户进行身份验证。
身份验证工作正常,当令牌格式错误或过期时,我得到 403 Http 状态,如下面的配置所示:

 @Bean
public SecurityWebFilterChain securitygWebFilterChain(ServerHttpSecurity http) {
    return http
            .exceptionHandling()
            .authenticationEntryPoint((swe, e) -> {
                return Mono.fromRunnable(() -> {
                    swe.getResponse().setStatusCode(HttpStatus.UNAUTHORIZED); 
                });
            }).accessDeniedHandler((swe, e) -> {
                return Mono.fromRunnable(() -> {
                    swe.getResponse().setStatusCode(HttpStatus.FORBIDDEN);
                });
            }).and()
            .csrf().disable()
            .formLogin().disable()
            .httpBasic().disable()
            .authenticationManager(authenticationManager)
            .securityContextRepository(securityContextRepository)
            .authorizeExchange()
            .pathMatchers(HttpMethod.OPTIONS).permitAll()
            .pathMatchers("/**").permitAll()
            .anyExchange().authenticated()
            .and().build();
}

但是,当我使用 Spring 安全上下文中的 Principal 或 Authentication 从 jwt 令牌中获取用户信息时,如下代码所示:

@ResponseStatus(HttpStatus.OK)
@GetMapping("/me")
public Mono<ClientDTO> find(final Principal principal) {
    return this.clientService.findByMail(principal.getName());
}

如果令牌格式错误或过期,我会从 Principal 对象中获得空指针异常和 500 https 状态。

【问题讨论】:

  • 不是 .pathMatchers("/**").permitAll() 禁用端点的 jwt 检查吗?
  • 正如@Lacuno 指出的那样, permitAll 然后假设会有一个有效的委托人会适得其反。如果匿名委托人已过期或格式不正确,您似乎想要一个匿名委托人。

标签: java spring spring-boot spring-security


【解决方案1】:

如果我的回答对你的问题没有帮助,我想马上道歉,因为我没有看到你所有的代码。


我有一个合适的项目,我能够在类似的条件下检查 Principal 对象的工作,并且一切都适合我。所以,问题不在于它。


您可能在令牌验证方法中抛出异常。类似的东西:

public boolean validateToken(String token) {
    try {
        Jws<Claims> claims = Jwts.parser().setSigningKey(secret).parseClaimsJws(token);
        return true;
    } catch (JwtException | IllegalArgumentException e) {
        throw new JwtAuthenticationException("JWT token is expired or invalid", e);
    }
}

在这种情况下,异常在您在配置中捕获之前被捕获。解决方案可能是拒绝令牌验证方法中的新异常,转而将信息输出到日志:

public boolean validateToken(String authToken) {
      try {
         Jwts.parser().setSigningKey(key).parseClaimsJws(authToken);
         return true;
      } catch (io.jsonwebtoken.security.SecurityException | MalformedJwtException e) {
         log.info("Invalid JWT signature.");
         log.trace("Invalid JWT signature trace: {}", e);
      } catch (ExpiredJwtException e) {
         log.info("Expired JWT token.");
         log.trace("Expired JWT token trace: {}", e);
      } catch (UnsupportedJwtException e) {
         log.info("Unsupported JWT token.");
         log.trace("Unsupported JWT token trace: {}", e);
      } catch (IllegalArgumentException e) {
         log.info("JWT token compact of handler are invalid.");
         log.trace("JWT token compact of handler are invalid trace: {}", e);
      }
      return false;
}

如果这对你有帮助,我会很高兴。否则,我需要有关您的代码的更多信息。

【讨论】:

    【解决方案2】:
    @ResponseStatus(HttpStatus.OK)
    @GetMapping("/me")
    public Mono<ClientDTO> find(final Principal principal) { 
    
    if(principal!=null) return this.clientService.findByMail(principal.getName());
    else throw new CustomTokenExpiredException();
    }
    

    并删除
    .pathMatchers("/**").permitAll()

    【讨论】:

      猜你喜欢
      • 2021-04-13
      • 1970-01-01
      • 2021-09-25
      • 2019-06-03
      • 2019-03-19
      • 2022-10-25
      • 2020-05-24
      • 2018-07-14
      • 2020-04-19
      相关资源
      最近更新 更多