第十七章:使用SpringSecurity让SpringBoot项目更安全

SpringSecurity是专门针对基于Spring项目的安全框架,充分利用了依赖注入和AOP来实现安全管控。在很多大型企业级系统中权限是最核心的部分,一个系统的好与坏全都在于权限管控是否灵活,是否颗粒化。在早期的SpringSecurity版本中我们需要大量的xml来进行配置,而基于SpringBoot整合SpringSecurity框架相对而言简直是重生了,简单到不可思议的地步。

SpringSecurity框架有两个概念认证授权,认证可以访问系统的用户,而授权则是用户可以访问的资源,下面我们来简单讲解下SpringBootSpringSecurity安全框架的支持。

本章目标

SpringBoot项目中使用SpringSecurity安全框架实现用户认证以及授权访问。

构建项目

我们使用IntelliJ IDEA工具创建一个SpringBoot项目,预先加入JPA、Security、Druid、MySQL等依赖,项目结构如下图1所示:

图1

我们下面先来配置数据库访问的配置,将我们之前章节(第十三章:SpringBoot实战SpringDataJPA)的application.yml配置文件复制到本章项目resources目录下,如下图2所示:

图2

用户和角色

数据库连接配置完成后,我们开始创建本章需要用到的三张表,用户表、角色表、用户角色关联表,一个用户存在多个角色!用户表结构图下图3所示:

图3

我们用户表结构仅有三个字段,这里只是为了演示我们的安全框架,所以不做太过详细。下面是我们的角色信息表结构如下图4所示:

图4

因为我们一个用户存在多个角色,一个角色又可以应用到多个用户上,所以我们采用的关联表的方式进行配置关系,用户角色关联表结构如下图5所示:

图5

下面我们根据用户信息表以及角色信息表创建对应的实体,如下图6、图7所示:

图6

可以看到我们的UserEntity实现了UserDetails接口,UserDetails是SpringSecurity验证框架内部提供的用户验证接口(我们下面需要用到UserEntity来完成自定义用户认证功能),我们需要实现getAuthorities方法内容,将我们定义的角色列表添加到授权的列表内。

图7

可以看到我们的用户实体内添加了对角色的列表支持,并添加了@ManyToMany的关系注解。我们查询用户时SpringDataJPA会自动查询处关联表user_roles对应用户的角色列表放置到名叫rolesList集合内。

填充测试数据

我们对用户表、角色表、关联表添加几条对应的数据,SQL脚本如下图8所示:

图8

初始化的SQL脚本已经添加到本章的resources目录下,本章结束为止会有源码下载地址。

配置JPA访问数据

根据创建的UserEntity实体来创建UserJPA接口并继承JPARepository接口,UserJPA内添加一个根据用户名查询的方法,如下图9所示:

图9

我们可以看到我在图9的UserJPA接口内添加了一个findByUsername方法,这个方法其实是SpringDataJPA的一个规则,我们这样写JPA就会认为我们要根据username这个字段去查询,并自动使用参数索引为0的值(有关SpringDataJPA方法查询后期会在SpringDataJPA 核心技术内体现)。

自定义SpringSecurity用户认证

我们上面的配置差不多已经完成,下面我们实现SpringSecurity内的UserDetailsService接口来完成自定义查询用户的逻辑,如下图10所示:

图10

可以看到上图10内的定义,实现UserDetailsService接口需要完成loanUserByUsername重写,我们使用UserJPA内的findByUsername方法从数据库中读取用户,并将用户作为方法的返回值。

配置SpringSecurity

自定义用户认证已经编写完成,下面我们需要配置SpringBoot项目支持SpringSecurity安全框架,具体配置代码如下图11所示:

图11

可以看到我们上图11配置了所有请求都必须登录访问,第一句我们仅用了csrd,在springSecurity4.0后,默认开启了CSRD拦截,如果需要配置请在form表单添加如下图12配置:

图12

我们这里配置了登录页面127.0.0.1:8080/login请求地址以及登录错误页面/login?error不被SpringSecurity拦截。下面我们来编写登录的JSP页面,我们之前构建项目的时候并没有添加JSP的依赖,下面我们修改pom.xml添加JSP依赖,如下图13所示:

图13

我们修改application.yml配置文件添加JSP的页面配置,如下图14所示:

图14

好了,下面我们简单的创建一个login.jsp页面,页面里面添加一个简单的表单提交,我们的表单提交地址这里要注意了,SpringSecurity内部已经给我们定义好了,在4.0版本之后登录地址都是/login,当然这个/login并不是我们上面配置的loginPage地址。这个地址如果直接访问是访问不到的。必须采用Post形式访问,login.jsp页面内容如下图15所示:

图15

我们来配置一个简单的SpringBoot内的MVC控制器跳转,下面我们添加一个名叫MVCConfig配置类继承WebMvcConfigurerAdapter类,重写addViewControllers()方法添加路径访问,可以通过Get形式的/login访问到我们的login.jsp,代码如下图16所示:

图16

上面有关SpringSecurity配置都已经完成,接下来我们添加一个IndexController来测试我们的SprinySecurity框架是否已经生效,我们上面已经配置了,如果在不登陆的状态下只有/login是可以访问的,所以我们直接访问/index是不可行的。SpringSecurity会直接给我们重定向到我们配置的loginPage,IndexController代码如下图17所示:

图17

运行测试

下面我们来启动项目,先来访问/index查看界面效果,如下图18所示:

图18

正如我们所说的,当我们在没有登录的状态下访问/index时,会直接被安全框架重定向到登录页面,那么我们登录后,再来访问/index并查看界面输出,如下图19所示:

