SpringSecurity数据库用户认证

1. 数据准备

create table sys_user(    
	id int primary key auto_increment,    
	user_name varchar(32) not null unique comment '用户名',    
	password varchar(128) comment '密码',    
	nick_name varchar(32) comment '昵称',    
	gender enum('男','女') comment '性别',    
	avatar varchar(128) comment '头像',    
	email varchar(128) comment '邮箱',    
	phone varchar(16) comment '手机号',    
	status tinyint comment '状态',    
	deleted tinyint comment '删除状态',    
	remark varchar(1024) comment '备注',    
	create_time datetime default now() comment '创建时间',    
	update_time datetime default null comment '更新时间'
);

2.项目创建

添加依赖

3 实体类的开发

package com.kclm.springsecuritydemo03.entiy;

import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;

import java.io.Serializable;
import java.time.LocalDateTime;
import java.util.Collection;

/**
 * @Classname SysUser
 * @Description TODO
 * @Date 2024/10/15 11:12
 * @Created by HP
 */
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
@Slf4j
public class SysUser  implements Serializable, UserDetails {
   private Integer id;//id
   private String userName; //用户名
    private String password;//密码
    private String nickName;//昵称
    private String gender ;//性别
    private String  avatar ;//头像
    private String  email;//邮箱
    private  String  phone ;//手机号
    private  Integer status ;//状态  0禁用  1:启用
    private  Integer  deleted ;//删除状态, 0 未删除  1删除
    private String   remark ;// 备注
    private LocalDateTime create_time;//创建时间
    private LocalDateTime  update_time ;//更新时间

    @Override
    public Collection<? extends GrantedAuthority> getAuthorities() {
        return null;
    }

    @Override
    public String getUsername() {
        return this.userName;
    }
    @Override
    public String getPassword() {
        return this.password;
    }

    @Override
    public boolean isAccountNonExpired() {
        return status==1;
    }

    @Override
    public boolean isAccountNonLocked() {
        return status==1;
    }

    @Override
    public boolean isCredentialsNonExpired() {
        return status==1;
    }

    @Override
    public boolean isEnabled() {
        return status==1;
    }
}

4.Mapper接口的开发

@Mapper
public interface SysUserMapper {
    SysUser findByUserName(String userName);
    void save(SysUser sysUser);
}

