SpringBoot 集成 SpringSecurity 详解(四)-- 基于MySQL数据库实现多用户认证信息

需求缘起

上一小节中,我们基于内存实现了多用户登录,但是很明显我们不可能为每一个用户这样配置,我们需要对用户进行持久化操作,一般都是通过数据库进行操作的。这一节我们就通过MySql数据库来操作。

技术要点

实现 UserDetailsService 接口中的 loadUserByUsername() 方法,在该方法中的主要逻辑是,将数据库中的用户名,密码和权限信息(现在先不考虑权限相关的知识点)传给 SpringSecurity ,由SpringSecurity 进一步处理。

Spring Data JPA进行操作数据库,关于 Spring JPA 的使用可以参考我的另一篇博文一起学Springboot – 第四节 Spring-data-jpa 操作MySQL数据库(一)

1.添加依赖

添加MySQL数据库依赖,我们在创建项目的时候已经添加过了,没添加过的再添加即可

        <!--MySql 依赖,要同步本地安装的数据库版本,我这里是8.0.11-->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <scope>runtime</scope>
            <version>8.0.11</version>
        </dependency>
        <!Spring data jpa 依赖 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-jpa</artifactId>
        </dependency>
       <!--这里使用阿里巴巴数据连接池-->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid</artifactId>
            <version>1.1.10</version>
        </dependency>

2. 添加配置

在application.yml 中添加数据库相关配置

spring:
  datasource:
    type: com.alibaba.druid.pool.DruidDataSource
    driverClassName: com.mysql.cj.jdbc.Driver
    url: jdbc:mysql://127.0.0.1:3306/security?useUnicode=true&characterEncoding=utf8&useSSL=false&serverTimezone=UTC
    username: root
    password: 123456
  jpa:
   show-sql: true
   hibernate:
     ddl-auto: update
   database: mysql

3.创建实体类 userinfo

@Data
@Entity
public class UserInfo {

    @Id//用户id
    @GeneratedValue(strategy = GenerationType.IDENTITY)//自增
    private Long id;
    //用户名
    private String username;
    //用户密码
    private String password;
}

4.创建Repository

JPA 与数据库交互 UserInfoRepository 接口

@Repository
public interface UserInfoRepository extends JpaRepository<UserInfo, Long> {
    /**
     * 通过用户名获取用户信息
     * @param username
     * @return
     */
    UserInfo findByUsername(String username);
}

5. UserInfo 实现业务逻辑

我们在这实现两个业务逻辑,添加用户信息和通过用户名获取用户信息。

UserInfoService 接口

public interface UserInfoService {

    /**
     * 创建新用户
     * @param userInfo
     * @return
     */
    UserInfo create(UserInfo userInfo);

    /**
     * 通过用户名查找用户信息
     * @param username
     * @return
     */
    UserInfo findByUsername(String username);
}

UserInfoService 接口实现类

package com.security.demo.service.impl;

import com.security.demo.entity.UserInfo;
import com.security.demo.repository.UserInfoRepository;
import com.security.demo.service.UserInfoService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
@Service
public class UserInfoServiceImpl implements UserInfoService {

    @Autowired
    private UserInfoRepository userInfoRepository;

    @Autowired
    private PasswordEncoder passwordEncoder;

    /**
     * 创建新用户
     *
     * @param userInfo
     * @return
     */
    @Override
    public UserInfo create(UserInfo userInfo) {
    	//密码加密
    	userInfo.setPassword(passwordEncoder.encode(userInfo.getPassword()));
        return userInfoRepository.save(userInfo);
    }

    /**
     * 通过用户名查找用户信息
     *
     * @param username
     * @return
     */
    @Override
    public UserInfo findByUsername(String username) {
        return userInfoRepository.findByUsername(username);
    }
}

在springSecurity 5.x之后密码需要加密,当创建用户信息的时候加密,还需要在配置,其实在上一节中我们使用过了,代码如下

@Configuration
@EnableWebSecurity//开启Spring Security的功能
public class SecurityConfig  extends WebSecurityConfigurerAdapter {

    @Bean
    public PasswordEncoder passwordEncoder() {
        //SpringSecurity 提供的一种编码器,我们也可以自己实现PasswordEncoder
        return new BCryptPasswordEncoder();
    }
}

6.添加用户信息

创建服务测试类 UserInfoServiceImplTest ,在类中添加用户信息

@Component
@Slf4j
public class UserInfoServiceImplTest extends SpringSecurityDemoApplicationTests {

    @Autowired
    private UserInfoService userInfoService;
    
    @Test
    public void create() {
        UserInfo userInfo1 = new UserInfo();
        userInfo1.setId(1L);
        userInfo1.setUsername("admin");
        userInfo1.setPassword("123456");
        UserInfo userInfoPO1 = userInfoService.create(userInfo1);
        log.info("userInfoPO1={}", userInfoPO1);

        UserInfo userInfo2 = new UserInfo();
        userInfo2.setId(2L);
        userInfo2.setUsername("user");
        userInfo2.setPassword("123456");
        UserInfo userInfoPO2 = userInfoService.create(userInfo2);
        log.info("userInfoPO2={}", userInfoPO2);
    }
}

执行 create() 方法后如果不出意外数据库中应该有两条数据了,可通过可视化工具或者 mysql 指令查看。

7.实现 UserDetailsService 接口中的 loadUserByUsername() 方法

这个也是这一小节的核心,这个方法的作用是将用户名、密码和权限传递给 Spring Security

@Component
@Slf4j
public class MyUserDetailsService implements UserDetailsService {

    @Autowired
    private UserInfoService userInfoService;

    @Autowired
    private PasswordEncoder passwordEncoder;


    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {

        log.info("loadUserByUsername->username={}", username);
        UserInfo userInfo = userInfoService.findByUsername(username);
        if (userInfo == null) {
            throw new UsernameNotFoundException("用户不存在");
        }
        //暂时不考虑权限
        List<GrantedAuthority> authorities = new ArrayList<>();
        
        //如果在创建用户信息的时候没有加密,这里就需要做加密处理否则会报错
        // User userDetails = new User(userInfo.getUsername(), passwordEncoder.encode(userInfo.getPassword()), authorities);
        
        //已经在创建用户信息的时候做了加密处理,这里直接使用即可
        User userDetails = new User(userInfo.getUsername(), userInfo.getPassword(), authorities);
        return userDetails;
    }
}

8.启动测试即可

具体测试这里不写了,参考上一篇,不出意外,项目将可以正常运行,本节Demo代码

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值