门户网站建设探究,网页传奇服务端,建设部网站规范查询,百度地图排名怎么优化mall4cloud-rbac角色权限访问控制模块 系统架构与模块介绍系统架构rbac模型介绍 相关代码权限校验接口代码 补充 代码地址 github地址 fork自github原始项目 gitee地址 fork自gitee原始项目
系统架构与模块介绍
系统架构 从图中可以看到#xff0c;微服务集群中#xff0c;… mall4cloud-rbac角色权限访问控制模块 系统架构与模块介绍系统架构rbac模型介绍 相关代码权限校验接口代码 补充 代码地址 github地址 fork自github原始项目 gitee地址 fork自gitee原始项目
系统架构与模块介绍
系统架构 从图中可以看到微服务集群中rbac模块是作为一个支持模块与认证授权账户服务模块关联在一起的但是代码中将其分离了出来作为单独的服务。中间的服务调用通过fegin来执行。对于权限管理系统来说灵活而有组织的权限服务是必不可少的。
rbac模型介绍
RBACRole-Based Access Control是一种访问控制模型用于管理和控制系统或应用程序中的用户对资源的访问权限。RBAC基于角色的概念将用户分配给不同的角色而每个角色具有特定的权限决定了用户可以执行的操作以及可以访问的资源。RBAC的主要组成部分包括 User用户每个用户都有唯一的UID识别并被授予不同的角色 Role角色不同角色具有不同的权限 Permission权限访问权限 用户-角色映射用户和角色之间的映射关系 角色-权限映射角色和权限之间的映射 可以通过以下关系反应
多用户对多角色关系 多个用户可以被分配到一个或多个角色。这使得在一个组织中不同用户可以担任不同的职务或角色每个角色有不同的权限。多角色对多权限关系 多个角色可以包含一个或多个权限。这意味着不同的角色可以具有不同的权限而同一权限可以分配给多个不同的角色。 上面的关系如果反应到数据库表设计中至少需要五张表来设计 用户表User Table用于存储系统中的用户信息每个用户有唯一的标识符用户ID。 角色表Role Table用于存储不同角色的信息每个角色也有唯一的标识符角色ID。 权限表Permission Table用于存储系统中各种权限的信息每个权限也有唯一的标识符权限ID。 用户-角色关联表User-Role Relationship Table用于建立用户与角色之间的多对多关系以确定哪些用户属于哪些角色。 角色-权限关联表Role-Permission Relationship Table用于建立角色与权限之间的多对多关系以确定哪些角色有权执行哪些操作。 如果想在RBAC模型中增加一个菜单表以管理系统菜单和其与角色的关联可以将菜单表和角色-菜单关联表添加到数据库模型中 在系统的数据表中分别对应了user(用户表)role(角色表)menu菜单表、menu_permission(菜单权限表这里将菜单和权限结合)、user_role(用户角色关联表)、role_menu(角色菜单表)
相关代码
在模块中主要是对于权限的校验是关联到了auth模块的过滤器中的代码其他是提供到前端的接口代码
权限校验
auth模块下过滤器中代码如下 ①参数传入了用户信息、uri、请求方式 ②③进行校验主要是对普通用户端进行校验其他没做校验这里相当于只给了一个例子有需要还是得自己补充。接下来就是调用rbac模块的远程接口。 ①查询用户拥有的权限标识集合这里是三张表的关联查询。 ②根据用户类型获取权限对象 ③④判断逻辑为如果请求的urimethod属于当前用户类型下的权限对象判断这个用户下面的权限id集合是否包含该权限对象的id。包含则校验完成。 这里会有一个疑问对每次的请求都去与数据库交互会对性能造成影响。如果为了避免这个影响可以通过使用缓存来存储已验证的权限结果可以减少频繁校验的性能开销 代码中有这一步的处理
通过使用Cacheable进行了方法级别的缓存同时还有使用CacheEvict清理缓存在每次登录后 Cacheable 是 Spring 框架提供的一个注解用于启用方法级别的缓存。它可以用于将方法的计算结果缓存起来以便在下一次调用相同方法时可以直接返回缓存的结果而不必重新计算 在使用时需要配置缓存管理器。Spring 支持多个缓存管理器例如 EhCache、Caffeine、Redis 等 缓存管理器的代码位置如下 具体代码如下
package com.mall4j.cloud.common.cache.config;import com.fasterxml.jackson.annotation.JsonTypeInfo;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.databind.jsontype.impl.LaissezFaireSubTypeValidator;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
import com.mall4j.cloud.common.cache.adapter.CacheTtlAdapter;
import com.mall4j.cloud.common.cache.bo.CacheNameWithTtlBO;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.cache.CacheManager;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.cache.RedisCacheConfiguration;
import org.springframework.data.redis.cache.RedisCacheManager;
import org.springframework.data.redis.cache.RedisCacheWriter;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.RedisSerializationContext;
import org.springframework.data.redis.serializer.RedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;import java.time.Duration;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;/*** author FrozenWatermelon* date 2020/7/4*/
EnableCaching
Configuration
public class RedisCacheConfig {Beanpublic CacheManager cacheManager(RedisConnectionFactory redisConnectionFactory, CacheTtlAdapter cacheTtlAdapter) {// 创建 RedisCacheManager 实例RedisCacheManager redisCacheManager new RedisCacheManager(RedisCacheWriter.nonLockingRedisCacheWriter(redisConnectionFactory),// 默认策略未配置的 key 会使用这个this.getRedisCacheConfigurationWithTtl(3600),// 指定 key 策略this.getRedisCacheConfigurationMap(cacheTtlAdapter));redisCacheManager.setTransactionAware(true);return redisCacheManager;}// 获取缓存策略的映射private MapString, RedisCacheConfiguration getRedisCacheConfigurationMap(CacheTtlAdapter cacheTtlAdapter) {if (cacheTtlAdapter null) {return Collections.emptyMap();}MapString, RedisCacheConfiguration redisCacheConfigurationMap new HashMap(16);// 根据 CacheTtlAdapter 配置每个缓存的超时时间for (CacheNameWithTtlBO cacheNameWithTtlBO : cacheTtlAdapter.listCacheNameWithTtl()) {redisCacheConfigurationMap.put(cacheNameWithTtlBO.getCacheName(),getRedisCacheConfigurationWithTtl(cacheNameWithTtlBO.getTtl()));}return redisCacheConfigurationMap;}// 获取 Redis 缓存策略包括超时时间private RedisCacheConfiguration getRedisCacheConfigurationWithTtl(Integer seconds) {RedisCacheConfiguration redisCacheConfiguration RedisCacheConfiguration.defaultCacheConfig();redisCacheConfiguration redisCacheConfiguration.serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(redisSerializer())).entryTtl(Duration.ofSeconds(seconds));return redisCacheConfiguration;}/*** 自定义redis序列化的机制,重新定义一个ObjectMapper.防止和MVC的冲突* https://juejin.im/post/5e869d426fb9a03c6148c97e*/Beanpublic RedisSerializerObject redisSerializer() {ObjectMapper objectMapper new ObjectMapper();// 反序列化时候遇到不匹配的属性并不抛出异常objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);// 序列化时候遇到空对象不抛出异常objectMapper.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false);// 反序列化的时候如果是无效子类型,不抛出异常objectMapper.configure(DeserializationFeature.FAIL_ON_INVALID_SUBTYPE, false);// 不使用默认的dateTime进行序列化,objectMapper.configure(SerializationFeature.WRITE_DATE_KEYS_AS_TIMESTAMPS, false);// 使用JSR310提供的序列化类,里面包含了大量的JDK8时间序列化类objectMapper.registerModule(new JavaTimeModule());// 启用反序列化所需的类型信息,在属性中添加classobjectMapper.activateDefaultTyping(LaissezFaireSubTypeValidator.instance, ObjectMapper.DefaultTyping.NON_FINAL,JsonTypeInfo.As.PROPERTY);// 配置null值的序列化器GenericJackson2JsonRedisSerializer.registerNullValueSerializer(objectMapper, null);return new GenericJackson2JsonRedisSerializer(objectMapper);}Beanpublic RedisTemplateObject, Object redisTemplate(RedisConnectionFactory redisConnectionFactory,RedisSerializerObject redisSerializer) {RedisTemplateObject, Object template new RedisTemplate();template.setConnectionFactory(redisConnectionFactory);template.setDefaultSerializer(redisSerializer);template.setValueSerializer(redisSerializer);template.setHashValueSerializer(redisSerializer);template.setKeySerializer(StringRedisSerializer.UTF_8);template.setHashKeySerializer(StringRedisSerializer.UTF_8);template.afterPropertiesSet();return template;}Beanpublic StringRedisTemplate stringRedisTemplate(RedisConnectionFactory redisConnectionFactory) {return new StringRedisTemplate(redisConnectionFactory);}BeanConditionalOnMissingBeanpublic CacheTtlAdapter cacheTtl() {return Collections::emptyList;}}
创建一个配置类用于配置 Redis 缓存管理器。可以使用 Configuration 注解和 EnableCaching 注解来启用缓存并配置 RedisCacheManager。RedisCacheManager是自定义的缓存策略。 this.getRedisCacheConfigurationMap(cacheTtlAdapter) 用于指定特定键的缓存策略。这是一种根据键的不同而使用不同策略的方式可能根据不同的业务需求来自定义缓存超时时间等。cacheTtlAdapter 参数是一个用于生成特定键的策略的适配器。 Bean 方法 cacheManager 创建了一个 Redis 缓存管理器 RedisCacheManager 的实例。这个管理器用于管理缓存配置缓存的策略以及连接到 Redis 数据库。在这个方法中使用了以下关键配置 RedisCacheWriter.nonLockingRedisCacheWriter(redisConnectionFactory)创建了一个用于与 Redis 交互的 RedisCacheWriter这里使用了非阻塞方式的写入。这是默认的并且常用的写入方式 getRedisCacheConfigurationWithTtl(3600)设置了默认的缓存策略包括缓存超时时间为 3600 秒。 getRedisCacheConfigurationMap(cacheTtlAdapter)指定了特定键的缓存策略这些策略根据不同的键和超时时间动态配置通过 cacheTtlAdapter 获取。 setTransactionAware(true)设置缓存管理器为事务感知以确保在事务中的缓存操作能够回滚。 getRedisCacheConfigurationMap 方法根据 cacheTtlAdapter 动态生成缓存策略的映射。这个方法会检查 cacheTtlAdapter 是否为 null如果不是则获取一组特定缓存键和对应的超时时间并创建相应的缓存策略。如果 cacheTtlAdapter 为 null则返回一个空的映射。 getRedisCacheConfigurationWithTtl 方法用于配置 Redis 缓存策略包括序列化策略和缓存超时时间。 redisSerializer 方法创建了一个自定义的 Redis 数据序列化器其中包含了一些自定义的配置如序列化器失败时不抛出异常、处理空对象等。 redisTemplate 和 stringRedisTemplate 方法分别配置了 RedisTemplate 和 StringRedisTemplate用于操作 Redis 数据库。它们使用了自定义的序列化器和连接工厂。 最后的 cacheTtl 方法用于创建一个缓存超时时间适配器 CacheTtlAdapter默认情况下返回一个空列表。 接口代码
接口代码主要从controller看即可都是相关的一些数据表的业务需求这里不再过多赘述
补充
关于rbac的一些扩展 RBAC1 模型 在 RBAC的基础上引入了角色继承的概念。即子角色可以继承父角色的所有权限。 使用场景如某个业务部门有经理、主管、专员。主管的权限不能大于经理专员的权限不能大于主管如果采用 RBAC0 模型做权限系统极可能出现分配权限失误最终出现主管拥有经理都没有的权限的情况。 而 RBAC1 模型就很好解决了这个问题创建完经理角色并配置好权限后主管角色的权限继承经理角色的权限并且支持在经理权限上删减主管权限 关于权限管理系统 若依权限管理系统也是一个适合学习的项目代码地址https://gitee.com/y_project/RuoYi-Cloud RuoYi-Cloud