Spring Security 系列教程 08-- 基于默认数据库模型实现授权
前言
在上一个章节中,一一哥 给大家讲解了如何基于内存模型来实现授权,在这种模型里,用户的信息是保存在内存中的。你知道,保存在内存中的信息,是无法持久化的,也就是程序一旦关闭,或者断电等情况发生,内存中的信息就丢失了,所以这种方式并不适用于生产环境!
那么我们肯定要把用户信息持久化, 但是持久化到哪里去呢?那就是数据库呗!数据库是我们做程序员必会必熟的知识点,尤其是做后端开发,开发时常用的数据库有 MySQL 和 Oracle,本案例中我们采用的是 MySQL 数据库。
一. JdbcUserDetailsManager 类介绍
在进行编码实现之前,壹哥 先和各位一起来看看 Spring Security 给我们提供的持久化 API 都有哪些,以及这些 API 之间的关系结构。
1. UserDetailsService 接口
Spring Security 支持 MySQL、Oracle 等多种不同的数据源,这些不同的数据源最终都由 UserDetailsService 这个接口的子类来负责进行操作,我们先来看看 UserDetailsService 接口都有哪些实现类:
2. JdbcUserDetailsManager 实现类
在上一章节中,我给大家介绍了如何在内存中创建并保存用户及角色信息,这种实现方式主要是利用 InMemoryUserDetailsManager 这个子类来实现的。如果我们想在数据库中创建并保存用户及角色信息,Spring Security 也很贴心,它还给我们提供了另一个 UserDetailsService 的实现子类,也就是 JdbcUserDetailsManager。其中 JdbcUserDetailsManager 类的关系结构如下图所示:
从上图中,我们可以看到 JdbcUserDetailsManager 的直接父类是 JDBCDaoSuport,利用 JdbcUserDetailsManager 可以帮助我们以 JDBC 的方式对接数据库进行增删改查等操作。它内部设定了一个默认的数据库模型,只要遵从这个模型,我们就可以很方便的实现在数据库中创建用户名和密码、角色等信息,但是灵活性不足。
二. 项目实现
了解完上面的相关 API 之后,咱们闲言少叙,直接动起手来撸码吧。
1. 准备测试接口
接下来我们就在上一章节创建的项目基础之上,创建一个新的 model,并对项目进行改造。我们还是跟之前一样,先创建 3 个测试接口,具体过程请参考之前章节。
2. 准备数据库
既然我们要操作数据库,那肯定得先建库建表啊,那么数据库和表结构是什么样呢?我们怎么创建出来呢?其实 JdbcUserDetailsManager 本身就给我们提供了对应的数据库脚本模型,这个数据库脚本模型保存在如下位置:
所以我们直接去这个对应的位置下,找到这个数据库脚本文件打开即可。
3. users 数据库脚本
当我们打开这个 users.ddl 文件,可以看到如下内容,会发现其中有 2 个建表语句,分别是创建了 users 表和 authorities 表,并且在 authorities 表中创建了唯一索引。
这时候我们只需要先自己创建一个数据库,编码格式就采用 UTF-8,然后把上面的建表语句,复制粘贴并执行,创建出 2 个表即可。users 表用来存放用户名、用户密码以及账户是否可用,authorities 表用来存放用户名及其对应权限,authorities 和 users 会通过 username 字段关联起来。
如下图所示:
注意:
上面的建表脚本中,有一种数据类型 varchar_ignorecase,这个是针对 HSQLDB 数据库创建的,但是我们使用的 MySQL 数据库并不支持这种数据类型,所以这里需要我们手动将这个数据类型改为 varchar。
4. 添加数据库依赖
接下来我们在 pom.xml 文件中,除了已有的 spring-web 和 spring-security 的依赖之外,还要再新增关于数据库的依赖包。
5. 添加数据库配置文件
添加完依赖包之后,我们在 resource 目录下创建一个 application.yml 文件,并在其中添加关于数据库的配置信息。
注意:url 中数据库的名字,需要改成自己的数据库名称,用户名和密码也要改成自己 mysql 的用户信息。
6. 编写编码类
然后我们编写一个 SecurityConfig 类,在其中配置对资源的访问控制,创建一个 UserDetailsService 实例,并在其中配置,生成存储用户和角色信息。
因为我们利用的是 SpringBoot 环境,只要我们配置好了数据库依赖和环境,就可以直接在这个 SecurityConfig 配置类中引用 DataSource 对象。
7. 核心代码释义
对上面 SpringSecurity 类中的代码,我主要针对 createUserDetailService()方法进行解释。
在这个方法中,我们首先构建一个 JdbcUserDetailsManager 实例对象,并给 JdbcUserDetailsManager 实例添加一个 DataSource 对象。
接下来调用 userExists()方法 判断用户是否存在,如果不存在,就创建一个新的用户出来(因为每次项目启动时这段代码都会执行,所以加一个判断,避免重复创建用户)。
用户的创建方法和我们之前 InMemoryUserDetailsManager 中的创建用户的方法基本一致。
以上就是我们基于默认的数据库模型实现的对用户及角色的操作,之所以可以实现,就是因为在 UserDetailsManager 这个父接口中,定义了如下方法,这些方法在子类中都有具体的实现。
我们可以看到 UserDetailsManager 类中,提供了创建、修改、删除、判断用户是否存在的方法,和修改用户密码的方法。
在 JdbcUserDetailsManager 这个实现子类中,已经定义好了 users 与 authorities 表对应的 CRUD 语句,所以我们直接调用相关方法即可实现对用户及角色的管理。另外我们在特殊情况下,也可以自定义这些 SQL 语句,如有需要,调用对应的 setXxxSQL()方法即可。
8. 项目结构
以上案例的完整代码结构如下图所示,请参考创建。
三. 测试运行
1. 启动项目测试
接下来我们把项目启动起来进行测试,这时候效果跟基于内存模型的授权实现效果是一样的,具体测试界面 壹哥 这里就不再展示了。
2. 小结
当我们使用 Spring Security 默认的数据库模型来操作实现用户授权时,存在灵活性不足的问题,因为我们必须按照源码规定的方式去建库建表。而我们真正开发时,用户角色等表肯定是根据自己的项目需求来单独设计的,所以真正开发时,我们有必要进行用户及角色表的自定义设计。
接下来 壹哥 就会带各位学习更灵活的基于自定义数据库模型的开发实现方式,敬请期待哦。对于本篇不明白的地方,请在评论区留言!
版权声明: 本文为 InfoQ 作者【一一哥】的原创文章。
原文链接:【http://xie.infoq.cn/article/855b57ecf94b8dce82ceb70ac】。未经作者许可,禁止转载。
评论