org.springframework.security.core.userdetails.User 不能转换为 MyUserDetails (Junit 5)
Posted
技术标签:
【中文标题】org.springframework.security.core.userdetails.User 不能转换为 MyUserDetails (Junit 5)【英文标题】:org.springframework.security.core.userdetails.User cannot be cast to MyUserDetails (Junit 5) 【发布时间】:2018-12-15 22:44:01 【问题描述】:我正在使用 Junit 5 测试 Web 应用程序,除了
SecurityContextHolder.getContext().getAuthentication().getPrincipal()
在运行测试用例时控制器类中的线
的线返回对象代码org.springframework.security.core.userdetails.User 而不是 MyUserDetails (而在 Spring Boot 中运行的应用程序返回对象是 MyUserDetails 并且代码运行良好)
我的测试用例类
@ExtendWith(SpringExtension.class)
@WebMvcTest(VendorController.class)
@AutoConfigureMockMvc
class VendorControllerTest
@Autowired
private MockMvc mvc;
@Test
void test() throws Exception
mvc.perform(MockMvcRequestBuilders.post("/vendor/user/getVendorList").with(csrf().asHeader())
.param("iDisplayStart","0")
.param("iDisplayLength", "10")
.param("iSortCol_0", "0")
.param("sSortDir_0", "asc")
.param("sSearch","")
.with(user("username").password("password").roles("2"))).andExpect(status().isOk());
我缺少什么代码,以便在使用 Junit 5 运行测试用例时返回 org.springframework.security.core.userdetails.User 对象,但如果我通过 Spring Boot 运行项目,则可以正常工作。
添加 UserDetailsService 实现代码
@Service("userDetailsService")
public class MyUserDetailsService implements UserDetailsService
@Autowired
private UserSvc userSvc;
@Transactional(readOnly=true)
@Override
public UserDetails loadUserByUsername(final String username) throws UsernameNotFoundException
com.esociety.entity.UserEntity userEntity = userSvc.findByUserName(username);
List<GrantedAuthority> authorities = buildUserAuthority(userEntity.getUserType());
return buildUserForAuthentication(userEntity, authorities);
private User buildUserForAuthentication(com.esociety.entity.UserEntity userEntity, List<GrantedAuthority> authorities)
MyUserDetails myUserDetails = new MyUserDetails (userEntity.getUsername(), userEntity.getPassword(), userEntity.isEnabled(), userEntity.isAccountNonExpired(), userEntity.isCredentialsNonExpired(),userEntity.isAccountNonLocked(),authorities,userEntity.getUserId(),userEntity.getSocietyId(),userEntity.getUserType(),userEntity.getFirstName(),userEntity.getMiddleName(),userEntity.getLastName());
return myUserDetails;
private List<GrantedAuthority> buildUserAuthority(String userType)
Set<GrantedAuthority> setAuths = new HashSet<GrantedAuthority>();
// Build user's authorities
setAuths.add(new SimpleGrantedAuthority(userType));
List<GrantedAuthority> Result = new ArrayList<GrantedAuthority>(setAuths);
return Result;
MyUserDetails 类
public class MyUserDetails extends User
public MyUserDetails(String username, String password, boolean enabled,
boolean accountNonExpired, boolean credentialsNonExpired,
boolean accountNonLocked,
Collection<? extends GrantedAuthority> authorities, Long userId,
Long societyId, String userType, String firstName,
String middleName, String lastName)
super(username, password, enabled, accountNonExpired,
credentialsNonExpired, accountNonLocked, authorities);
this.userId = userId;
this.societyId = societyId;
this.userType = userType;
this.firstName = firstName;
this.middleName = middleName;
this.lastName = lastName;
// getter setter goes here
【问题讨论】:
您是否使用UserDetailsService
的实现来返回MyUserDetails
?如果是这样,您如何使该服务可用于测试(因为您没有加载整个 SpringApplication 上下文)?
@AndreiDamian-Fekete 我添加了 userDetailsService 实现代码。当我登录应用程序时,会调用 buildUserForAuthentication 方法并创建一个扩展 User 的 MyUserDetails 对象,但我相信如果在 Junit 测试时应该调用 buildUserForAuthentication 方法,那么我将不会遇到类转换异常问题。
【参考方案1】:
问题是您使用的是SecurityMockMvcRequestPostProcessors.user(String username)
RequestPostProcessor
,它将创建并返回一个org.springframework.security.core.userdetails.User
,它是UserDetails
的实现,但不是您想要的MyUserDetails
。
相反,您可以使用SecurityMockMvcRequestPostProcessors.user(UserDetails user)
,它允许提交您自己的UserDetails
实现,在本例中为您想要的MyUserDetails
。
改变你的测试如下:
@Test
void test() throws Exception
mvc.perform(MockMvcRequestBuilders.post("/vendor/user/getVendorList").with(csrf().asHeader())
.param("iDisplayStart","0")
.param("iDisplayLength", "10")
.param("iSortCol_0", "0")
.param("sSortDir_0", "asc")
.param("sSearch","")
.with(user(new MyUserDetails ("username", "password", true, true, true,true, Arrays.asList(new SimpleGrantedAuthority("2")),1,1,USER_TYPE,"FirstName","MiddleName","LastName")))).andExpect(status().isOk());
参考 Spring Security Source code
【讨论】:
它说将参数 1 转换为 RequestPostProcessor 或让 MyUserDetails 实现 RequestPostProcessor.with( (RequestPostProcessor) new MyUserDetails ("username", "password", true, true, true,true, Arrays.asList(new SimpleGrantedAuthority("2")),2L,1L,"ROLE_2","Firstname","middlename","Lastname"))).andExpect(status().isOk());
,但我仍然遇到同样的错误
您不能将 MyUserDetails 转换为 RequestPostProcessor。您的代码更改甚至运行了吗?
如果我不强制转换,它会给出编译错误,是的,代码运行正常
对代码进行了少量更改,并且可以正常工作 .with( user( new MyUserDetails ("username", "password", true, true, true,true, Arrays.asList(new SimpleGrantedAuthority("2")),2L,1L,"ROLE_2","Firstname","middlename","Lastname")))).andExpect(status().isOk());
参考 custom_UserDetails
SecurityMockMvcRequestPostProcessors.user(UserDetails user)
是我使用@WithMockUser
编写集成单元测试以获得精细角色和权限的关键。感谢您为我指明正确的方向。以上是关于org.springframework.security.core.userdetails.User 不能转换为 MyUserDetails (Junit 5)的主要内容,如果未能解决你的问题,请参考以下文章