我有一个POST方法,用于发送Item
。每个项目包含作者的用户ID。为获取作者ID,我使用:(User)SecurityContextHolder.getContext().getAuthentication().getPrincipal();
但是在测试中,由于结果,这不起作用:
org.springframework.web.util.NestedServletException: Request processing failed; nested exception is java.lang.ClassCastException: org.springframework.security.core.userdetails.User cannot be cast to ru.pravvich.domain.User
POST方法:
@PostMapping("/get_all_items/add_item_page/add_item")
public String addItem(@RequestParam(value = "description") final String description) {
final User user = (User) SecurityContextHolder
.getContext()
.getAuthentication()
.getPrincipal();
final Item item = new Item();
item.setDescription(description);
item.setAuthorId(user.getId());
service.add(item);
return "redirect:/get_all_items";
}
并测试:
@Test
@WithMockUser(username = "user", roles = "USER")
public void whenPostThenAdd() throws Exception {
Item item = new Item();
item.setDescription("test");
mvc.perform(
post("/get_all_items/add_item_page/add_item")
.param("description", "test")
).andExpect(
status().is3xxRedirection()
);
verify(itemService, times(1)).add(item);
}
为什么ClassCastException
没有丢弃然后我从浏览器表单发送数据?如何解决这个问题?
谢谢。
更新
@Service
public class UserService implements UserDetailsService {
@Autowired
private UserRepository userRepo;
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
User user = userRepo.findByUsername(username);
if (user == null) user = new User();
return user;
}
}
答案 0 :(得分:4)
.
可帮助您注入WHERE t1.siteID = 1 AND deleted = 0 AND (t2.toUserID = 3 OR t2.userID = 3) GROUP BY
个对象并执行测试,但在这种情况下,您需要一个自定义用户对象LIMIT 1
。
为什么它适用于浏览器表单?这是因为主体来自您的身份验证过程,例如,如果您有自己的 BITS 16
ORG 100h
start:
;I want to write a byte into a register on the sound card or NIC or
;whatever. So, I'm using a move instruction to accomplish that where X
;is the register's memory mapped or IO mapped address.
mov X,11h
times 510 - ($ - $$) db 0
dw 0xaa55
以便返回自定义@WithMockUser
,则当您通过Web执行身份验证时,此过程会在正常情况下发生表单,但在测试用例场景中,至少您配置测试用例并告知您的自定义实现并不会发生。让我们看一个例子:
从用户扩展的自定义用户类(在此更新)
org.springframework.security.core.userdetails.User
自定义用户详细信息服务(在此更新)
ru.pravvich.domain.User
最后使用UserDetailsService
测试用例通知测试应该调用自定义ru.pravvich.domain.User
实现的 //MySpring user is just a class that extends from
//org.springframework.security.core.userdetails.User
//org...security....User implements UserDetailsService that is the
//the reason why I can return this class from loadUserByUsername method, you will see it later
//it helps me to wrap my own User definition
public class MySpringUser extends User {
//this is my own user definition, where all my custom fields are defined
private MyUser user;
//the constructor expect for myUser and then I call the super
//constructor to fill the basic fields that are mandatory for spring
//security in order to perform the authentication process
public MySpringUser(MyUser myUser, Collection<? extends GrantedAuthority> authorities) {
super(myUser.getUsername(), myUser.getPassword(), myUser.isEnabled()
, true, true, true, authorities);
this.setUser(myUser);
}
public MyUser getUser() {
return user;
}
public void setUser(MyUser user) {
this.user = user;
}
//this is an example of how to get custom fields a custom id for example
public Long getId(){
return this.getUser().getId();
}
}
方法,在这种情况下,您可以自由地将主体转换为您的自定义用户对象。
@Service
public class MyUserService implements UserDetailsService {
@Autowired
MyUserRepository myUserRepository;
//Principal
@Override
public UserDetails loadUserByUsername(String s) throws UsernameNotFoundException {
//Here I get the User that I defined for my own domain structure
MyUser myUser = myUserRepository.findFirstByUsername(s);
//Here I return a new User object, in this case MySpringUser is
//just a class that extends from User class, its constructor
//receive myUser object as parameter in order to get my own custom fields later
return new MySpringUser(myUser,AuthorityUtils.createAuthorityList("ADMIN"));
}
}
这就是在控制器中执行强制转换的方式,就像你的
一样@WithUserDetails
(在这里更新)我还上传了一个完整的例子到我的git repo,你可以下载它并尝试它以便给你一个更清晰的视图,当然这只是一个选项,还有其他的,例如,而不是extends spring User类,您可以创建自己的类来实现loadUserByUsername
接口,替代方案将取决于您的需求。
希望这个替代方案可以帮助你。
答案 1 :(得分:0)
Spring Security&#39; @WithMockUser
使用org.springframework.security.core.userdetails.User
对象填充安全上下文,这就是您遇到此异常的原因。 documentation对此很清楚:
身份验证的主体是Spring Security的用户对象
ClassCastException
的一个可能解决方案是简单地重复使用Spring User
类并使用getUsername()
返回作者ID,或者如果您必须使用{{1}对象,找到另一种方法来填充测试的安全上下文。