{"id":13676485,"url":"https://github.com/dolyw/ShiroJwt","last_synced_at":"2025-04-29T07:32:23.292Z","repository":{"id":37735662,"uuid":"146854113","full_name":"dolyw/ShiroJwt","owner":"dolyw","description":"API SpringBoot + Shiro + Java-Jwt + Redis(Jedis)","archived":false,"fork":false,"pushed_at":"2022-06-21T00:47:32.000Z","size":199,"stargazers_count":679,"open_issues_count":7,"forks_count":277,"subscribers_count":26,"default_branch":"master","last_synced_at":"2024-11-11T18:42:10.203Z","etag":null,"topics":["element-ui","jwt","mysql","redis","redis-refreshtoken","shiro","spring-boot","vue"],"latest_commit_sha":null,"homepage":"https://gitee.com/dolyw/ShiroJwt","language":"Java","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/dolyw.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}},"created_at":"2018-08-31T06:57:56.000Z","updated_at":"2024-10-31T13:39:50.000Z","dependencies_parsed_at":"2022-07-12T15:18:27.565Z","dependency_job_id":null,"html_url":"https://github.com/dolyw/ShiroJwt","commit_stats":null,"previous_names":[],"tags_count":10,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dolyw%2FShiroJwt","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dolyw%2FShiroJwt/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dolyw%2FShiroJwt/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dolyw%2FShiroJwt/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/dolyw","download_url":"https://codeload.github.com/dolyw/ShiroJwt/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":251455975,"owners_count":21592269,"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":["element-ui","jwt","mysql","redis","redis-refreshtoken","shiro","spring-boot","vue"],"created_at":"2024-08-02T13:00:28.269Z","updated_at":"2025-04-29T07:32:22.859Z","avatar_url":"https://github.com/dolyw.png","language":"Java","readme":"## ShiroJwt\n\n[![License](https://img.shields.io/badge/license-MIT-blue.svg)](LICENSE)\n[![PRs Welcome](https://img.shields.io/badge/PRs-welcome-brightgreen.svg)](https://github.com/wang926454/ShiroJwt/pulls)\n[![GitHub stars](https://img.shields.io/github/stars/wang926454/ShiroJwt.svg?style=social\u0026label=Stars)](https://github.com/wang926454/ShiroJwt)\n[![GitHub forks](https://img.shields.io/github/forks/wang926454/ShiroJwt.svg?style=social\u0026label=Fork)](https://github.com/wang926454/ShiroJwt)\n\n\u003e 前端地址:[https://github.com/wang926454/VueStudy/tree/master/VueStudy08-JWT](https://github.com/wang926454/VueStudy/tree/master/VueStudy08-JWT)\n\n#### 疑问查看\n\n1. [#14 重复请求会不会生成多个token](https://github.com/dolyw/ShiroJwt/issues/14)\n2. [#19 跨域sso问题](https://github.com/dolyw/ShiroJwt/issues/19)\n3. [#29 Token刷新并发处理](https://github.com/dolyw/ShiroJwt/issues/29)\n\n\u003cimg src=\"https://cdn.jsdelivr.net/gh/wliduo/CDN@master/feed/qq.png\" height=\"180\"\u003e\u003c/img\u003e\n\n有疑问请扫码加**QQ**群交流: **779168604**\n\n#### 项目相关\n\n* JavaDoc:[https://apidoc.gitee.com/dolyw/ShiroJwt](https://apidoc.gitee.com/dolyw/ShiroJwt)\n* 接口文档:[https://note.dolyw.com/shirojwt/ShiroJwt-Interface.html](https://note.dolyw.com/shirojwt/ShiroJwt-Interface.html)\n* 教程目录:[https://note.dolyw.com/shirojwt](https://note.dolyw.com/shirojwt)\n* 改为数据库形式(MySQL):[https://note.dolyw.com/shirojwt/ShiroJwt02-MySQL.html](https://note.dolyw.com/shirojwt/ShiroJwt02-MySQL.html)\n* 解决无法直接返回401错误:[https://note.dolyw.com/shirojwt/ShiroJwt03-401.html](https://note.dolyw.com/shirojwt/ShiroJwt03-401.html)\n* 实现Shiro的Cache(Redis)功能:[https://note.dolyw.com/shirojwt/ShiroJwt04-Redis.html](https://note.dolyw.com/shirojwt/ShiroJwt04-Redis.html)\n\n#### 项目介绍\n\n1. RESTful API\n2. Maven集成Mybatis Generator(逆向工程)\n3. Shiro + Java-JWT实现无状态鉴权机制(Token)\n4. 密码加密(采用AES-128 + Base64的方式)\n5. 集成Redis(Jedis)\n6. 重写Shiro缓存机制(Redis)\n7. Redis中保存RefreshToken信息(做到JWT的可控性)\n8. 根据RefreshToken自动刷新AccessToken\n\n##### 关于Shiro + Java-JWT实现无状态鉴权机制(Token)\n\n\u003e 1. 首先**Post**用户名与密码到**user/login**登入，成功返回加密的**AccessToken**，失败直接返回401错误(帐号或密码不正确)\n\u003e 2. 以后访问都带上这个**AccessToken**即可\n\u003e 3. 鉴权流程主要是重写了**Shiro**的入口过滤器**JWTFilter**(**BasicHttpAuthenticationFilter**)，判断请求**Header**里面是否包含**Authorization**字段\n\u003e 4. 有就进行**Shiro**的**Token**登录认证授权(用户访问每一个需要权限的请求必须在**Header**中添加**Authorization**字段存放**AccessToken**)，没有就以游客直接访问(有权限管控的话，以游客访问就会被拦截)\n\n##### 关于AES-128 + Base64当两个用户的明文密码相同时进行加密，会发现数据库中存在相同结构的暗文密码\n\n\u003e 大部分是以**MD5 + 盐**的形式解决了这个问题(详细自己百度)，我采用**AES-128 + Base64**是以帐号+密码的形式进行加密密码，因为帐号具有唯一性，所以也不会出现相同结构的暗文密码这个问题\n\n##### 关于将Jedis工具类与SpringBoot整合\n\n\u003e 本来是直接将**JedisUtil**注入为**Bean**，每次使用直接`@Autowired`注入使用即可，但是在重写**Shiro**的**CustomCache**无法注入**JedisUtil**，所以就改成静态注入**JedisPool连接池**，**JedisUtil工具类**还是直接调用静态方法，无需`@Autowired`注入\n\n##### 关于Redis中保存RefreshToken信息(做到JWT的可控性)\n\n\u003e 1. 登录认证通过后返回**AccessToken**信息(在**AccessToken**中**保存当前的时间戳和帐号**)\n\u003e 2. 同时在**Redis**中设置一条以**帐号为Key，Value为当前时间戳(登录时间)**的**RefreshToken**\n\u003e 3. 现在认证时必须**AccessToken**没失效以及**Redis**存在所对应的**RefreshToken**，且**RefreshToken时间戳**和**AccessToken信息中时间戳一致**才算认证通过，这样可以做到**JWT的可控性**\n\u003e 4. 如果重新登录获取了新的**AccessToken**，旧的**AccessToken**就认证不了，因为**Redis**中所存放的的**RefreshToken时间戳信息**只会和最新生成的**AccessToken信息中携带的时间戳一致**，这样每个用户就只能使用最新的**AccessToken**认证\n\u003e 5. **Redis**的**RefreshToken**也可以用来判断用户是否在线，如果删除**Redis**的某个**RefreshToken**，那这个**RefreshToken**所对应的**AccessToken**之后也无法通过认证了，就相当于控制了用户的登录，可以剔除用户\n\n##### 关于根据RefreshToken自动刷新AccessToken\n\n\u003e 1. 本身**AccessToken的过期时间为5分钟**(配置文件可配置)，**RefreshToken过期时间为30分钟**(配置文件可配置)\n\u003e 2. 当登录后时间过了5分钟之后，当前**AccessToken**便会过期失效，再次带上**AccessToken**访问**JWT**会抛出**TokenExpiredException**异常说明**Token**过期\n\u003e 3. 开始判断是否要**进行AccessToken刷新**，**Redis查询当前用户的RefreshToken是否存在**，**以及这个RefreshToken所携带时间戳**和**过期AccessToken所携带的时间戳**是否**一致**\n\u003e 4. **如果存在且一致就进行AccessToken刷新，设置过期时间为5分钟(配置文件可配置)，时间戳为当前最新时间戳，同时也设置RefreshToken中的时间戳为当前最新时间戳，刷新过期时间重新为30分钟过期(配置文件可配置)**\n\u003e 5. 最终将刷新的**AccessToken**存放在**Response的Header中的Authorization字段**返回(前端进行获取替换，下次用新的**AccessToken**进行访问)\n\n#### 软件架构\n\n1. SpringBoot + Mybatis核心框架\n2. PageHelper插件 + 通用Mapper插件\n3. Shiro + Java-JWT无状态鉴权认证机制\n4. Redis(Jedis)缓存框架\n\n#### 安装教程\n\n1. 数据库帐号密码默认为root，如有修改，请自行修改配置文件application.yml\n2. 解压后执行src\\main\\resources\\sql\\MySQL.sql脚本创建数据库和表\n3. Redis需要自行安装Redis服务，端口密码默认\n4. SpringBoot直接启动即可，测试工具PostMan\n\n#### 使用说明\n\n##### Mybatis Generator使用(可视化自定义模板快速生成基础代码:[https://github.com/wang926454/ViewGenerator](https://github.com/wang926454/ViewGenerator))\n\n先配置src\\main\\resources\\generator\\generatorConfig.xml文件(默认配置都在原来包的下一级reverse包下)，在pom.xml这一级目录(即项目根目录下)的命令行窗口执行(前提是配置了mvn)(IDEA可以直接在Maven窗口Plugins中双击执行)\n```shell\nmvn mybatis-generator:generate\n```\n\n##### PostMan使用(Token获取及使用)\n\n```java\n先设置Content-Type为application/json\n```\n![image text](https://docs.dolyw.com/Project/ShiroJwt/image/20181006001.PNG)\n```text\n然后填写请求参数帐号密码信息\n```\n![image text](https://docs.dolyw.com/Project/ShiroJwt/image/20181006002.PNG)\n```text\n进行请求访问，请求访问成功\n```\n![image text](https://docs.dolyw.com/Project/ShiroJwt/image/20181006003.PNG)\n```java\n点击查看Header信息的Authorization属性即是Token字段\n```\n![image text](https://docs.dolyw.com/Project/ShiroJwt/image/20181006004.PNG)\n```java\n访问需要权限的请求将Token字段放在Header信息的Authorization属性访问即可\n```\n![image text](https://docs.dolyw.com/Project/ShiroJwt/image/20181006005.PNG)\n```java\nToken的自动刷新也是在Token失效时返回新的Token在Header信息的Authorization属性\n```\n\n#### 搭建参考\n\n1. 感谢SmithCruise的Shiro+JWT+Spring Boot Restful简易教程:[https://www.jianshu.com/p/f37f8c295057](https://www.jianshu.com/p/f37f8c295057)\n2. 感谢王洪玉的[Shiro入门]（一）使用Redis作为缓存管理器:[https://blog.csdn.net/why15732625998/article/details/78729254](https://blog.csdn.net/why15732625998/article/details/78729254)\n3. 感谢袋🐴饲养员的springboot(七).springboot整合jedis实现redis缓存:[http://www.cnblogs.com/GodHeng/p/9301330.html](http://www.cnblogs.com/GodHeng/p/9301330.html)\n4. 感谢W_Z_W_888的spring注入静态变量的三种方法及其注意事项:[https://blog.csdn.net/W_Z_W_888/article/details/79979103](https://blog.csdn.net/W_Z_W_888/article/details/79979103)\n5. 感谢天降风云的Vue2.0+ElementUI+PageHelper实现的表格分页:[https://blog.csdn.net/u012907049/article/details/70237457](https://blog.csdn.net/u012907049/article/details/70237457)\n6. 感谢yaxx的Vuejs之axios获取Http响应头:[https://segmentfault.com/a/1190000009125333](https://segmentfault.com/a/1190000009125333)\n7. 感谢Twilight的解决使用jwt刷新token带来的问题:[https://segmentfault.com/a/1190000013151506](https://segmentfault.com/a/1190000013151506)\n8. 感谢chuhx的shiro拦截器，返回json数据:[https://blog.csdn.net/chuhx/article/details/51148877](https://blog.csdn.net/chuhx/article/details/51148877)\n9. 感谢yidao620c的Shiro自带拦截器配置规则:[https://github.com/yidao620c/SpringBootBucket/tree/master/springboot-jwt](https://github.com/yidao620c/SpringBootBucket/tree/master/springboot-jwt)\n\n#### 参与贡献\n\n1. Fork 本项目\n2. 新建 Feat_xxx 分支\n3. 提交代码\n4. 新建 Pull Request\n","funding_links":[],"categories":["Java"],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdolyw%2FShiroJwt","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fdolyw%2FShiroJwt","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdolyw%2FShiroJwt/lists"}