在本周给出题系统加了Travis的自动测试,前一天还能通过,但第二天上课回来却报错了,原因是加了权限校验,是通过Spring Security实现的,不过初始化用户的时候也初始化了权限了呀。打上断点debug可以发现,该有的初始化状态都有
但是测试还是报了 403
,为什么呢?
测试时用户是通过 @WithMockUser
实现的,其他测试类通过继承 ControllerTest
获得基础配置
和潘哥一番查找,发现spring已经替我们准备好了解决办法,只需在 @WithMockUser
添加相应的属性即可
添加相应的角色:
@WithMockUser(username = "admin", password = "admin", roles = "COLLEGE")
单元测试顺利通过。
关于 @WithMockUser
和 Spring Security
测试的更详细内容可以查看 官方文档 。
user里面已经有了相应的角色,为何还需要在注解中配置角色呢?
知其然还需知其所以然才行,所以尝试着去寻找为何这样,先自己在网上搜了搜,没整太明白,问了问张喜硕学长,学长给我解释了一下。以下内容需要Spring Security的基础知识。
在本项目中,登录流程如下:
通过继承自 UserDetailsService
的 YunzhiAuthService
生成了一个 org.springframework.security.core.userdetails.User
@Component public class YunzhiAuthService implements UserDetailsService { private static final Logger logger = LoggerFactory.getLogger(YunzhiAuthService.class); private final UserRepository userRepository; public YunzhiAuthService(UserRepository userRepository) { this.userRepository = userRepository; } @Transactional @Override public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException { logger.debug("根据用户名查询用户"); User user = userRepository.findByUsername(username); if (user == null) { logger.error("用户名不存在"); throw new UsernameNotFoundException("用户名不存在"); } logger.debug("获取用户授权菜单"); Set<Menu> menus = new HashSet<>(); for (Role role : user.getRoles()) { menus.addAll(role.getMenus()); } logger.debug("初始化授权列表"); List<SimpleGrantedAuthority> authorities = new ArrayList<>(); logger.debug("根据菜单进行 API 授权"); for (Menu menu : menus) { authorities.add(new SimpleGrantedAuthority(menu.getRoleName())); } logger.debug("构造用户"); return new org.springframework.security.core.userdetails.User(username, user.getPassword(), authorities); } }
session
而权限是在 UserDetailsService
的 loadUserByUsername
中生成的。
当使用 @WithMockUser
时,实际上并没有进行登录操作,自然无法从数据库中的用户中提取出相应的权限,而在注解中配置的权限会直接放入 session
中。