SpringBoot项目——配置Mysql与session注册登录验证实现

SpringBoot项目——配置Mysql与session注册登录验证实现

回顾:
SpringBoot项目——创建菜单与游戏页面
SpringBoot项目——配置git环境与项目创建


1. 配置 MySQL,创建所需数据库

mysql基本命令

  • 启动:net start mysql80

  • 关闭:net stop mysql80

  • 连接:mysql -uroot -p 链接用户名为root,密码为123456的数据库服务;

  • 退出:exit

  • 列出所有数据库:show databases;

  • 创建数据库:create database kob;

  • 删除数据库:drop database kob;

    扫描二维码关注公众号,回复: 17096508 查看本文章
  • 使用数据库kob:use kob;

  • 列出当前数据库的所有表:show tables;

  • 创建名称为user的表,表中包含id和username两个属性:create table user(id int, username varchar(100))

  • 删除表:drop table user;

  • 在表中插入数据:insert into user values(1, ' ');

  • 查询表中数据:select * from user where id=2;

  • 删除某行数据:delete from user where id = 2;


2. 配置 SpringBoot 操控 MySQL

2.1 安装依赖
  • Maven仓库地址

  • Mybatis-Plus官网

  • 在pom.xml文件中添加依赖:

    • Spring Boot Starter JDBC ——用数据库
    • Project Lombok —— 自动写好通用方法,包括set、get、toString、equal、hashCode方法
    • MySQL Connector/J
    • mybatis-plus-boot-starter —— MyBatis Plus 写好mapper层sql语句
    • mybatis-plus-generator

    • spring-boot-starter-security —— 实现登录授权机制

    • jjwt-api

    • jjwt-impl

    • jjwt-jackson

  • 在application.properties中添加数据库配置:

    spring.datasource.username=root
    spring.datasource.password=123456
    spring.datasource.url=jdbc:mysql://localhost:3306/kob?serverTimezone=Asia/Shanghai&useUnicode=true&characterEncoding=utf-8
    spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
    
2.2 SpringBoot 框架基本结构
  • pojo层:将数据库中的表对应成Java中的Class

  • mapper层(Dao层):数据访问层,将pojo层的class中的操作,映射成sql语句

  • service层:业务逻辑层,写具体的业务逻辑,组合使用mapper中的操作

  • controller层:调度service,负责请求转发,接受页面过来的参数,传给Service处理,接到返回值,再传给页面

  • 类似 SpringMVC、三层架构。
    在这里插入图片描述

2.3 SpringBoot 代码介绍

在这里插入图片描述

SpringBoot入口: 启动SpringBoot应用,SpringApplication.run

package com.kob.backend;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class BackendApplication {
    
    
    public static void main(String[] args) {
    
    
        SpringApplication.run(BackendApplication.class, args);
    }
}

pojo层: com.kob.backend.pojo.User.class

package com.kob.backend.pojo;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

// 加入依赖的注解后可帮助写Set、Get、toString等方法。
@Data
@NoArgsConstructor
@AllArgsConstructor
public class User {
    
    
    private Integer id;
    private String username;
    private String password;
}

在这里插入图片描述

mapper层: com.kob.backend.mapper.UserMapper.class

package com.kob.backend.mapper;

import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.kob.backend.pojo.User;
import org.apache.ibatis.annotations.Mapper;

@Mapper
// mybatisplus 帮助写sql语句
public interface UserMapper extends BaseMapper<User> {
    
    

}

service层:

// 目前业务逻辑较简单,直接写在了Controller层

controller层: package com.kob.backend.controller.user.UserController.class

package com.kob.backend.controller.user;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.kob.backend.mapper.UserMapper;
import com.kob.backend.pojo.User;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;

import java.util.List;

@RestController
public class UserController {
    
    
    @Autowired // 如果要用到数据库接口的mapper的话,需要加此注解
    UserMapper userMapper;

    // @RequestMapping会将所有请求映射,也可指明类型。
    // @GetMapping映射Get类型请求。@PostMapping会映射Post类型请求

    // 查询所有
    @GetMapping("/user/all/")
    public List<User> getAll() {
    
    
        return userMapper.selectList(null); //null表示查询所有的
    }

    // 按id查找
    @GetMapping("/user/{userId}/")
    public List<User> getUser(@PathVariable int userId){
    
     //@PathVariable 映射 URL 绑定的占位符
        // 按id查找
        QueryWrapper<User> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("id",2);
        return userMapper.selectList(queryWrapper);
        // 上面三行等价与直接return userMapper.selectById(userId);
    }

    // 插入
    @GetMapping("/user/add/{userId}/{username}/{password}/")
    public String addUser(@PathVariable int userId,
                          @PathVariable String username,
                          @PathVariable String password){
    
    
        User user = new User(userId, username, password);
        userMapper.insert(user);
        return "Add User Successfully!";
    }

