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匿名请求

ruoyi接口权限校验

  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());               }           }       }   }

发表评论

评论已关闭。

相关文章