Spring Security进阶身份认证之使用数据库中的用户进行身份认证(附源码)

本文涉及的产品
云数据库 RDS MySQL Serverless,0.5-2RCU 50GB
简介:

    在上一篇HelloSpringSecurity一文中,我们使用了静态账号和密码的方式完成了身份认证。本文在上一篇博文的基础上,将使用数据库中的用户进行身份认证。从本文中你将会看到Spring Security使用数据库中的用户进行身份认证依然是非常简单的事情。


    1. 在pom.xml中添加mysql数据库驱动与c3p0数据源的相关的依赖。


1
2
3
4
5
6
7
8
9
10
  < dependency >
            < groupId >mysql</ groupId >
            < artifactId >mysql-connector-java</ artifactId >
            < version >5.1.21</ version >
  </ dependency >
< dependency >
             < groupId >c3p0</ groupId >
             < artifactId >c3p0</ artifactId >
             < version >0.9.1.2</ version >
  </ dependency >


    2. 准备MySQL数据库及相关数据。


    本例子使用到user(用户表)、role(角色表)和user_role(用户角色表)三个表,表之间的关系如下:


wKioL1TBtlex1oMgAACUVwD_IMc921.jpg


    为了方便大家进行测试,建表的语句如下:


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
/*
Navicat MySQL Data Transfer
 
Source Server         : 10.0.0.12
Source Server Version : 50619
Source Host           : 10.0.0.12:3305
Source  Database        : favsecurity
 
Target Server Type    : MYSQL
Target Server Version : 50619
File Encoding         : 65001
 
Date : 2015-01-23 10:28:39
*/
 
SET  FOREIGN_KEY_CHECKS=0;
 
-- ----------------------------
-- Table structure for role
-- ----------------------------
DROP  TABLE  IF EXISTS `role`;
CREATE  TABLE  `role` (
   `id`  int (11)  NOT  NULL  DEFAULT  '0'  COMMENT  'id' ,
   ` name varchar (50)  DEFAULT  NULL  COMMENT  'name' ,
   `descn`  varchar (50)  DEFAULT  NULL  COMMENT  'descn' ,
   PRIMARY  KEY  (`id`)
) ENGINE=InnoDB  DEFAULT  CHARSET=utf8 COMMENT= '角色表' ;
 
-- ----------------------------
-- Records of role
-- ----------------------------
INSERT  INTO  `role`  VALUES  ( '1' 'ROLE_ADMIN' '管理员角色' );
INSERT  INTO  `role`  VALUES  ( '2' 'ROLE_USER' '用户角色' );
 
-- ----------------------------
-- Table structure for user
-- ----------------------------
DROP  TABLE  IF EXISTS ` user `;
CREATE  TABLE  ` user ` (
   `id`  int (11)  NOT  NULL  DEFAULT  '0'  COMMENT  'id' ,
   `username`  varchar (50)  DEFAULT  NULL  COMMENT  'username' ,
   ` password varchar (50)  DEFAULT  NULL  COMMENT  'password' ,
   `status`  varchar (1024)  DEFAULT  NULL  COMMENT  'status' ,
   `descn`  varchar (1024)  DEFAULT  NULL  COMMENT  'descd' ,
   PRIMARY  KEY  (`id`),
   KEY  `AK_Key_1` (`id`)
) ENGINE=InnoDB  DEFAULT  CHARSET=utf8 COMMENT= '用户表' ;
 
