spring security基于jdbc的账号密码

文档

  1. 00 - spring security框架使用
  2. 01 - spring security自定义登录页面
  3. 02 - spring security基于配置文件及内存的账号密码
  4. 03 - spring security自定义登出页面
  5. 04 - spring security关闭csrf攻击防御
  6. 05 - spring security权限控制
  7. 06 - spring security角色和权限设置
  8. 07 - spring security基于数据库的账号密码

基于jdbc的账号密码

说明
  1. spring security自带基于内存的登录认证及基于jdbc的登录认证
  2. 基于jdbc的登录认证会将用户信息及权限信息存储在数据库中,登录认证、添加用户等功能spring security已经实现
  3. spring security提供了sql脚本,能够创建users表及authorities表,位置:org\springframework\security\spring-security-core\6.2.0\spring-security-core-6.2.0.jar!\org\springframework\security\core\userdetails\jdbc\users.ddl,但此脚本不适配mysql,使用时需要调整
配置基于jdbc的账号密码
  1. 在上篇文章07 - spring security基于数据库的账号密码的基础上进行修改即可

  2. 在上篇文章中,已经配置了数据源,这里也需要用到数据源

  3. 在数据库中创建users表及authorities表,spring security提供了sql脚本,但不适配mysql,下面是参考脚本

    创建users

    CREATE TABLE `users` (
      `username` varchar(50) COLLATE utf8mb4_general_ci NOT NULL,
      `PASSWORD` varchar(500) COLLATE utf8mb4_general_ci NOT NULL,
      `enabled` tinyint(1) NOT NULL,
      PRIMARY KEY (`username`)
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
    

    创建authorities

    CREATE TABLE `authorities` (
      `username` varchar(50) COLLATE utf8mb4_general_ci NOT NULL,
      `authority` varchar(50) COLLATE utf8mb4_general_ci NOT NULL,
      UNIQUE KEY `ix_auth_username` (`username`,`authority`),
      CONSTRAINT `fk_authorities_users` FOREIGN KEY (`username`) REFERENCES `users` (`username`)
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
    
  4. 在上篇文章中,自定义了UserDetailsManager的实现类DatabaseUserDetailsManager,并且接受spring管理,这里需要取消spring管理该类,注释掉DatabaseUserDetailsManager类上的@Component注解即可

    package xin.yangshuai.springsecurity03.config;
    
    import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.security.core.userdetails.User;
    import org.springframework.security.core.userdetails.UserDetails;
    import org.springframework.security.core.userdetails.UsernameNotFoundException;
    import org.springframework.security.provisioning.UserDetailsManager;
    import org.springframework.stereotype.Component;
    import xin.yangshuai.springsecurity03.entity.SpringSecurityUser;
    import xin.yangshuai.springsecurity03.mapper.SpringSecurityUserMapper;
    
    //@Component
    public class DatabaseUserDetailsManager implements UserDetailsManager {
    // ...   
    }
    
  5. 定义一个UserDetailsManager类型的Bean,实际的实现类是JdbcUserDetailsManager,既基于jdbc的登录认证。该实现类需要传入数据源,数据源可以直接通过注入的方式获取到

    @Configuration
    // @EnableWebSecurity
    @EnableMethodSecurity //开启基于方法的授权
    public class WebSecurityConfig {
    
        @Autowired
        private DataSource dataSource;
    
        @Bean
        public UserDetailsManager userDetailsManager() {
    
            JdbcUserDetailsManager manager = new JdbcUserDetailsManager();
            manager.setDataSource(dataSource);
    
            if (!manager.userExists("user")) {
                manager.createUser(User.withDefaultPasswordEncoder().username("user").password("password").authorities("USER_LIST").build());
            }
    
            return manager;
        }
        
        // ...
    }
    
    • 在基于内存的账号密码时,我们定义了一个UserDetailsService类型的Bean,这里定义的是UserDetailsManager类型的Bean,实际上UserDetailsManagerUserDetailsService的子类,并且有createUser等方法,后面演示创建用户需要用到,如果仅仅是登录认证,定义UserDetailsService类型的Bean是可以的
    • 这里默认创建user用户,可以用来登录,需要注意的是,创建用户时需要至少分配一个权限,否则无法登录,参考org.springframework.security.core.userdetails.jdbc.JdbcDaoImpl#loadUserByUsername
  6. 启动服务,启动成功后,默认创建的用户及对应的权限信息会保存在数据库表中

添加用户
  1. 创建UserDetailsController类,注入UserDetailsManager类型的对象,UserDetailsManager类型的对象就是上面定义的基于jdbc认证的Bean

    package xin.yangshuai.springsecurity03.controller;
    
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.security.core.userdetails.User;
    import org.springframework.security.core.userdetails.UserDetails;
    import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
    import org.springframework.security.crypto.password.DelegatingPasswordEncoder;
    import org.springframework.security.crypto.password.MessageDigestPasswordEncoder;
    import org.springframework.security.crypto.password.PasswordEncoder;
    import org.springframework.security.provisioning.UserDetailsManager;
    import org.springframework.web.bind.annotation.GetMapping;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.RestController;
    import xin.yangshuai.common01.entity.BaseResult;
    
    import java.util.HashMap;
    import java.util.Map;
    import java.util.Random;
    
    /**
     * UserDetailsController
     *
     * @author shuai
     * @date 2025/8/28
     */
    @RestController
    @RequestMapping("userDetails")
    public class UserDetailsController {
    
        @Autowired
        private UserDetailsManager userDetailsManager;
    
        @GetMapping("add")
        public BaseResult<Integer> add() {
    
            String encodingId = "bcrypt";
            Map<String, PasswordEncoder> encoders = new HashMap();
            encoders.put(encodingId, new BCryptPasswordEncoder());
            encoders.put("MD5", new MessageDigestPasswordEncoder("MD5"));
            // ...
    
            encodingId = "MD5";
            PasswordEncoder encoder = new DelegatingPasswordEncoder(encodingId, encoders);
    
            // 这里示例,添加用户
            int i = new Random().nextInt(100);
    
            UserDetails userDetails1 = User.builder().passwordEncoder(encoder::encode).username("test" + i).password("123456").authorities("USER_LIST").build();
            userDetailsManager.createUser(userDetails1);
    
            BaseResult<Integer> result = new BaseResult<>();
            result.setCode("200");
            result.setData(1);
            return result;
        }
    }
    
  2. 注入的UserDetailsManager类型的对象就是上面定义的基于jdbc认证的BeancreateUser方式是spring security已经实现的逻辑,执行后,即可添加用户及权限到数据库中

  3. spring security进行账号认证的时候,loadUserByUsername方法返回的UserDetails对象的密码是需要传入加密的,在基于jdbc的账号认证中,loadUserByUsername方法返回的UserDetails对象的密码是保持数据库原始密码不变的,所以在创建用户的时候直接对密码进行加密

Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