Shiro + JWT + Spring Boot Restful 简易教程
GitHub 项目地址:https://github.com/Smith-Cruise/Spring-Boot-Shiro 。
1. 序言
我也是半路出家的人,如果大家有什么好的意见或批评,请务必 issue 下。
如果想要直接体验,直接 clone 项目,运行 mvn spring-boot:run 命令即可进行访问。网址规则自行看教程后面。
如果想了解 Spring Security 可以看
Spring Boot 2.0+Srping Security+Thymeleaf的简易教程
Spring Boot 2 + Spring Security 5 + JWT 的单页应用Restful解决方案 (推荐)
2. 特性
完全使用了 Shiro 的注解配置,保持高度的灵活性。
放弃 Cookie ,Session ,使用JWT进行鉴权,完全实现无状态鉴权。
JWT 密钥支持过期时间。
对跨域提供支持。
3. 准备工作
在开始本教程之前,请保证已经熟悉以下几点。
Spring Boot 基本语法,至少要懂得
Controller、RestController、Autowired等这些基本注释。其实看看官方的 Getting-Start 教程就差不多了。Shiro 的基本操作,看下官方的 10 Minute Tutorial 即可。
模拟 HTTP 请求工具,我使用的是 PostMan。
简要的说明下我们为什么要用 JWT ,因为我们要实现完全的前后端分离,所以不可能使用 session, cookie 的方式进行鉴权,所以 JWT 就被派上了用场,你可以通过一个加密密钥来进行前后端的鉴权。
4. 程序逻辑
我们 POST 用户名与密码到
/login进行登入,如果成功返回一个加密 token,失败的话直接返回 401 错误。之后用户访问每一个需要权限的网址请求必须在
header中添加Authorization字段,例如Authorization: token,token为密钥。后台会进行
token的校验,如果有误会直接返回 401。
5. Token加密说明
携带了
username信息在 token 中。设定了过期时间。
使用用户登入密码对
token进行加密。
6. Token校验流程
获得
token中携带的username信息。进入数据库搜索这个用户,得到他的密码。
使用用户的密码来检验
token是否正确。
7. 准备Maven文件
新建一个 Maven 工程,添加相关的 dependencies。
注意指定JDK版本和编码。
8. 构建简易的数据源
为了缩减教程的代码,我使用 HashMap 本地模拟了一个数据库,结构如下:
smith
smith123
user
view
danny
danny123
admin
view,edit
这是一个最简单的用户权限表,如果想更加进一步了解,自行百度 RBAC。
之后再构建一个 UserService 来模拟数据库查询,并且把结果放到 UserBean 之中。
UserService.java
UserBean.java
9. 配置 JWT
我们写一个简单的 JWT 加密,校验工具,并且使用用户自己的密码充当加密密钥,这样保证了 token 即使被他人截获也无法破解。并且我们在 token 中附带了 username 信息,并且设置密钥5分钟就会过期。
10. 构建URL
ResponseBean.java
既然想要实现 restful,那我们要保证每次返回的格式都是相同的,因此我建立了一个 ResponseBean 来统一返回的格式。
自定义异常
为了实现我自己能够手动抛出异常,我自己写了一个 UnauthorizedException.java
URL结构
/login
登入
/article
所有人都可以访问,但是用户与游客看到的内容不同
/require_auth
登入的用户才可以进行访问
/require_role
admin的角色用户才可以登入
/require_permission
拥有view和edit权限的用户才可以访问
Controller
处理框架异常
之前说过 restful 要统一返回的格式,所以我们也要全局处理 Spring Boot 的抛出异常。利用 @RestControllerAdvice 能很好的实现。
11. 配置 Shiro
大家可以先看下官方的 Spring-Shiro 整合教程,有个初步的了解。不过既然我们用了 Spring-Boot,那我们肯定要争取零配置文件。
实现JWTToken
JWTToken 差不多就是 Shiro 用户名密码的载体。因为我们是前后端分离,服务器无需保存用户状态,所以不需要 RememberMe 这类功能,我们简单的实现下 AuthenticationToken 接口即可。因为 token 自己已经包含了用户名等信息,所以这里我就弄了一个字段。如果你喜欢钻研,可以看看官方的 UsernamePasswordToken 是如何实现的。
实现Realm
realm 的用于处理用户是否合法的这一块,需要我们自己实现。
在 doGetAuthenticationInfo() 中用户可以自定义抛出很多异常,详情见文档。
重写 Filter
所有的请求都会先经过 Filter,所以我们继承官方的 BasicHttpAuthenticationFilter ,并且重写鉴权的方法。
代码的执行流程 preHandle -> isAccessAllowed -> isLoginAttempt -> executeLogin 。
getSubject(request, response).login(token); 这一步就是提交给了 realm 进行处理。
配置Shiro
里面 URL 规则自己参考文档即可 http://shiro.apache.org/web.html 。
12. 总结
我就说下代码还有哪些可以进步的地方吧
没有实现 Shiro 的
Cache功能。Shiro 中鉴权失败时不能够直接返回 401 信息,而是通过跳转到
/401地址实现。
最后更新于
这有帮助吗?