SpringSecurity实现基于数据库的身份验证
程序员文章站
2022-07-03 11:00:16
...
1. 问题描述
基于数据库MySQL实现用户登录的身份验证,暂时不考虑权限问题;
2.技术选型
SpringBoot+SpringSecurity+SpringData JPA+MySQL;
3.Pom依赖
3.1 springboot版本
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.8.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
3.2 maven依赖
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
4.application.yml配置
spring:
# jpa
jpa:
show-sql: true
hibernate:
ddl-auto: update
database: mysql
# db
datasource:
type: com.zaxxer.hikari.HikariDataSource
url: jdbc:mysql://localhost/yuyufeng?useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone=UTC
hikari:
driver-class-name: com.mysql.cj.jdbc.Driver
username: root
password: 2289288246
5.项目结构
6.HelloSecurityController实现
package springsecuritydemo1.controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("/hello")
public class HelloSecurityController {
@GetMapping
public String hello(){
return "Hello Spring Security!";
}
}
启动项目,访问HelloSecurityController的路由,由于导入了SpringSecurity依赖,会出现默认的身份验证,跳转到 路径: http://localhost:8080/login; 默认用户名是:user,密码会在控制台生成:
Using generated security password: d3f3d4ff-111a-442c-8488-d6dfd4a15475
默认登录页面:
7.SpringData jpa实现
7.1 UserInfo实体实现
package springsecuritydemo1.entity;
import javax.persistence.*;
@Entity(name="userInfo")
@Table(name="user_info")
public class UserInfo {
@Id
@Column(name = "id")
@GeneratedValue(strategy = GenerationType.IDENTITY)//自增
private Long id;
//用户名
@Column(name = "username",nullable = false)
private String username;
//用户密码
@Column(name = "password",nullable = false,unique = false)
private String password;
public Long getId() {
return id;
}
public void setId(Long 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;
}
@Override
public String toString() {
return "UserInfo{" +
"id=" + id +
", username='" + username + '\'' +
", password='" + password + '\'' +
'}';
}
}
7.2 UserInfoRepository实现
package springsecuritydemo1.repository;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
import springsecuritydemo1.entity.UserInfo;
@Repository
public interface UserInfoRepository extends JpaRepository<UserInfo,Long> {
UserInfo findByUsername(String username);
}
7.3 UserInfoService接口及UserInfoServiceImpl类实现
(1) UserInfoService接口
package springsecuritydemo1.service;
import springsecuritydemo1.entity.UserInfo;
public interface UserInfoService {
UserInfo create(UserInfo userInfo);
UserInfo findByUsername(String username);
}
(2)UserInfoServiceImpl类
package springsecuritydemo1.service.impl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import springsecuritydemo1.entity.UserInfo;
import springsecuritydemo1.repository.UserInfoRepository;
import springsecuritydemo1.service.UserInfoService;
@Service
public class UserInfoServiceImpl implements UserInfoService {
@Autowired
private UserInfoRepository userInfoRepository;
@Autowired
private PasswordEncoder passwordEncoder;
@Override
public UserInfo create(UserInfo userInfo) {
//密码加密
userInfo.setPassword(passwordEncoder.encode(userInfo.getPassword()));
return userInfoRepository.save(userInfo);
}
@Override
public UserInfo findByUsername(String username) {
return userInfoRepository.findByUsername(username);
}
}
7.4 数据库数据准备
package springsecuritydemo1;
import org.junit.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import springsecuritydemo1.entity.UserInfo;
import springsecuritydemo1.service.UserInfoService;
@SpringBootTest
class SpringSecurityDemo1ApplicationTests {
@Autowired
private UserInfoService userInfoService;
@Test
void contextLoads() {
UserInfo userInfo1 = new UserInfo();
userInfo1.setId(1L);
userInfo1.setUsername("admin");
userInfo1.setPassword("123456");
UserInfo userInfoPO1 = userInfoService.create(userInfo1);
System.out.println(userInfo1);
UserInfo userInfo2 = new UserInfo();
userInfo2.setId(2L);
userInfo2.setUsername("user");
userInfo2.setPassword("123456");
UserInfo userInfoPO2 = userInfoService.create(userInfo2);
System.out.println(userInfo2);
}
}
不出意外,数据库已存在上述两条数据;
8. MyUserDetailService实现(关键步骤)
创建MyUserDetailService类,实现UserDetailsService接口,重写loadUserByUsername(String s)方法,返回的UserDetails类包含了用户名、密码、权限(暂不考虑),交给SpringSecurity进行身份验证;
package springsecuritydemo1.common.security;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Component;
import springsecuritydemo1.entity.UserInfo;
import springsecuritydemo1.service.UserInfoService;
import java.util.ArrayList;
import java.util.List;
@Component
public class MyUserDetailService implements UserDetailsService {
@Autowired
private UserInfoService userInfoService;
@Autowired
private PasswordEncoder passwordEncoder;
@Override
public UserDetails loadUserByUsername(String s) throws UsernameNotFoundException {
UserInfo userInfo = userInfoService.findByUsername(s);
if (userInfo == null) {
throw new UsernameNotFoundException("用户不存在");
}
//暂时不考虑权限验证,故该权限List为空;
List<GrantedAuthority> authorities = new ArrayList<>();
User userDetails = new User(userInfo.getUsername(), userInfo.getPassword(), authorities);
return userDetails;
}
}
9.SecurityConfig类实现
创建SecurityConfig类继承WebSecurityConfigurerAdapter类,注入PasswordEncoder;
package springsecuritydemo1.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
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 org.springframework.security.crypto.password.PasswordEncoder;
@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Bean
public PasswordEncoder passwordEncoder(){
return new BCryptPasswordEncoder();
}
@Override
protected void configure(HttpSecurity http) throws Exception {
super.configure(http);
}
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
super.configure(auth);
}
}
10.测试
10.1 测试
访问HelloSecurityController,进入默认登录页面,输入用户名与密码(参照7.4),登录成功,验证成功。