• ruoyi接口权限校验


    此文章属于ruoyi项目实战系列

    ruoyi系统在前端主要通过权限字符包含与否来动态显示目录和按钮。为了防止通过http请求绕过权限限制,后端接口也需要进行相关权限设计。

    @PreAuthorize使用

    由于对@PreAuthorize原理还不够深入了解,所以此处只粗浅讲解在ruoyi项目是如何应用的。
    在请求调用接口前,被@preAuthorize注解的接口需要首先通过验证。通过注解参数value()返回值truefalse来判断是否有权限。

    public @interface PreAuthorize {  
        String value();  
    }
    

    Ruoyi并没有使用原生的Spel表达式,而是使用了自定义的PermissionService类,通过其中自定义方法hasPermi(String Permission) 来进行权限判断。注解使用举例:@PreAuthorize("@ss.hasPermi('system:menu:list')")

    public boolean hasPermi(String permission)  
    {  
        if (StringUtils.isEmpty(permission))//用注解就必须有permission值  
        {  
            return false;  
        }  
        LoginUser loginUser = SecurityUtils.getLoginUser();  
        if (StringUtils.isNull(loginUser) ||
         CollectionUtils.isEmpty(loginUser.getPermissions()))  
        {  
            return false;  
        }  
        return hasPermissions(loginUser.getPermissions(), permission);
    
    private boolean hasPermissions(Set<String> permissions, String permission)  
    {  
        return permissions.contains(ALL_PERMISSION) ||
         permissions.contains(StringUtils.trim(permission)); //判断是否持有"所有权限”字符,或者持有该权限 
    }
    

    接口权限校验流程

    粗略用两个例子来讲解前端请求如何经过后端接口权限校验。

    Login匿名请求

    1. Login请求路径是/login,在过滤器链中被AnnoymousAuthenticationFilter添加匿名authentication到Spring上下文里。由于/login请求在SecurityConfig.java里设置成匿名请求,所以可以成功到达SysLoginController

    2. 调用SysLoginService.login方法,关键的一行命令:

      Authentication authentication = authenticationManager  
      .authenticate(new UsernamePasswordAuthenticationToken(username, password));
      

      authenticationManager.authenticate()是钩子方法,在AbstractUserDetailsAuthenticationProvider中实现,会根据传入的token类型来自动选择,此处UsernamePasswordAuthenticationToken将由DaoAuthenticationProvider来处理(不清楚的话可以前后打两个断点看调用栈)。

    3. DaoAuthenticationProvider中可以看到关键的一行:

      UserDetails loadedUser = this.getUserDetailsService()
      .loadUserByUsername(username);
      

      这会调用我们自定义实现的UserDetailsServiceImpl#loadUserByUsername方法(如流程图所示),获得user信息。至于为什么会使用自定义方法,因为在SecurityConfig.java中进行了配置

      @Override  
      protected void configure(AuthenticationManagerBuilder auth) throws Exception  
      {  
          auth.userDetailsService(userDetailsService).passwordEncoder(bCryptPasswordEncoder());  
      }
      
    4. 生成token,然后返回。

    已登录请求

    已登录请求流程较简单,在流程图里的some filters里会通过自定义的JwtAuthenticationFilter,其中会通过token获得user信息,然后装入Spring的上下文,方便提取使用。

    曾纠结踩坑的点

    由于对SpringSecurity较陌生,虽然功能强大,但其复杂性也是大大提高,所以调试项目的同时翻看了很多入门博客文章,其中都不约而同的提到了UsernamePasswordAuthenticationFilter,可是我在实战项目中反复调试都没有看到这个过滤器的调用。

    原因:Security配置文件需要添加httpSecurity.formLogin()启用表单登录才会使用该filter。查看项目使用的所有filter可以使用以下测试代码:

    
    class RuoYiApplicationTest {  
        @Autowired  
        private FilterChainProxy filterChainProxy;  
        @Test  
        public void test() {  
            List<SecurityFilterChain> filterChains = filterChainProxy.getFilterChains();  
            for(SecurityFilterChain sfc:filterChains){  
                for(Filter filter:sfc.getFilters()){  
                    System.out.println(filter.getClass().getName());  
                }  
            }  
        }  
    }
  • 相关阅读:
    极简网络用户手册(1)
    vscode使用svn
    455. 分发饼干
    DNS (Domain Name System)域名系统工作原理
    企业通过5G双DNN同时接入Internet和IMS配置案例
    数组名是什么
    郭明錤:Meta收缩有利于VR竞品发展,苹果XR头显将改变行业规则
    原型制作与图解
    腾讯mini项目-【指标监控服务重构】2023-08-13
    Vue React大屏可视化进阶
  • 原文地址:https://www.cnblogs.com/allworldg/p/ruoyi-learn-1.html