6

在本周给出题系统加了Travis的自动测试,前一天还能通过,但第二天上课回来却报错了,原因是加了权限校验,是通过Spring Security实现的,不过初始化用户的时候也初始化了权限了呀。打上断点debug可以发现,该有的初始化状态都有
image.png

但是测试还是报了403,为什么呢?

解决办法

测试时用户是通过@WithMockUser实现的,其他测试类通过继承ControllerTest获得基础配置

image.png

和潘哥一番查找,发现spring已经替我们准备好了解决办法,只需在@WithMockUser添加相应的属性即可

image.png

添加相应的角色:

@WithMockUser(username = "admin", password = "admin", roles = "COLLEGE")

单元测试顺利通过。

关于@WithMockUserSpring Security测试的更详细内容可以查看官方文档

为何会这样

user里面已经有了相应的角色,为何还需要在注解中配置角色呢?

知其然还需知其所以然才行,所以尝试着去寻找为何这样,先自己在网上搜了搜,没整太明白,问了问张喜硕学长,学长给我解释了一下。以下内容需要Spring Security的基础知识。

在本项目中,登录流程如下:

  1. 前台传一个用户到后台
  2. 通过继承自UserDetailsServiceYunzhiAuthService生成了一个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);
        }
    }
  3. 和数据库中的user比较密码
  4. 正确则登录成功,并存入session

而权限是在UserDetailsServiceloadUserByUsername中生成的。

当使用@WithMockUser时,实际上并没有进行登录操作,自然无法从数据库中的用户中提取出相应的权限,而在注解中配置的权限会直接放入 session中。

image.png


笙歌会停
1k 声望45 粉丝

代码成就万世基积沙镇海 梦想永在凌云意意气风发