近期,工作需求也是涉及到 Shiro 权限的问题,而且目前项目是前后端分离的,所以要求做到实现前后端分离。作为一个攻城狮,自然不能推辞。
鉴于之前未接触过 SpringBoot 中 用 ShIro 做授权和认证,然后去各大网站上搜了一番,果然,还和以前一样,千篇一律,Copy的居多,而且即使 GitHub 上有 demo 的,下载之后也是跑步不起来,无计可施。
由于关于 SpringBoot 会涉及到很多版本的问题,所以建议各位,还是选择自己项目需要的版本,而且在未验证此 demo 和方法可行性的情况下,不要 Copy 或者转载到自己博客中,以免误人子弟。
好了,言归正传,今天就给大家简单说一下, SpringBoot 中怎么用 Shiro 做权限验证,并实现前后端分离,其实没有大家想象的那么难,主要是不要进坑里爬不出来。一旦进坑,要立马回头,不要驻留,要不然浪费的只是自己的时间。
先上下源码吧,要不然大家看着也比较枯燥,启动项目,结合源码看博客更易懂。
GitHub :https://github.com/313989006/shiroDemo
项目结构如下:
第一步、在IDEA中导入项目,在application.properties 文件中修改自己的 redis 地址。
第二步、打开 Navicat ,新建数据库,运行 sql.txt 文件,插入表和数据。(表中只造了一点数据,只是测试)
第三步、运行 ShiroDemoApplication 文件,启动项目
注意:如果遇到启动不成功的情况下,大概率是因为 redis 地址的问题,修改下 redis 地址即可。
第四步、发送登陆请求,查看程序运行(debug 状态下)。
当然,对于 SpringBoot 项目用的是 Rest 风格的开发方式,前端发送请求都是通过 ajax 请求,后端接收到请求之后,返回 Json 和状态码数据给前端。
JwtFilter 是自定义的过滤器,继承 BasicHttpAuthenticationFilter ,重写 onAccessDenied、 createToken、preHandle 方法。
a、onAccessDenied :验证是否过滤请求,验证 token 是否有效
b、createToken : 创建 token
c、preHandle :设置支持跨域 (SpringBoot 有很多跨域问题,所以最好还是重写preHandle 方法,支持跨域)
发送请求后会先进入 onAccessDenied 方法(过滤是否可以直接访问的 URL,这里userLogin 登陆请求肯定是可以直接访问的,anonymousStr 是在 application.properties 文件中配置的,此处配置为:登陆、登出、图片验证可以直接访问):
第五步、这里发送登陆请求,会直接到登陆的 API 接口。
这里是通过查询数据库,判断账号密码是否匹配,如果匹配,则写入 Redis ,返回 code 和 msg 给前端。
在请求成功之后,也会在 header 中添加 Authorization 字段,返回给前端,前端保存到本地,请求的时候带着请求头发起请求。
第六步、发起 test2 请求,这里就是我们要抓住的重点了。
请求时,在header 中带上 Authorization 和刚才登陆返回的 值。
同样也会先进入JWTFilter 进行过滤,如果是非登陆、登出、图片验证码请求,则会验证 token 是否有效。
当认证通过之后,会进入 MyRealm 的 doGetAuthenticationInfo 方法,进行认证。
认证通过之后,会到 doGetAuthorizationInfo 方法中,进行授权,这里就是授权的核心代码:
此处获取 该用户 权限 和 角色,加入到 SimpleAuthorizationInfo 实例化对象中。
这里可以看到,我们拿到的当前用户的角色和权限都是 admin ,并且保存在 SimpleAuthorizationInfo 的实例化对象中。
那接下来 F8 到底会不会进入请求的 URL(test2)中呢?答案肯定是:会的,因为 test2 需要的 permission 就是 admin,肯定会正常进入到 test2 的。我们来看下:
当然,这里如果改成 @RequiresRoles(“admin”)当然也是可以访问的,因为该用户的 roles 也包含了 admin 的角色。
而后端返回给我们的数据是:
也就说明如果该用户有 url 上允许的permissions或者roles的话就可以正常访问该 URL。
到这里,我们就验证结束了,相信看到的应该也知道流程是什么样子的,代码没那么复杂。
主要就是通过过滤器 JWTFilter 过滤请求,MyRealm 进行认证和授权,Controller 层通过 @RequiresPermissions 和 @RequiresRoles 注解来实现权限的验证。
现在对 Shiro 还有什么不懂的吗?如果还有不懂的话,可以一步步debug ,看底层源码怎么实现的,其实很多时候学习不只是学习到底怎么用的,还要去 Debug 调试去看看他怎么实现的,这样才能学到更多的技术栈。
这里也是我一步步 Debug 来进行验证和实现的,当然也遇到很多坑,但是要及时跳出来,才能找到更好的解决方法。希望和大家一起学习新的技术和知识,欢迎大家一起沟通交流,互相进步。
注:
1、这里 使用的是 SpringBoot 2.1.3版本。
2、shiro版本:Shiro 1.4.0 版本
3、开发环境:Java 1.8 版本
4、数据库驱动:com.mysql.cj.jdbc.Driver (com.mysql.jdbc.Driver 已经被遗弃)
我是进阶的球儿,大家一起2019年的爬坑历程。感觉分享很给力的话给个赞,谢谢!!!有问题也可以下方留言或者加本人QQ:313989006 进行沟通。