使用JDBCUserDetailsService方式实现身份验证
Posted 流星蝴蝶没有剑
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了使用JDBCUserDetailsService方式实现身份验证相关的知识,希望对你有一定的参考价值。
spring security 两个作用:
-
你是谁:who are you?
专业一点叫: Authentication(认证):
a. 内存认证
b. jdbc认证
c. UserDetailsService认证
d. ldap 认证
下面是源码中的四个认证方法
-
你能干什么:what are you allwoed to do?
pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>wx0725.top</groupId>
<artifactId>guojihua</artifactId>
<version>1.0.0</version>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.3.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>1.8</java.version>
</properties>
<dependencies>
<!-- Spring Boot提供的配置处理器依赖,代码提示 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<optional>true</optional>
</dependency>
<!-- web 开发场景-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- 测试依赖-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<!-- 热部署-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
</dependency>
<!-- 静态模板依赖-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<!-- IO 操作-->
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.6</version>
</dependency>
<!-- 数据库连接-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
<!-- 阿里巴巴 适配的druid数据源启动器 -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-starter</artifactId>
<version>1.1.10</version>
</dependency>
<!-- Spring Data JPA启动器-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<!-- redis 依赖-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<!-- spring security-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<!-- JDBC 连接数据库的依赖启动器-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
</dependencies>
<!-- maven 打包工具等插件-->
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<version>2.1.3.RELEASE</version>
</plugin>
</plugins>
</build>
</project>
1. 内存认证
写一个配置类,自定义内存认证。
package wx0725.top.config;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
/**
* @author WEN
* @version 1.0
* @description: Wen Xuan
* @date 2021/5/7 下午 19:42
* @link http://wx0725.top
*/
@EnableWebSecurity
// 上面一个注解中包含下面三个注解
//@Import
//@EnableGlobalAuthentication
//@Configuration
public class WebSecurityConfig extends WebSecurityConfigurerAdapter
@Override
protected void configure(AuthenticationManagerBuilder authenticationManagerBuilder) throws Exception
// 选择定义密码加密算法
BCryptPasswordEncoder bCryptPasswordEncoder = new BCryptPasswordEncoder();
// 内存认证使用这个密码加密
authenticationManagerBuilder.inMemoryAuthentication().passwordEncoder(bCryptPasswordEncoder)
// 注册一个身份,并且密码需要加密
.withUser("文轩").password(bCryptPasswordEncoder.encode("0725")).roles("common")
.and()
.withUser("wenxuan").password(bCryptPasswordEncoder.encode("wenxuan")).roles("vip");
新建一个index.html
<html>
<head>
<meta charset = "UTF-8">
<meta name = "viewport"
content = "width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
<meta http-equiv = "X-UA-Compatible" content = "ie=edge">
<title>首页</title>
</head>
<body>
<h1>hello world!</h1>
</body>
</html>
运行项目
输入:127.0.0.1:8082 也就是直接访问 spring boot 项目地址
此时会自动跳珠到login
可以看到login页面是从127.0.0.1:8082重定向过去的
2. JDBC 认证
需要新建一个安全检测的表格:
客户表:
身份表:
客户对应的身份表
在内存认证的配置类中如下代码:
package wx0725.top.config;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.WebSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import javax.sql.DataSource;
/**
* @author WEN
* @version 1.0
* @description: Wen Xuan
* @date 2021/5/7 下午 19:42
* @link http://wx0725.top
*/
@EnableWebSecurity
// 上面一个注解中包含下面三个注解
//@Import
//@EnableGlobalAuthentication
//@Configuration
public class WebSecurityConfig extends WebSecurityConfigurerAdapter
@Autowired
private DataSource dataSource;
@Override
protected void configure(AuthenticationManagerBuilder authenticationManagerBuilder) throws Exception
// 选择定义密码加密算法
BCryptPasswordEncoder bCryptPasswordEncoder = new BCryptPasswordEncoder();
// 内存认证使用这个密码加密
authenticationManagerBuilder.inMemoryAuthentication().passwordEncoder(bCryptPasswordEncoder)
// 注册一个身份,并且密码需要加密
.withUser("user").password(bCryptPasswordEncoder.encode("user")).roles("common")
.and()
.withUser("admin").password(bCryptPasswordEncoder.encode("admin")).roles("common");
// 使用JDBC认证
// 查询客户
String usql = "select username,password,valid from t_customer where username=?";
// 查询客户对应的身份
String asql = "select c.username, a.authority from t_customer c,t_authority a,t_customer_authority ca where ca.customer_id=c.id and ca.authority_id=a.id and c.username=?";
authenticationManagerBuilder.jdbcAuthentication().passwordEncoder(bCryptPasswordEncoder)
.dataSource(dataSource)
.usersByUsernameQuery(usql)
.authoritiesByUsernameQuery(asql);
// 允许忽略静态资源的安全访问
@Override
public void configure(WebSecurity web) throws Exception
web.ignoring().antMatchers("/css/**", "/js/**", "/img/**", "/fonts/**");
登录成功之后会跳转到首页
这里其实跳到首页是因为第一次输入的时候,输入的是127.0.0.1:8082
如果你输入的是其他的页面,在登录成功之后会跳转到那个页面,并非跳转到首页。
3.UserDetailsService
这一部分代码不少:
其主要实现的是减少数据库压力,通过用户缓存信息,实现验证登录,在登录的时候只查询一次数据库,将其保存在缓存中,下次查询就直接读取缓存。
- 新建三个实体类
分别对应上面的三个表格,但是这里没有用到用户权限id对应的实体类,只在查询的时候用到表格了,所以该表没写对应的实体类
- Customer.java
- 保存用户对应的权限
package wx0725.top.domain;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import java.io.Serializable;
/**
* @author WEN
* @version 1.0
* @description: Wen Xuan
* @date 2021/5/8 下午 13:58
* @link http://wx0725.top
*
* 用户信息
*/
@Entity(name = "t_customer")
public class Customer implements Serializable
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
private String username;
private String password;
private Integer valid;
@Override
public String toString()
return "Customer" +
"id=" + id +
", username='" + username + '\\'' +
", password='" + password + '\\'' +
", valid=" + valid +
'';
public Integer getId()
return id;
public void setId(Integer id)
this.id = id;
public String getUsername()
return username;
public void setUsername(String username)
this.username = username;
public String getPassword()
return password;
public void setPassword(String password)
this.password = password;
public Integer getValid()
return valid;
public void setValid(Integer valid)
this.valid = valid;
- Authority.java
- 保存用户的基本信息,这里是我自己设置的,没有对应数据库字段
package wx0725.top.domain;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import java.io.Serializable;
/**
* @author WEN
* @version 1.0
* @description: Wen Xuan
* @date 2021/5/8 下午 14:13
* @link http://wx0725.top
* <p>
* 用户权限
*/
@Entity(name = "t_authority")
public class Authority implements Serializable
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
private String authority;
@Override
public String toString()
return "Authority" +
"id=" + id +
", authority='" + authority + '\\'' +
'';
public Integer getId()
return id;
public void setId(Integer id)
this.id = id;
public String getAuthority()
return authority;
public void setAuthority(String authority)
this.authority = authority;
- 还需对应写两个接口:
- CustomerRepository.java
- 通过用户名查询用户信息
package wx0725.top.repository;
import org.springframework.data.jpa.repository.JpaRepository;
import wx0725.top.domain.Customer;
/**
* @author WEN
* @version 1.0
* @description: Wen Xuan
* @date 2021/5/8 下午 13:56
* @link http://wx0725.top
* <p>
* 用户信息查询接口
*/
public interface CustomerRepository extends JpaRepository<Customer, Integer>
// 可以直接使用JPA生成的实现
// @Query(value = "select c.* from t_customer c where c.username=?1", nativeQuery = true)
Customer findByUsername(String username);
- AuthorityRepository.java
- 通过用户名查询用户对应的权限
- 需要注意的是查询时需要些 a.* 不然会报错,懵逼,这里没查到
package wx0725.top.repository;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import wx0725.top.domain.Authority;
import java.util.List;
/**
* @author WEN
* @version 1.0
* @description: Wen Xuan
* @date 2021/5/8 下午 13:57
* @link http://wx0725.top
*/
public interface AuthorityRepository extends JpaRepository<Authority, Integer>
// a.*
@Query(value = "select a.* from t_customer c,t_authority a,t_customer_authority ca where ca.customer_id=c.id and ca.authority_id=a.id and c.username=?1", nativeQuery = true)
List<Authority> findAuthoritiesByUsername(String s);
- 接下来就是具体的实现操作,也就是业务层
对接实体层与控制层
- CustomerService.java
- 用来获取用户信息与权限,方便控制层调用
package wx0725.top.service;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import wx0725.top.domain.Authority;
import wx0725.top.domain如何使用R语言进行卡方检验