4.功能权限

文章详细介绍了如何在系统中实现基于角色的权限控制,包括使用权限标识进行细粒度控制,通过SpringSecurity的@PreAuthorize注解进行预授权,以及自定义登录判断。同时,文章还展示了如何配置自定义权限,如Swagger接口的匿名访问和SpringBootAdminServer的安全设置。
摘要由CSDN通过智能技术生成

基于角色的权限控制,用户分配角色,角色分配菜单。

1. 权限注解

1.基于【权限标识】的权限控制

权限标识,对应 system_menu 表的 permission 字段,推荐格式为 {系统}:{模块}:{操作},例如说 system:admin:add 标识 system 服务的添加管理员。
在这里插入图片描述

  • @PreAuthorize (opens new window)是 Spring Security 内置的前置权限注解,添加在接口方法上,声明需要的权限,实现访问权限的控制。
  • 当 @PreAuthorize 注解里的 Spring EL 表达式返回 false 时,表示没有权限。

ss是自动配置类中注入的一个名字为ss的bean,传入的是PermissionApi接口的一个实现类,返回的是SecurityFrameworkServiceImpl类型
在这里插入图片描述
传入的实现类定义在system模块下
在这里插入图片描述
返回的实体类在
在这里插入图片描述

这样当访问一个接口时,会进到SecurityFrameworkServiceImpl类的hasPermission方法。传入的就是controller中的system:dept:update
在这里插入图片描述
然后继续往下调用
在这里插入图片描述
PermissionApi就是PermissionApiImpl类型
在这里插入图片描述
然后会调用permissionService的hasAnyPermissions方法
在这里插入图片描述
然后进入判断逻辑
在这里插入图片描述

    @Override
    public boolean hasAnyPermissions(Long userId, String... permissions) {
        // 如果为空,说明已经有权限,也就是controller传入的权限就是空,也就是可以不加注解
        if (ArrayUtil.isEmpty(permissions)) {
            return true;
        }

        // 获得当前登录的角色(从缓存)。如果为空,说明没有权限,传入当前用户id和开启的status 0
        //流程就是获取到当前用户的所有角色id 然后判断这些角色是否为关闭状态
        Set<Long> roleIds = getUserRoleIdsFromCache(userId, singleton(CommonStatusEnum.ENABLE.getStatus()));
        if (CollUtil.isEmpty(roleIds)) {
            return false;
        }
        // 判断是否是超管。如果是,当然符合条件
        if (roleService.hasAnySuperAdmin(roleIds)) {
            return true;
        }

        // 遍历权限,判断是否有一个满足
        return Arrays.stream(permissions).anyMatch(permission -> {
        //根据permission获取菜单,获取不到说明没有权限
            List<MenuDO> menuList = menuService.getMenuListByPermissionFromCache(permission);
            // 采用严格模式,如果权限找不到对应的 Menu 的话,认为
            if (CollUtil.isEmpty(menuList)) {
                return false;
            }
            // 获得是否拥有该权限,任一一个
            //获取到菜单,去缓存中根据菜单id看是否能匹配当前角色
            //anyMatch用法 遍历menuList,
            //CollUtil.containsAny(roleIds, menuRoleCache.get(menu.getId()))有一个返回true的话,就返回true
            return menuList.stream().anyMatch(menu -> CollUtil.containsAny(roleIds,
                    menuRoleCache.get(menu.getId())));
        });
    }

这样这个判断就完成了。

2.基于角色的权限控制

    @Override
    public boolean hasAnyRoles(Long userId, String... roles) {
        // 如果为空,说明已经有权限
        if (ArrayUtil.isEmpty(roles)) {
            return true;
        }

        // 获得当前登录的角色。如果为空,说明没有权限
        Set<Long> roleIds = getUserRoleIdsFromCache(userId, singleton(CommonStatusEnum.ENABLE.getStatus()));
        if (CollUtil.isEmpty(roleIds)) {
            return false;
        }
        // 判断是否是超管。如果是,当然符合条件
        if (roleService.hasAnySuperAdmin(roleIds)) {
            return true;
        }
        Set<String> userRoles = convertSet(roleService.getRoleListFromCache(roleIds),
                RoleDO::getCode);
        return CollUtil.containsAny(userRoles, Sets.newHashSet(roles));
    }

3.登陆判断

@PreAuthenticated 注解

  • @PreAuthenticated (opens new window)是项目自定义的认证注解,添加在接口方法上,声明登录的用户才允许访问。
  • 主要使用场景是,针对用户 App 的 /app-app/** 的 RESTful API 接口,默认是无需登录的,通过 @PreAuthenticated 声明它需要进行登录。

针对这个注解的aop
在这里插入图片描述
如果加了这个注解而且没有登录,会抛出异常,然后会被GlobalExceptionHandler类的serviceExceptionHandler方法捕获。返回前端异常信息。

2.自定义权限配置

1.自定义 AuthorizeRequestsCustomizer 实现

例如yudao-module-infra 模块的 SecurityConfiguration ()类

@Configuration("infraSecurityConfiguration")
public class SecurityConfiguration {

    @Value("${spring.boot.admin.context-path:''}")
    private String adminSeverContextPath;

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

            @Override
            public void customize(ExpressionUrlAuthorizationConfigurer<HttpSecurity>.ExpressionInterceptUrlRegistry registry) {
                // Swagger 接口文档
                registry.antMatchers("/swagger-ui.html").anonymous()
                        .antMatchers("/swagger-resources/**").anonymous()
                        .antMatchers("/webjars/**").anonymous()
                        .antMatchers("/*/api-docs").anonymous();
                // 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();
            }

        };
    }

}

  • permitAll() 方法:所有用户可以任意访问,包括带上 Token 访问
  • anonymous() 方法:匿名用户可以任意访问,带上 Token 访问会报错

2.@PermitAll 注解

直接在接口方法加这个注解

3.配置文件配置

在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值