【发布时间】: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