{"id":16619959,"url":"https://github.com/top-lh/rainbow-security-boot-starter","last_synced_at":"2026-04-28T03:02:36.990Z","repository":{"id":180567860,"uuid":"324132248","full_name":"TOP-LH/rainbow-security-boot-starter","owner":"TOP-LH","description":"一款基于redis的权限框架，springboot start可以轻松和springboot集成，简单好用。","archived":false,"fork":false,"pushed_at":"2021-01-14T02:12:35.000Z","size":39,"stargazers_count":2,"open_issues_count":0,"forks_count":1,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-01-17T22:09:18.394Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"Java","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/TOP-LH.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2020-12-24T10:42:17.000Z","updated_at":"2021-03-13T12:49:10.000Z","dependencies_parsed_at":null,"dependency_job_id":"b8f526f4-ad89-4ed7-8450-01398b6ebd84","html_url":"https://github.com/TOP-LH/rainbow-security-boot-starter","commit_stats":null,"previous_names":["top-lh/rainbow-security-boot-starter"],"tags_count":1,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/TOP-LH%2Frainbow-security-boot-starter","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/TOP-LH%2Frainbow-security-boot-starter/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/TOP-LH%2Frainbow-security-boot-starter/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/TOP-LH%2Frainbow-security-boot-starter/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/TOP-LH","download_url":"https://codeload.github.com/TOP-LH/rainbow-security-boot-starter/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":242988196,"owners_count":20217559,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-10-12T02:43:10.658Z","updated_at":"2025-12-26T03:17:00.924Z","avatar_url":"https://github.com/TOP-LH.png","language":"Java","funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003ccenter\u003e\n    \u003ch1\u003erainbow-security-boot-starter\u003c/h1\u003e\n    \u003ch2\u003e一款基于springboot+redis的权限框架\u003c/h2\u003e\n\u003c/center\u003e\n\n## 1.简介\n\n​\t\t对比`java`市场上的两大安全框架`shiro`和`spring security`，rainbow-security-boot-starter的设计初衷就是为了让权限框架使用的更为简单，快速应用。\n\n## 2. 如何使用\n\n\u003e 实现声明：rainbow-security-boot-starter不会去控制你登录的业务逻辑，你只需要判断用户信息一切准确无误的时候，调用RainbowSecurityUtils下的方法即可。\n\n\n\n### 2.1 配置拦截器\n\n```java\npackage org.rainbow.config;\n\nimport com.rainbow.security.interceptor.RainbowSecurityInterceptor;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.web.servlet.config.annotation.InterceptorRegistry;\nimport org.springframework.web.servlet.config.annotation.WebMvcConfigurer;\n\n/**\n * @author lihao3\n * @Date 2020/9/30 14:17\n */\n@Configuration\npublic class RainbowSecurityConfig implements WebMvcConfigurer {\n\n    /**\n     * 注册rainbow-security-boot-starter的拦截器，打开注解式鉴权功能\n     *\n     * @param registry\n     */\n    @Override\n    public void addInterceptors(InterceptorRegistry registry) {\n        // 全局拦截器\n        registry.addInterceptor(new RainbowSecurityInterceptor())\n            .addPathPatterns(\"/**\")\n            .excludePathPatterns(\"添加不需要登陆即可访问的接口URL\");\n    }\n}\n```\n\n### 2.2 配置yaml文件\n\n```yaml\nrainbow:\n  security:\n    is-read-body: false # 是否尝试从请求体里读取token\n    is-read-cookie: false # 是否尝试从cookie里读取token\n    timeout: 172800 # token有效期，单位s 默认1天\n    token-name: rainbowSecurity # token名称 (同时也是cookie名称)\n    is-read-head: false # 是否尝试从header里读取token\n    is-share: false # 在多人登录同一账号时，是否共享会话 (为true时共用一个，为false时新登录挤掉旧登录)\n```\n\n\n\n### 2.3 执行登陆方法\n\n\u003e 如果 is-share为true的时候，如果A已经登陆了账号a并拿到了tokenA，这时候如果B也登陆了账号a，那么他也将返回tokenA\n\u003e\n\u003e 如果 is-share为false的时候，如果A已经登陆了账号a并拿到了tokenA，这时候如果B也登陆了账号a，那么tokenA作废，B则返回\n\n```java\n// loginId是用户唯一标识，token为登陆之后返回的令牌\nString token = RainbowSecurityUtils.login(loginId);\n```\n\n\n\n### 2.4 将用户的一些个人信息放入到缓存中\n\n```java\n/**\n  * 根据loginID将对应的数据缓存起来\n  *\n  * @param loginID 用户唯一标识\n  * @param key     数据对应的key,如果为空则使用loginID作为key\n  * @param load    存储的数据\n  */\nRainbowSecurityUtils.setDataByLoginID(String loginID, String key, Object load);\n```\n\n\n\n### 2.5 根据用户唯一标识获取缓存中对应的信息\n\n```java\n/**\n  * 根据loginID获取他对于的缓存\n  *\n  * @param loginID 用户唯一标识\n  * @param key     数据对应的key,如果为空则使用loginID作为key\n  */\nObject sysUser = RainbowSecurityUtils.getDataByLoginID(String loginID, String key);\n```\n\n\n\n### 2.6 根据接口中的token获取对应loginID\n\n```java\nString loginID = RainbowSecurityUtils.getLoginID();\n```\n\n\n\n### 2.7 获取接口中的token\n\n\u003e 根据yml配置的获取token的方法来获取\n\u003e\n\u003e 优先级：header \u003e cookie \u003e body\n\n```java\nString token = RainbowSecurityUtils.getRequestToken();\n```\n\n\n\n### 2.8 通过loginID获取对应的token\n\n```java\nString token = RainbowSecurityUtils.byLoginIDGetToken(String loginID);\n```\n\n\n\n### 2.9 通过token获取对应的loginID\n\n\u003e 如果token过期或者token异常则返回null\n\n```java\nString token = RainbowSecurityUtils.byTokenGetLoginID(String token);\n```\n\n\n\n### 2.10 退出登录\n\n\u003e 根据getRequestToken()方法获取接口中的token，让token作废\n\n```java\nRainbowSecurityUtils.logout();\n```\n\n\n\n### 2.11 判断当回话是否登录\n\n\u003e true代表已登录，反之\n\n```java\nBoolean isLogin = RainbowSecurityUtils.isLogin();\n```\n\n\n\n### 2.12 强T下线\n\n\u003e 根据loginID将用户强T下线\n\n```java\nRainbowSecurityUtils.forceLogout(String loginID)\n```\n\n\n\n## 3. 控制接口的权限标识和角色\n\n### 3.1 实现根据loginID获取对应权限标识和角色的接口\n\n```java\nimport com.rainbow.security.service.RainbowSecurityService;\nimport org.springframework.stereotype.Service;\n\nimport java.util.ArrayList;\nimport java.util.List;\n\n/**\n * @author lihao3\n * @Date 2020/12/24 16:49\n */\n@Service\npublic class RainbowSecurityServiceImpl implements RainbowSecurityService {\n\n    @Autowired\n    private SysMenuMapper sysMenuMapper;\n    \n    @Override\n    public List\u003cString\u003e getPermissionCodeList(String s) {\n        List\u003cString\u003e permissionCodeList = new ArrayList\u003c\u003e();\n        permissionCodeList.add(\"admin:list\");\n        permissionCodeList.add(\"role:list\");\n        permissionCodeList.add(\"menu:list\");\n        permissionCodeList.add(\"dept:list\");\n        permissionCodeList.add(\"log:list\");\n        return permissionCodeList;\n    }\n\n    @Override\n    public List\u003cString\u003e getRoleCodeList(String s) {\n        List\u003cString\u003e roleCodeList = new ArrayList\u003c\u003e();\n        roleCodeList.add(\"admin\");\n        return roleCodeList;\n    }\n}\n\n```\n\n\n\n### 3.2 在需要控制的方法上添加注解\n\n1. 需要拥有权限标识`system:list`才能访问的接口\n\n   ```java\n       @RainbowCheckPerms(\"system:list\")\n       @GetMapping(\"/test\")\n       public Result test() {\n           return Result.success();\n       }\n   ```\n\n\n\n\n2. 需要拥有角色`admin`才能访问的接口\n\n   ```java\n       @RainbowCheckRoles(\"admin\")\n       @GetMapping(\"/test\")\n       public Result test() {\n           return Result.success();\n       }\n   ```\n\n   \n\n\n\n## 4. 常见BUG\n\n### 4.1 redis存入的数据被序列化了，无法查看\n\n\u003e 这是使用了阿里的fastjson进行反序列化，市场上还有很多种实现方法，这里就不一一列举了\n\n1. pom 坐标\n\n   ```xml\n           \u003c!-- 阿里JSON解析器 --\u003e\n           \u003cdependency\u003e\n               \u003cgroupId\u003ecom.alibaba\u003c/groupId\u003e\n               \u003cartifactId\u003efastjson\u003c/artifactId\u003e\n               \u003cversion\u003e${fastjson.version}\u003c/version\u003e\n           \u003c/dependency\u003e\n   ```\n\n   \n\n2. 实现RedisSerializer接口\n\n   ```java\n   import com.alibaba.fastjson.JSON;\n   import com.alibaba.fastjson.parser.ParserConfig;\n   import com.alibaba.fastjson.serializer.SerializerFeature;\n   import com.fasterxml.jackson.databind.JavaType;\n   import com.fasterxml.jackson.databind.ObjectMapper;\n   import com.fasterxml.jackson.databind.type.TypeFactory;\n   import org.springframework.data.redis.serializer.RedisSerializer;\n   import org.springframework.data.redis.serializer.SerializationException;\n   import org.springframework.util.Assert;\n   \n   import java.nio.charset.Charset;\n   \n   /**\n    * Redis使用FastJson序列化\n    *\n    * @author lihao3\n    */\n   public class FastJson2JsonRedisSerializer\u003cT\u003e implements RedisSerializer\u003cT\u003e {\n   \n       @SuppressWarnings(\"unused\")\n       private ObjectMapper objectMapper = new ObjectMapper();\n   \n       public static final Charset DEFAULT_CHARSET = Charset.forName(\"UTF-8\");\n   \n       private Class\u003cT\u003e clazz;\n   \n       static {\n           ParserConfig.getGlobalInstance().setAutoTypeSupport(true);\n       }\n   \n       public FastJson2JsonRedisSerializer(Class\u003cT\u003e clazz) {\n           super();\n           this.clazz = clazz;\n       }\n   \n       @Override\n       public byte[] serialize(T t) throws SerializationException {\n           if (t == null) {\n               return new byte[0];\n           }\n           return JSON.toJSONString(t, SerializerFeature.WriteClassName).getBytes(DEFAULT_CHARSET);\n       }\n   \n       @Override\n       public T deserialize(byte[] bytes) throws SerializationException {\n           if (bytes == null || bytes.length \u003c= 0) {\n               return null;\n           }\n           String str = new String(bytes, DEFAULT_CHARSET);\n   \n           return JSON.parseObject(str, clazz);\n       }\n   \n       public void setObjectMapper(ObjectMapper objectMapper) {\n           Assert.notNull(objectMapper, \"'objectMapper' must not be null\");\n           this.objectMapper = objectMapper;\n       }\n   \n       protected JavaType getJavaType(Class\u003c?\u003e clazz) {\n           return TypeFactory.defaultInstance().constructType(clazz);\n       }\n   }\n   \n   ```\n\n   \n\n3. 设置RedisTemplate的序列化方式\n\n   ```java\n   import com.fasterxml.jackson.annotation.JsonAutoDetect;\n   import com.fasterxml.jackson.annotation.PropertyAccessor;\n   import com.fasterxml.jackson.databind.ObjectMapper;\n   import com.rainbow.security.config.FastJson2JsonRedisSerializer;\n   import org.springframework.cache.annotation.CachingConfigurerSupport;\n   import org.springframework.cache.annotation.EnableCaching;\n   import org.springframework.context.annotation.Bean;\n   import org.springframework.context.annotation.Configuration;\n   import org.springframework.data.redis.connection.RedisConnectionFactory;\n   import org.springframework.data.redis.core.RedisTemplate;\n   import org.springframework.data.redis.serializer.StringRedisSerializer;\n   \n   /**\n    * redis配置\n    *\n    * @author lihao3\n    */\n   @Configuration\n   @EnableCaching\n   public class RedisConfig extends CachingConfigurerSupport {\n   \n       @Bean\n       @SuppressWarnings(value = {\"unchecked\", \"rawtypes\"})\n       public RedisTemplate\u003cObject, Object\u003e redisTemplate(RedisConnectionFactory connectionFactory) {\n           RedisTemplate\u003cObject, Object\u003e template = new RedisTemplate\u003c\u003e();\n           template.setConnectionFactory(connectionFactory);\n   \n           com.rainbow.security.config.FastJson2JsonRedisSerializer serializer = new FastJson2JsonRedisSerializer(Object.class);\n   \n           ObjectMapper mapper = new ObjectMapper();\n           mapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);\n           mapper.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);\n           serializer.setObjectMapper(mapper);\n   \n           template.setValueSerializer(serializer);\n           // 使用StringRedisSerializer来序列化和反序列化redis的key值\n           template.setKeySerializer(new StringRedisSerializer());\n           template.afterPropertiesSet();\n           return template;\n       }\n   \n   }\n   ```\n\n   \n\n## 5. 框架内的异常\n\n1. `AdminMandatoryLogout`是指被此loginID已被强T下线\n2. `MandatoryLogout`是指被挤下线的异常（此异常只有当is-share: false才会触发）\n3. `NoPermsException`访问该接口的loginID没有访问该接口的权限时触发的异常\n4. `NoTokenException`没有携带token访问需要登录才能访问的接口时触发的异常\n5. `TokenTimeOutException`此token已经超时的异常\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftop-lh%2Frainbow-security-boot-starter","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ftop-lh%2Frainbow-security-boot-starter","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftop-lh%2Frainbow-security-boot-starter/lists"}