【问题标题】:Request processing failed: java.lang.ClassCastException: class CustomUserDetails cannot be cast to class User请求处理失败:java.lang.ClassCastException:类 CustomUserDetails 无法转换为类 User
【发布时间】:2023-02-14 21:46:23
【问题描述】:

问题

我在我的控制器类中创建了一个端点/update2fa,但是当我尝试在 Postman 或浏览器中测试它时,我无法做到。

目标是使用参数 use2FA 发出 POST 请求并从后端接收响应。

我得到的错误如下(已修整):

exception [Request processing failed: java.lang.ClassCastException: class com.my.app.service.CustomUserDetails cannot be cast to class com.my.app.model.User

我试过的

之前,我收到了错误的 CSRF 消息,因此我尝试使用 CSRF 令牌创建 AJAX 调用,但没有解决问题:

<script type="text/javascript">
  $(document).ready(function() {
    $.ajax({
      url: '/update2fa',
      type: 'POST',
      data: {use2FA: true},
      beforeSend: function(xhr) {
        xhr.setRequestHeader('X-CSRF-TOKEN', $('meta[name="_csrf"]').attr('content'));
      },
      success: function(response) {
        console.log('Success!', response);
      },
      error: function(error) {
        console.error('Error!', error);
      }
    });
  });
</script>

接下来,我将 .csrf().disable() 添加到我的 SecurityFilterChain,这导致了我之前描述的错误。

我找到了这个old question,但我无法理解解决方案,很可能在将近 8 年后,Spring 中的许多事情都发生了变化。

信息很明确;类之间存在 Cast 问题,但我不确定如何解决它。我是 Spring 的新手。

用户控制器类:

@RestController
public class UserController {
    @Autowired
    private UserRepository userRepo;
    private final CustomUserDetailsService userDetailsService;
    public UserController(CustomUserDetailsService userDetailsService) {
        this.userDetailsService = userDetailsService;
    }
    @PostMapping("/update2fa")
    public String modifyUser2FA(@RequestParam("use2FA") final boolean use2FA) throws UnsupportedEncodingException {
        Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
        UserDetails userDetails = userDetailsService.loadUserByUsername(authentication.getName());
        User user = (User) userDetails;
        user.setUse2FA(use2FA);
        if (use2FA) {
            String qrUrl = userDetailsService.generateQRUrl(user);
            return qrUrl;
        } else{
            return "2FA disabled";
        }
    }

CustomUserDetailService 类:

@Service
public class CustomUserDetailsService implements UserDetailsService {
    public static String QR_PREFIX = "https://chart.googleapis.com/chart?chs=200x200&chld=M%%7C0&cht=qr&chl=";
    public static String APP_NAME = "My app";
    @Autowired
    private UserRepository userRepo;
    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        User user = userRepo.getUserByUsername(username);
        if (user == null) {
            throw new UsernameNotFoundException("User not found");
        }
        return new CustomUserDetails(user);
    }
    public String generateQRUrl(User user) throws UnsupportedEncodingException {
        return QR_PREFIX + URLEncoder.encode(String.format("otpauth://totp/%s:%s?secret=%s&issuer=%s", APP_NAME, user.getUsername(), user.getSecretKey(), APP_NAME), "UTF-8");
    }
}

用户库类:

public interface UserRepository extends JpaRepository<User, Long> {
    @Query("SELECT u FROM User u WHERE u.username = :username")
    User getUserByUsername(@Param("username") String username);
}

自定义用户详细信息类:

public class CustomUserDetails implements UserDetails {
    private User user;
    public CustomUserDetails(User user) { this.user = user;}
    @Override
    public Collection<? extends GrantedAuthority> getAuthorities() { return null; }
    @Override
    public String getPassword() { return user.getPassword(); }
    @Override
    public String getUsername() { return user.getUsername(); }
    @Override
    public boolean isAccountNonExpired() { return true; }
    @Override
    public boolean isAccountNonLocked() { return true; }
    @Override
    public boolean isCredentialsNonExpired() { return true; }
    @Override
    public boolean isEnabled() { return true; }
    public String getFullName() { return user.getFirst_name() + " " + user.getLast_name(); }
}

【问题讨论】:

  • 这是你的问题 - User user = (User) userDetails;。您正在将 UserDetails 转换为 User,而实际的类实际上是 CustomUserDetails。
  • @Chaosfire 是的,这绝对是导致错误的那一行,但我对如何从身份验证对象中转换或提取用户对象有点困惑。我一直在尽力而为,但似乎无法提出更好的解决方案。为新手问题道歉 - 我对 Spring 完全陌生。
  • 从存储库中获取用户,无论如何你已经自动装配它了。 UserDetailsService 不应该用于此,你只会让事情变得更复杂。

标签: java spring spring-boot spring-security


【解决方案1】:

我找到了一个修复:

@PostMapping("/update2fa")
public String modifyUser2FA(@RequestParam("use2FA") final boolean use2FA) throws UnsupportedEncodingException {
    CustomUserDetails userDetails = (CustomUserDetails) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
    String username = userDetails.getUsername();
    User user = userRepo.getUserByUsername(username);
    user.setUse2FA(use2FA);
    if (use2FA) {
        String qrUrl = userDetailsService.generateQRUrl(user);
        return qrUrl;
    }
    return "2FA disabled";
}

我会把它留在这里,以防它对某人有帮助。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-10-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-07-01
    • 1970-01-01
    相关资源
    最近更新 更多