当前位置:   article > 正文

011-若依pro(ruoyi-vue-pro)的功能权限RBAC学习_ruoyi vue pro

ruoyi vue pro

RBAC

用户 -> 角色 -> 菜单 三者之间关联, 3张单表+2张关联表

  • 用户 system_users
    用户账号, 部门, 手机等
  • 角色 system_role
    角色, 字符串标识, 数据权限标识等
  • 菜单 system_menu
    菜单名, 权限标识, 前端组件名和路径等
  • 用户和角色关联表 system_user_role
  • 角色和菜单关联表 system_role_menu

token认证

Spring Security + Token
(不使用jwt是因为jwt无状态, 没法登出, 只能过期登出. 而token 存表可以)

使用流程:
登录 -> 拿到token -> 访问接口带上token

登录

Controller 入口
cn.iocoder.yudao.module.system.controller.admin.auth.AuthController#login

流程

  1. @Valid校验VO
  2. 校验验证码
    通过第三方直接调用
  3. 校验用户名和密码
    通过查数据库看用户名是否存在
    通过security的PasswordEncoder看密码是否正确
  4. token生成

表名

  • system_users
    用户表

token

流程

  1. 找到system_oauth2_client里的过期时间等配置
  2. 创建RefreshToken, 插入数据库
  3. 创建登录AccessToken, 插入数据库

表名

  • system_oauth2_client
    OAuth2配置默认token过期时间和refresh token过期时间
  • system_oauth2_access_token
    记录了用户 token, refresh token, 过期时间

前端使用

前端调用其它接口,需要在请求头带上 Token 进行访问
Authorization: Bearer d2a3cdbc6c53470db67a582bd115103f

后端的过滤器:
cn.iocoder.yudao.framework.security.core.filter.TokenAuthenticationFilter

流程:

  1. 从request里拿到header里的token
  2. 拿到用户类型
  3. 检测accessToken, 先从redis里拿, 找不到再从mysql里找并存入redis里(设置好过期时间)
  4. 设置登录用户到上下文里(SecurityContextHolder)和request

权限注解

@PreAuthorize 注解

① 基于【权限标识】的权限控制
权限标识,对应 system_menu 表的 permission 字段,推荐格式为 {系统}:{模块}:{操作},例如说 system:admin:add 标识 system 服务的添加管理员

// 符合 system:user:list 权限要求
@PreAuthorize("@ss.hasPermission('system:user:list')")

// 符合 system:user:add 或 system:user:edit 权限要求即可
@PreAuthorize("@ss.hasAnyPermissions('system:user:add,system:user:edit')")

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

② 基于【角色标识】的权限控制
权限标识,对应 system_role 表的 code 字段, 例如说 super_admin 超级管理员、tenant_admin 租户管理员

// 属于 user 角色
@PreAuthorize("@ss.hasRole('user')")

// 属于 user 或者 admin 之一
@PreAuthorize("@ss.hasAnyRoles('user,admin')")
  • 1
  • 2
  • 3
  • 4
  • 5

原理:
调用beanName为ss的方法
YudaoSecurityAutoConfiguration里可以看到

    @Bean("ss") // 使用 Spring Security 的缩写,方便使用
    public SecurityFrameworkService securityFrameworkService(PermissionApi permissionApi) {
        return new SecurityFrameworkServiceImpl(permissionApi);
    }
  • 1
  • 2
  • 3
  • 4

一层一层走下去, 发现最终是调用
cn.iocoder.yudao.module.system.service.permission.PermissionService
的实现类

hasPermission 和 hasAnyPermissions

流程 rbac 的用法

  1. 去system_user_role查用户有角色id
  2. 去system_role查角色
  3. 比较角色权限和注解里需要的权限,
    1. system_menu里找到注解定义的permission对应的id列表
    2. system_role_menu里找到角色对应的menu的id列表
    3. 两者存在交集, 说明有权限
  4. 如果是超管也

hasRole和hasAnyRoles

流程

  1. 获取用户的权限列表
  2. 比较注解里的权限的交集

@PreAuthenticated

自定义注解, 声明登录的用户才允许访问
cn.iocoder.yudao.framework.security.core.aop.PreAuthenticatedAspect
用aop实现

流程

  1. SecurityContext里拿用户信息Authentication(通过cn.iocoder.yudao.framework.security.core.filter.TokenAuthenticationFilter 过滤器里设置)

自定义api的权限配置

方式一:自定义 AuthorizeRequestsCustomizer 实现

AuthorizeRequestsCustomizer的实现
比如各个module里的XxxSecurityConfiguration的配置的bean, return new AuthorizeRequestsCustomizer(), 重写customize方法

可以看
cn.iocoder.yudao.module.infra.framework.security.config.SecurityConfiguration#authorizeRequestsCustomizer方法

    @Bean("infraAuthorizeRequestsCustomizer")
    public AuthorizeRequestsCustomizer authorizeRequestsCustomizer() {
        return new AuthorizeRequestsCustomizer() {

            @Override
            public void customize(ExpressionUrlAuthorizationConfigurer<HttpSecurity>.ExpressionInterceptUrlRegistry registry) {
                // Swagger 接口文档
                registry.antMatchers("/v3/api-docs/**").permitAll()
                        .antMatchers("/swagger-ui.html").permitAll()
                        .antMatchers("/swagger-ui/**").permitAll()
                        .antMatchers("/swagger-resources/**").anonymous()
                        .antMatchers("/webjars/**").anonymous()
                        .antMatchers("/*/api-docs").anonymous();
                // 积木报表
                registry.antMatchers("/jmreport/**").permitAll();
                // Spring Boot Actuator 的安全配置
                registry.antMatchers("/actuator").anonymous()
                        .antMatchers("/actuator/**").anonymous();
                // Druid 监控
                registry.antMatchers("/druid/**").anonymous();
                // Spring Boot Admin Server 的安全配置
                registry.antMatchers(adminSeverContextPath).anonymous()
                        .antMatchers(adminSeverContextPath + "/**").anonymous();
                // 文件读取
                registry.antMatchers(buildAdminApi("/infra/file/*/get/**")).permitAll();
            }

        };
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29

方式二: @PermitAll

在 API 接口上添加 @PermitAll 注解
比如
cn.iocoder.yudao.module.member.controller.app.auth.AppAuthController

    @PostMapping("/logout")
    @PermitAll
    @Operation(summary = "登出系统")
    public CommonResult<Boolean> logout(HttpServletRequest request) {
        String token = SecurityFrameworkUtils.obtainAuthorization(request, securityProperties.getTokenHeader());
        if (StrUtil.isNotBlank(token)) {
            authService.logout(token);
        }
        return success(true);
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

方式三: yudao.security.permit-all-urls 配置项

cn.iocoder.yudao.framework.security.config.SecurityProperties
会解析到成员变量permitAllUrls里

yudao:
  security:
    permit-all-urls:
      - /admin-ui/** # /resources/admin-ui 目录下的静态资源
      - /admin-api/xxx/yyy
  • 1
  • 2
  • 3
  • 4
  • 5
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/article/detail/49013
推荐阅读
相关标签
  

闽ICP备14008679号