    // 按id删除
    @GetMapping("/user/delete/{userId}")
    public String deleteUser(@PathVariable int userId){
    
    
        userMapper.deleteById(userId);
        return "Delete User Successfully!";
    }
}
2.4 SpringBoot 主要注解介绍
  • @RestController注解

    • @RestController = @Controller + @ResponseBody。将java对象转为json格式的数据,后端通过api将json数据传到前端

    • 代表返回的是json格式的数据,这个注解是Spring4之后新加的注解,原来返回json格式的数据需要@ResponseBody配合@Controller一起使用;

    • 如果我们在项目中使用的是@Conrtroller注解的话,不加@Response注解,则当直接返回一个字符串的时候,就好比返回的是一个模板页面,类似我们返回一个jsp页面一样。所以我们需要加上模板引擎。(这种返回html一类的模板的开发方式现在一般不会再用了,因为现在都是前后端分离式的开发,后台服务器一般只需要返回json格式的数据即可,所以了解即可

  • @Autowired 如果要用到数据库接口的mapper的话,需要加此注解

  • @RequestMapping 会将所有请求映射,也可指明类型。

    • @GetMapping映射Get类型请求。
    • @PostMapping映射Post类型请求
  • @PathVariable 映射 URL 绑定的占位符


3. 修改Spring Security,实现 session 登录授权机制

  • 装依赖 spring-boot-starter-security

在这里插入图片描述

验证过程: 登录时用户端输入用户名密码,后端查找数据库,若存在且密码一致则返回给用户端sessionID。sessionID存在本地cookie里,登录成功后,每次访问后端数据库都会自动将sessionID传递进去验证,一段时间内有效,过期需要再次登陆验证。数据库通过sessionId对应信息。

3.1 密码明文验证

在这里插入图片描述

  • 编写service.impl.UserDetailsServiceImpl类,继承自UserDetailsService接口,用来接入数据库信息。所写loadUserByUsername方法,按用户名查找。
    UserDetailsService 接口用来接入数据库信息,从数据库中获取信息。

  • 如果想让security对接自己写的数据库,需要把username在数据库中对应的的用户找出来,返回他的密码(这里的数据库存储中指明明文{noop}),需要用到数据库操作mapper,能写private就写private,用数据库记得加上autowired.

    package com.kob.backend.service.impl;
    
    import ...;
    
    // 实现service.impl.UserDetailsServiceImpl类,继承自UserDetailsService接口
    // UserDetailsService 用来接入数据库信息,从数据库中获取信息。
    // 调用loadUserByUsername,按用户名查找。
    @Service
    public class UserDetailsServiceImpl implements UserDetailsService {
          
          
    
        @Autowired
        private UserMapper userMapper;
        @Override
        // 传入用户名,返回用户名和密码(要求数据库中用户名唯一)
        public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
          
          
            QueryWrapper<User> queryWrapper = new QueryWrapper<>();
            queryWrapper.eq("username",username);
            User user = userMapper.selectOne(queryWrapper);
            if(user == null){
          
          
                throw new RuntimeException("用户不存在");
            }
            return new UserDetailsImpl(user);
        }
    }
    

    UserDetails介绍: 这个接口代表了最详细的用户信息,这个接口涵盖了一些必要的用户信息字段,具体的实现类对它进行了扩展。 它和Authentication接口很类似,比如它们都拥有username,authorities。
    Authentication的getCredentials()与UserDetails中的getPassword()需要被区分对待,前者是用户提交的密码凭证,后者是用户正确的密码,认证器其实就是对这两者的比对。Authentication中的getAuthorities()实际是由UserDetails的getAuthorities()传递而形成的。Authentication接口中的getUserDetails()方法吗,其中的UserDetails用户详细信息便是经过了AuthenticationProvider之后被填充的

    package com.kob.backend.service.impl.utils;
    
    import ...
    @Data
    @NoArgsConstructor
    @AllArgsConstructor
    public class UserDetailsImpl implements UserDetails {
          
          
    
        private User user;
    
        @Override
        public Collection<? extends GrantedAuthority> getAuthorities() {
          
          
            return null;
        }
    
        @Override
        public String getPassword() {
          
          
            return user.getPassword(); // 返回User中user的password
        }
    
        @Override
        public String getUsername() {
          
          
            return user.getUsername(); // 返回User中user的name
        }
    
        // 是否没被锁定
        @Override
        public boolean isAccountNonExpired() {
          
          
            return true;
        }
    
        // 是否没被锁定
        @Override
        public boolean isAccountNonLocked() {
          
          
            return true;
        }
    
        // 授权是否过期
        @Override
        public boolean isCredentialsNonExpired() {
          
          
            return true;
        }
    
        // 用户是否被启用
        @Override
        public boolean isEnabled() {
          
          
            return true;
        }
    }
    
3.2 密码是密文(经过加密算法加密)时如何实现?

若数据库中所存密码是P1,加密后是SP1。每次将输入的密码P2,加密成SP2,看与SP是否匹配来验证登录。即无序知道具体内容,只需知道是否匹配即可。
测试如下:在这里插入图片描述

  • 实现config.SecurityConfig类,用来实现用户密码的加密存储,此时数据库中需要存密文,而非明文。
    在这里插入图片描述

    package com.kob.backend.config;
    
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
    import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
    import org.springframework.security.crypto.password.PasswordEncoder;
    
    @Configuration
    @EnableWebSecurity
    public class SecurityConfig {
          
          
        @Bean
        public PasswordEncoder passwordEncoder() {
          
          
        	// 返回所用加密方法(包括明文转密文,明文跟密文是否匹配)
            return new BCryptPasswordEncoder();
        }
    }
    
  • 注册插入用户信息时,便可以实现密码存储为密文
    修改UserController中插入用户函数:

    // 插入
    @GetMapping("/user/add/{userId}/{username}/{password}/")
    public String addUser(@PathVariable int userId,
                          @PathVariable String username,
                          @PathVariable String password){
          
          
        PasswordEncoder passwordEncoder = new BCryptPasswordEncoder();//指明编码方式
        String encodePassword = passwordEncoder.encode(password);
        User user = new User(userId, username, encodePassword);
        userMapper.insert(user);
        return "Add User Successfully!";
    }
    

    结果如下:
    在这里插入图片描述
    在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/qq_46201146/article/details/126129909