5.开发SysUserMapper.xml

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "https://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.kclm.springsecuritydemo03.mapper.SysUserMapper">
      <select id="findByUserName" resultType="SysUser">
      select
          id,user_name,password,nick_name,gender,avatar,email,phone,status,deleted,remark,create_time,update_time
        from  sys_user
        where user_name=#{userName}
    </select>
    <insert id="save">
        insert into
            sys_user(user_name,password,nick_name,gender,avatar,email,phone,status,deleted,remark,create_time,update_time)
        values(#{username},#{password},#{nickName},#{gender},#{avatar},#{email},#{phone},#{status},#{deleted},#{remark},#{createTime},#{updateTime})
    </insert>
</mapper>

6.配置文件application.yaml

server:
  port: 9091
spring:
  profiles:
    active: dev
mybatis:
  type-aliases-package: com.kclm.springsecuritydemo03.entiy
  configuration:
    map-underscore-to-camel-case: true
  mapper-locations: classpath:mybatis/mappers/*.xml

 application.yaml

spring:
  datasource:
    driver-class-name: com.mysql.cj.jdbc.Driver
    url: jdbc:mysql://localhost:3306/db2?useUnicode=true&characterEncoding=urt8&serverTimezone=GMT%2B8
    username: root
    password: 123456

以上接口的测试代码

@Test
	public  void save(){
		SysUser sysUser = SysUser.builder()
				.userName("admin")
				.password("123456")
				.nickName("admin用户")
				.gender("男")
				.avatar("/static/admin.png")
				.email("admin123456@16.com")
				.phone("136123466578")
				.status(1)
				.deleted(0)
				.remark("备注admin用户")
				.createTime(LocalDateTime.of(2023, 10, 1, 10, 12, 10))
				.updateTime(LocalDateTime.of(2024, 3, 1, 13, 12, 10)).build();
		sysUserMapper.save(sysUser);
	}

	@Test
	public  void testFindByName(){
		SysUser admin = sysUserMapper.findByUserName("admin");
		System.out.println(admin);
	}

8 开发SysUserDetailsService

@Service
@Slf4j
public class SysUserDetailsService  implements UserDetailsService {
    private SysUserMapper sysUserMapper;
    //采用构造方法的注入方式
    public SysUserDetailsService(SysUserMapper sysUserMapper) {
        this.sysUserMapper = sysUserMapper;
    }
    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        log.info("====》调用loadUserByUserName:{}",username);
        SysUser sysUser = sysUserMapper.findByUserName(username);
        return sysUser ;
    }
}

9 springSecurity.java配置类

@Configuration
@EnableWebSecurity
@Slf4j
public class SecurityConfig {
    private SysUserDetailsService sysUserDetailsService;

    public SecurityConfig(SysUserDetailsService sysUserDetailsService) {
        log.info("====>通过构造器注入 sysUserDetailsService");
        this.sysUserDetailsService = sysUserDetailsService;
    }
    @Bean
    public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
        //关闭csrf机制
        http.csrf(csrf-> csrf.disable());
        http.authorizeHttpRequests(auth->auth.anyRequest().authenticated());
        //走security 内部的登录页面
        http.formLogin(Customizer.withDefaults());
        return  http.build();
    }
    @Bean
    public PasswordEncoder passwordEncoder(){
             //构建编码器
        return  new BCryptPasswordEncoder();
    }
}

开发一个接口测试做测试

@RestController
public class HomeController {
    @RequestMapping("home")
    public String  home(){
        return  "welcome home!!!";
    }
}

访问localhost:9091/home 浏览器会自动重定向到登录页面

输入用户名和密码 【和数据中用户名和密码保持一致】

以上是基于springSecurity内置表单认证的

认证流程

1 .当用户提用户名和密码的时候,UsernamePasswordAuthenticationFilter创建一个UsernamePasswordAuthenticationToken,这是一种通过从HttpServletRequest提取用户名和密码的身份验证类型。

2.将UsernamePasswordAuthenticationToken传递到要进行身份验证的AuthenticationManager。

3 .AuthenticationManager对象 默认是ProvideManager 调用AuthenticationManager.authenticate() 此方法的参数就是UsernamePasswordAuthenticationToken(未认证) 返回值也是一个Authentication(已经认证过的对象--未出现异常情况)

基于非默认表单验证

1 创建SysUserDto 对象接受前端传递过来数据

@Data
public class SysUserDto {
    private String username;
    private String  password;
}

2 登录控制器LoginConrtoller.java

@RestController
@Slf4j
@RequestMapping("user")
public class LoginController {
    //引入业务类
    private ISysUserService sysUserService;

    public LoginController(ISysUserService sysUserService) {
        this.sysUserService = sysUserService;
    }
    //用户登录
    @PostMapping("/login")
    public  String   login(@RequestBody  SysUserDto sysUserDto){
         String token = sysUserService.login(sysUserDto);
        return token;
    }
}

3 业务接口和实现类的开发

public interface ISysUserService {
    String  login(SysUserDto sysUserDto);
}

@Service
@Slf4j
public class SysUserServiceImpl  implements ISysUserService {
    private AuthenticationManager authenticationManager;
    //通过构造器注入的方式
    public SysUserServiceImpl(AuthenticationManager authenticationManager) {
        this.authenticationManager = authenticationManager;
    }

    /**
     * 用户登录的方法中实现自定义认证流程
     */
    @Override
    public String login(SysUserDto sysUserDto) {
        //实现认证流程
        //1 创建 UsernamePasswordAuthenticationToken对象
        UsernamePasswordAuthenticationToken  authenticationToken =
                new UsernamePasswordAuthenticationToken(sysUserDto.getUsername(),sysUserDto.getPassword());
       //2 调用 authenticationManager.authenticate()方法完成认证
        Authentication authenticate =null;
         try {
             authenticate =   authenticationManager.authenticate(authenticationToken);
         }catch (AuthenticationException e){
             return  "用户名或密码错误";
         }
        //3 获取返回的用户
        SysUser sysUser  = (SysUser) authenticate.getPrincipal();
        // 通过认证  这里返回一个字符串     后期使用jwt 生成token
        String  token  = UUID.randomUUID().toString().replace("-","");
        log.info("登录后的用户====>{}",sysUser);
        return token;
    }
}

4 SecurityConfig.java类

@Configuration
@EnableWebSecurity
@Slf4j
public class SecurityConfig {
    private SysUserDetailsService sysUserDetailsService;

    public SecurityConfig(SysUserDetailsService sysUserDetailsService) {
        log.info("====>通过构造器注入 sysUserDetailsService");
        this.sysUserDetailsService = sysUserDetailsService;
    }
    @Bean
    public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
        //关闭csrf机制
        http.csrf(csrf-> csrf.disable());
        http.authorizeHttpRequests(auth->
                auth.requestMatchers("/user/**").permitAll()
                        .anyRequest().authenticated());
        //走security 内部的登录页面
//        http.formLogin(Customizer.withDefaults());
        return  http.build();
    }

    @Bean
    public AuthenticationManager authenticationManager(PasswordEncoder passwordEncoder){
        log.info("======>创建AuthenticationManager实例:注入passwordEncoder");
        DaoAuthenticationProvider  authenticationProvider = new DaoAuthenticationProvider();
        authenticationProvider.setPasswordEncoder(passwordEncoder);
        //设置UserDetailsService
        authenticationProvider.setUserDetailsService(sysUserDetailsService);
        return  new ProviderManager(authenticationProvider);
    }

    @Bean
    public PasswordEncoder passwordEncoder(){
             //构建编码器
        return  new BCryptPasswordEncoder();
    }
}

使用postMan或者apiPost做测试

  输入正确的用户名和密码:

 输入错误的用户名和密码:

  

原理图如下 

官方原文 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值