-- ----------------------------
-- Records of user
-- ----------------------------
INSERT  INTO  ` user VALUES  ( '1' 'admin' 'admin' '1' '管理\r\n员' );
INSERT  INTO  ` user VALUES  ( '2' 'user' 'user' '1' '用户\r\n' );
INSERT  INTO  ` user VALUES  ( '3' 'favccxx' 'favboy' '1' '帅锅' );
 
-- ----------------------------
-- Table structure for user_role
-- ----------------------------
DROP  TABLE  IF EXISTS `user_role`;
CREATE  TABLE  `user_role` (
   `user_id`  int (11)  DEFAULT  NULL  COMMENT  '用户表_id' ,
   `role_id`  int (11)  DEFAULT  NULL  COMMENT  '角色表_id' ,
   KEY  `FK_FK_USER_ROLE_ROLE` (`role_id`),
   KEY  `FK_FK_USER_ROLE_USER` (`user_id`),
   CONSTRAINT  `FK_FK_USER_ROLE_USER`  FOREIGN  KEY  (`user_id`)  REFERENCES  ` user ` (`id`),
   CONSTRAINT  `FK_FK_USER_ROLE_ROLE`  FOREIGN  KEY  (`role_id`)  REFERENCES  `role` (`id`)
) ENGINE=InnoDB  DEFAULT  CHARSET=utf8 COMMENT= '用户角色表' ;
 
-- ----------------------------
-- Records of user_role
-- ----------------------------
INSERT  INTO  `user_role`  VALUES  ( '1' '1' );
INSERT  INTO  `user_role`  VALUES  ( '1' '2' );
INSERT  INTO  `user_role`  VALUES  ( '2' '2' );
INSERT  INTO  `user_role`  VALUES  ( '3' '1' );
INSERT  INTO  `user_role`  VALUES  ( '3' '2' );

        
    3. 修改springSecurity.xml,更改security:authentication-provider提供的用户访问机制。


<security:authentication-manager>

  <security:authentication-provider>

   <security:user-service>

    <security:user name="favccxx" password="favccxx" authorities="ROLE_USER,ROLE_ADMIN"/>

    <security:user name="super" password="super" authorities="ROLE_SUPERADMIN"/>

   </security:user-service>

  </security:authentication-provider>

 </security:authentication-manager>


     将上面的灰色划掉的部分更改为下面绿色的部分。


<security:authentication-manager>

  <security:authentication-provider>

       <security:jdbc-user-service data-source-ref="dataSource" users-by-username-query="select username,password,1 as enabled from user WHERE username=?"

        authorities-by-username-query="select u.username, r.name as role from user u,user_role ur, role r where u.id=ur.user_Id and r.id = ur.role_Id and u.username=?"/>

      </security:authentication-provider>

 </security:authentication-manager>


    备注:dataSource在springdb.xml中定义,在springSecurity.xml中引用springdb.xml即可。springdb.xml相关的文件如下:


    springdb.xml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
<? xml  version = "1.0"  encoding = "UTF-8" ?>
< beans  xmlns = "http://www.springframework.org/schema/beans"
     xmlns:xsi = "http://www.w3.org/2001/XMLSchema-instance"
     xmlns:context = "http://www.springframework.org/schema/context"
      xmlns:tx = "http://www.springframework.org/schema/tx"
      xmlns:aop = "http://www.springframework.org/schema/aop"
     xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
     http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd
           http://www.springframework.org/schema/tx
         http://www.springframework.org/schema/tx/spring-tx-3.0.xsd
          http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd
     ">
     
     < context:property-placeholder  location = "classpath:database.properties" />
     
     < bean  id = "dataSource"  class = "com.mchange.v2.c3p0.ComboPooledDataSource"  destroy-method = "close" >
         < property  name = "driverClass" >
             < value >${dataSource.driverClassName}</ value >
         </ property >
         < property  name = "jdbcUrl" >
             < value >${dataSource.url}</ value >
         </ property >
         < property  name = "user" >
             < value >${dataSource.username}</ value >
         </ property >
         < property  name = "password" >
             < value >${dataSource.password}</ value >
         </ property >
 
         <!-- 最大连接数 -->
         < property  name = "maxPoolSize" >
             < value >${dataSource.c3p0.max_size}</ value >
         </ property >
 
         <!-- 最小连接数 -->
         < property  name = "minPoolSize" >
             < value >${dataSource.c3p0.min_size}</ value >
         </ property >
 
         <!-- 最大空闲时间,超时未被使用则连接被抛弃,单位毫秒 -->
         < property  name = "maxIdleTime" >
             < value >${dataSource.c3p0.max_idle_time}</ value >
         </ property >
 
         <!-- 获得连接的超时时间,如果超过这个时间,会抛出异常,单位毫秒 -->
         <!-- 
         <property name="checkoutTimeout">
             <value>${dataSource.c3p0.checkout_timeout}</value>
         </property>
        -->
 
         <!-- 最大的PreparedStatement的数量 -->
         < property  name = "maxStatements" >
             < value >${dataSource.c3p0.max_statements}</ value >
         </ property >
 
         <!-- 每隔120秒检查连接池里的空闲连接 ,单位是秒 -->
         < property  name = "idleConnectionTestPeriod" >
             < value >${dataSource.c3p0.idle_test_period}</ value >
         </ property >
 
         <!-- 当连接池里面的连接用完的时候,C3P0一下获取的新的连接数 -->
         < property  name = "acquireIncrement" >
             < value >${dataSource.c3p0.acquire_increment}</ value >
         </ property >
     </ bean >
     
</ beans >


    database.properties

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<![CDATA[
dataSource.driverClassName=com.mysql.jdbc.Driver
dataSource.username=favccxx
dataSource.password=favboy
dataSource.url=jdbc:mysql://10.0.0.12:3305/favsecurity?useUnicode=true&characterEncoding=utf-8
 
 
# For c3p0 connect pool
dataSource.c3p0.max_size=200
dataSource.c3p0.min_size=10
dataSource.c3p0.max_idle_time=300
#dataSource.c3p0.checkout_timeout=30000
dataSource.c3p0.max_statements=0
dataSource.c3p0.idle_test_period=120
dataSource.c3p0.acquire_increment=5
 
]]>


    4. 工程运行效果如下

wKioL1TBuF2icSKJAAEI0IdviBU699.jpg

wKiom1TBt4bRzodmAAGcgxLBT3Q508.jpg


    5. 点这里看看源代码





本文转自 genuinecx 51CTO博客,原文链接:http://blog.51cto.com/favccxx/1607284,如需转载请自行联系原作者
目录
相关文章
|
1月前
|
XML 缓存 Java
Spring源码之 Bean 的循环依赖
循环依赖是 Spring 中经典问题之一,那么到底什么是循环依赖?简单说就是对象之间相互引用, 如下图所示: 代码层面上很好理解,在 bean 创建过程中 class A 和 class B 又经历了怎样的过程呢? 可以看出形成了一个闭环,如果想解决这个问题,那么在属性填充时要保证不二次创建 A对象 的步骤,也就是必须保证从容器中能够直接获取到 B。 一、复现循环依赖问题 Spring 中默认允许循环依赖的存在,但在 Spring Boot 2.6.x 版本开始默认禁用了循环依赖 1. 基于xml复现循环依赖 定义实体 Bean java复制代码public class A {
|
1月前
|
存储 缓存 Java
【Spring原理高级进阶】有Redis为啥不用?深入剖析 Spring Cache:缓存的工作原理、缓存注解的使用方法与最佳实践
【Spring原理高级进阶】有Redis为啥不用?深入剖析 Spring Cache:缓存的工作原理、缓存注解的使用方法与最佳实践
|
1月前
|
前端开发 搜索推荐 Java
【Spring底层原理高级进阶】基于Spring Boot和Spring WebFlux的实时推荐系统的核心:响应式编程与 WebFlux 的颠覆性变革
【Spring底层原理高级进阶】基于Spring Boot和Spring WebFlux的实时推荐系统的核心:响应式编程与 WebFlux 的颠覆性变革
|
1月前
|
Java 测试技术 数据库连接
【Spring源码解读!底层原理高级进阶】【下】探寻Spring内部:BeanFactory和ApplicationContext实现原理揭秘✨
【Spring源码解读!底层原理高级进阶】【下】探寻Spring内部:BeanFactory和ApplicationContext实现原理揭秘✨
|
1天前
|
Java 关系型数据库 MySQL
一套java+ spring boot与vue+ mysql技术开发的UWB高精度工厂人员定位全套系统源码有应用案例
UWB (ULTRA WIDE BAND, UWB) 技术是一种无线载波通讯技术,它不采用正弦载波,而是利用纳秒级的非正弦波窄脉冲传输数据,因此其所占的频谱范围很宽。一套UWB精确定位系统,最高定位精度可达10cm,具有高精度,高动态,高容量,低功耗的应用。
一套java+ spring boot与vue+ mysql技术开发的UWB高精度工厂人员定位全套系统源码有应用案例
|
2天前
|
SQL JavaScript API
❤Nodejs 第四章(操作本地数据库实现删除-源码地址已开放)
【4月更文挑战第4天】❤Nodejs 第四章(操作本地数据库实现删除-源码地址已开放)在Node.js中实现删除本地数据库记录的操作。首先尝试通过SQL删除ID为8的用户,然后编写`app.delete`路由处理程序,从请求体获取ID并执行删除。。最终成功删除用户并展示了数据库的更新结果。下一节将优化增删改查功能。
15 1
|
7天前
|
XML Java 数据格式
进阶注解探秘:深入Spring高级注解的精髓与实际运用
进阶注解探秘:深入Spring高级注解的精髓与实际运用
24 2
|
30天前
|
Java Spring
使用spring实现邮件的发送(含测试,源码,注释)
使用spring实现邮件的发送(含测试,源码,注释)
7 0
|
1月前
|
Java 大数据 数据库
【Spring底层原理高级进阶】Spring Batch清洗和转换数据,一键处理繁杂数据!Spring Batch是如何实现IO流优化的?本文详解!
【Spring底层原理高级进阶】Spring Batch清洗和转换数据,一键处理繁杂数据!Spring Batch是如何实现IO流优化的?本文详解!
|
1月前
|
Java Spring 容器
【Spring源码】单例创建期间进行同步可能会导致死锁?
通过这个标题我们就可以思考本次的阅读线索了,看起来可以学到不少东西。1. 旧代码的死锁是怎么产生的。2. 贡献者通过改变什么来解决本次PR的问题呢?而阅读线索2的答案也显而易见,就是上文提到的通过后台线程来创建Micrometer单例...
41 3