图19

可以看到界面的效果,我们已经可以正确的访问到index路径所返回的数据,证明了我们的安全框架已经生效了。

角色判断

我们在文章开始的部分已经创建了角色表,我们下面就要根据角色,在用户登录成功后显示不同的内容,在这之前我们需要添加SpringSecurity为我们提供的JSTL标签库,我们可以根据标签库自行判断登录用户的角色,我们修改pom.xml配置文件添加如下图20所示依赖:

图20

下面我们创建main.jsp,在jsp页面引入SpringSecurity标签库,并根据角色判断输出内容,如下图21所示:

图21

我们在main.jsp判断了是超级管理员、普通用户的角色并根据不同的角色输出不同的内容,下面我们重启项目访问127.0.0.1:8080/main地址查看界面输出内容,如下图22所示:

图22

我们的界面并没有输出任何的内容,这是为什么呢?

SpringSecurity不支持中文比对,所以我们这里不能直接使用角色中文名称作为判断条件,下面我们修改roles信息表添加一个标识字段,如下图23所示:

图23

下面我们对应的添加RoleEntity实体内字段,如下图24所示:

图24

还有最重要的一点,我们的UserEntity内是根据RoleName来添加角色授权的,下面我们需要改成flag,如下图25所示:

图25

最后我们修改main.jsp,hasRole改成对应的flag字段值,如下图26所示:

图26

上图的ROLE_USERROLE_ADMIN是我们在roles表内的对应添加的数据,也是作为授权的flag字段值,下面我们重启项目,登录后再来访问127.0.0.1:8080/main页面查看界面输出如下图27所示:

图27

界面为了们输出了两条信息,这个是正确的,因为我们在user_roles表内为admin用户添加了两条对应的角色。下面我们修改user_roles表结构,删除对应普通用户的关联,再来访问127.0.0.1:8080/main,界面输出效果如下图28所示:

图28

我们很奇怪,数据为什么没有变化呢?因为SpringSecurity将我们的用户数据、角色数据都缓存到框架内,下面我们来重启下项目再次访问后,界面输出内容如下图29所示:

图29

这次界面输出的内容才是正确的。

总结

以上内容就是本章的全部内容,本章主要讲解了SpringBoot项目中如何使用SpringSecurity来作为安全框架,并通过SpringSecurity提供的JSTL标签库来判断界面的输出,还有如果修改了用户的权限不会实时生效,而需要我们退出用户后再次登录方可生效。

本章的代码以及SQL都已上传到码云:

SpringBoot配套源码地址:https://gitee.com/hengboy/spring-boot-chapter

SpringCloud配套源码地址:https://gitee.com/hengboy/spring-cloud-chapter

SpringBoot相关系列文章请访问:目录:SpringBoot学习目录

QueryDSL相关系列文章请访问:QueryDSL通用查询框架学习目录

SpringDataJPA相关系列文章请访问:目录:SpringDataJPA学习目录

SpringBoot相关文章请访问:目录:SpringBoot学习目录,感谢阅读!

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏LanceToBigData

Maven(二)Maven项目的创建(命令、myeclipse)及生命周期

上一篇给大家介绍了Maven的概念和仓库的一些信息,接下来给大家分享一下使用命令和MyEclipse创建Maven项目 一、使用命令管理Maven项目 1.1、...

1819
来自专栏pythonlove

FTP使用MariaDB完成虚拟用户认证

文件传输协议(英文:File Transfer Protocol,縮寫:FTP)是用於在網絡上進行文件傳輸的一套標準協議。它属于网络传输协议的应用层。FTP是一...

824
来自专栏小狼的世界

Maven 快速入门

Maven是一个Java工具,因此你的电脑上必须安装有JAVA环境(JDK或者JRE)

973
来自专栏微信公众号:Java团长

单点登录原理与简单实现

web应用采用browser/server架构,http作为通信协议。http是无状态协议,浏览器的每一次请求,服务器会独立处理,不与之前或之后的请求产生关联,...

934
来自专栏緣來來來

如何启用Shadowsocks的多端口

一键脚本默认只会开启单个端口以供使用。之所以这么做,是因为考虑到一般都是个人使用才会自己搭建属于自己的 Shadowsocks 服务端,所以在安装交互的时候,默...

2652
来自专栏依乐祝

使用Visual Studio Code开发.NET Core看这篇就够了

在本文中,我将带着大家一步一步的通过图文的形式来演示如何在Visual Studio Code中进行.NET Core程序的开发,测试以及调试。尽管Visual...

690
来自专栏LanceToBigData

KVM+Qemu+Libvirt实战

上一篇的文章是为了给这一篇文件提供理论的基础,在这篇文章中我将带大家一起来实现在linux中虚拟出ubuntu的server版来 我们需要用KVM+Qemu+L...

3287
来自专栏Web项目聚集地

Git简洁教程-本地项目推送到GitHub

Git是当今最流行的版本控制软件,它包含了许多高级工具,这里小编就讲一下Git的安装和使用,怎样推送到自己的远程仓库。

832
来自专栏JMCui

Docker 系列四(自定义仓库).

    Docker hub 是 Docker 官方维护的一个公共仓库,大部分需求都可以通过在 Docker hub 中直接下载镜像来完成。接下来,来看一下怎么...

1113
来自专栏SpringBoot 核心技术

SpringCloud组件:搭建Eureka服务注册中心

Eureka服务注册中心是netflix开源组织提供的一个服务高可用的解决方案,在前端时间一直在疯传的2.0开源流产的问题,其实并不影响我们的使用,netfli...

682

扫码关注云+社区