云计算百科
云计算领域专业知识百科平台

Spring Boot音乐服务器项目-登录模块

登录模块->项目结构图

一、项目准备与数据库设计

1. 创建Spring Boot项目

  • 先创建一个Maven项目:

  • 项目结构图如上

2. 数据库设计

— 创建数据库
CREATE DATABASE IF NOT EXISTS musicserver CHARACTER SET utf8;

USE musicserver;

— 用户表
CREATE TABLE user (
id INT PRIMARY KEY AUTO_INCREMENT,
username VARCHAR(20) NOT NULL,
password VARCHAR(255) NOT NULL
);

— 音乐表
CREATE TABLE music (
id INT PRIMARY KEY AUTO_INCREMENT,
title VARCHAR(50) NOT NULL,
singer VARCHAR(30) NOT NULL,
time VARCHAR(13) NOT NULL,
url VARCHAR(1000) NOT NULL,
userid INT(11) NOT NULL
);

— 收藏表
CREATE TABLE lovemusic (
id INT PRIMARY KEY AUTO_INCREMENT,
user_id INT(11) NOT NULL,
music_id INT(11) NOT NULL
);

二、项目配置

整体项目的pom依赖

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.6.6</version>
<relativePath/> <!– lookup parent from repository –>
</parent>
<groupId>com.example</groupId>
<artifactId>musicplayer</artifactId>(自己项目名称)
<version>0.0.1-SNAPSHOT</version>
<name>musicplayer</name>(自己项目名称)
<description>Demo project for Spring Boot</description>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>

<!– mybatis 依赖 –>
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>2.2.2</version>
</dependency>

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
<optional>true</optional>
</dependency>

<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>

<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>

<!– md5 依赖 –>
<dependency>
<groupId>commons-codec</groupId>
<artifactId>commons-codec</artifactId>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.9</version>
</dependency>

<!– security依赖包 (加密)–>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-web</artifactId>
</dependency>

<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-config</artifactId>
</dependency>

</dependencies>

<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<excludes>
<exclude>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</exclude>
</excludes>
</configuration>
</plugin>
</plugins>
</build>

</project>

application.properties配置(resources包下)

# 数据库配置
spring.datasource.url=jdbc:mysql://localhost:3306/musicserver?characterEncoding=utf8&serverTimezone=UTC
spring.datasource.username=root(自己数据库)
spring.datasource.password=123456(自己数据库)
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver

# MyBatis配置
mybatis.mapper-locations=classpath:mybatis/**Mapper.xml

# 文件上传大小限制
spring.servlet.multipart.max-file-size=15MB
spring.servlet.multipart.max-request-size=100MB

# 日志配置
logging.level.com.example.musicserver.mapper=debug

三、登录模块实现

1. 用户实体类(model->User)

@Data
public class User {
private int id;
private String username;
private String password;
}

2. Mapper接口与XML

// UserMapper.java
@Mapper
public interface UserMapper {
User selectByName(String username);
}
<!– UserMapper.xml –>
<select id="selectByName" resultType="com.example.musicserver.model.User">
SELECT * FROM user WHERE username=#{username}
</select>

3. 统一响应信息工具类(tools->ResponseBodyMessage)

@Data
public class ResponseBodyMessage<T> {
private int status;
private String message;
private T data;

public ResponseBodyMessage(int status, String message, T data) {
this.status = status;
this.message = message;
this.data = data;
}
}

4. 登录控制器(Controller层)

@RestController
@RequestMapping("/user")
public class UserController {
@Autowired
private UserMapper userMapper;

@Autowired
private BCryptPasswordEncoder bCryptPasswordEncoder;

@PostMapping("/login")
public ResponseBodyMessage<User> login(
@RequestParam String username,
@RequestParam String password,
HttpServletRequest request) {

User userInfo = userMapper.selectByName(username);

if (userInfo == null || !bCryptPasswordEncoder.matches(password, userInfo.getPassword())) {
return new ResponseBodyMessage<>(-1, "用户名或密码错误", null);
}

request.getSession().setAttribute(Constant.USERINFO_SESSION_KEY, userInfo);
return new ResponseBodyMessage<>(0, "登录成功", userInfo);
}
}

注解介绍:

@RestController:@ResponseBody+ @Controller合在⼀起的作⽤。@Controller注解,表明了这 个类是⼀个控制器类 ,@ResponseBody表⽰⽅法的返回值直接以指定的格式写⼊Http response  body中 。 

@RequestMapping:使⽤ @RequestMapping来映射请求,也就是通过它来指定控制器可以处理哪 些URL请求 

@RequestParam:将请求参数绑定到你控制器的⽅法参数上 。

如果这个参数是⾮必传的可以写为: @RequestParam(required = false) ,默认是true.  

5. 常量类(tools->Constant)

public class Constant {
public static final String USERINFO_SESSION_KEY = "USERINFO_SESSION_KEY";
}

6. BCrypt加密配置

  • BCrypt加密: 一种加盐的单向Hash,不可逆的加密算法,同一种明文(plaintext),每次加密后的密文都不一样,而且不可反向破解生成明文,破解难度很大。

  • MD5加密: 是不加盐的单向Hash,不可逆的加密算法,同一个密码经过hash的时候生成的是同一个hash值,在大多数的情况下,有些经过md5加密的方法将会被破解。

相关依赖我们在一开始的项目配置就已经加上了,主要就是这几个

<dependency>
<groupId>commons-codec</groupId>
<artifactId>commons-codec</artifactId>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.9</version>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-config</artifactId>
</dependency>

接下来就创建⼀个tools包,新建MD5Util类 

package com.example.musicplayer.tools;

import org.apache.commons.codec.digest.DigestUtils;

/**
@Author hy
@Description:
*/
public class MD5Util {
private static final String salt = "1b2i3t4e";

public static String md5(String src){
return DigestUtils.md5Hex(src);
}

/**
* 第⼀次加密 :模拟前端⾃⼰加密,然后传到后端
* @param inputPass
* @return
*/
public static String inputPassToFormPass(String inputPass){
String str = ""+salt.charAt(1) + salt.charAt(3) + inputPass + salt.charAt(5) + salt.charAt(6);
return md5(str);
}
/**
* 第2次MD5加密
* @param formPass 前端加密过的密码,传给后端进⾏第2次加密
* @param salt ⽤⼾数据库当中的盐值
* @return
*/
public static String formPassToDBPass(String formPass,String salt){
String str = ""+salt.charAt(0)+salt.charAt(2) + formPass
+salt.charAt(5)
+ salt.charAt(4);
return md5(str);
}
/**
* 上⾯两个函数合到⼀起进⾏调⽤

* @param inputPass
* @param saltDB
* @return

*/

public static String inputPassToDbPass(String inputPass, String saltDB) {
String formPass = inputPassToFormPass(inputPass);
String dbPass = formPassToDBPass(formPass, saltDB);
return dbPass;
}
public static void main(String[] args) {
System.out.println("对⽤⼾输⼊密码进⾏第1次加密:"+inputPassToFormPass("123456"));
System.out.println("对⽤⼾输⼊密码进⾏第2次加密:"+formPassToDBPass(inputPassToFormPass("123456"),
"1b2i3t4e"));
System.out.println("对⽤⼾输⼊密码进⾏第2次加密:"+inputPassToDbPass("123456", "1b2i3t4e"));
}
}

创建⼀个tools包,新建BCryptTest类 

package com.example.musicplayer.tools;

import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;

/**
* @Author 12629
* @Date 2022/4/11 14:29
* @Description:
*/
public class BCryptTest {

public static void main(String[] args) {
//模拟从前端获得的密码
String password = "123456";
BCryptPasswordEncoder bCryptPasswordEncoder = new BCryptPasswordEncoder();

String newPassword = bCryptPasswordEncoder.encode(password);

System.out.println("加密的密码为: "+newPassword);

//使用matches方法进行密码的校验
boolean same_password_result = bCryptPasswordEncoder.matches(password,newPassword);
//返回true
System.out.println("加密的密码和正确密码对比结果: "+same_password_result);

boolean other_password_result = bCryptPasswordEncoder.matches("987654",newPassword);
//返回false
System.out.println("加密的密码和错误的密码对比结果: " + other_password_result);

}
}

基于此我们来实现加密登录!

UserMapper新增逻辑

@Mapper

public interface UserMapper {
User login(User loginUser);
//username⽤⼾名是唯⼀的
User selectByName(String username);
}

 UserMapper.xml配置

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"

"http://mybatis.org/dtd/mybatis-3-mapper.dtd">

<mapper namespace="com.example.musicserver.mapper.UserMapper">
<select id="login" resultType="com.example.musicserver.model.User">
select * from user where username=#{username} and password=#{password}
</select>
<select id="selectByName" resultType="com.example.musicserver.model.User">
select * from user where username=#{username}
</select>
</mapper>

修改UserController类

@RestController//@ResponseBody + @Controller合在⼀起的作⽤

@RequestMapping("/user")//使⽤ @RequestMapping 来映射请求,也就是通过它来指定控制器可
以处理哪些URL请求

public class UserController {
@Autowired

private UserMapper userMapper;
@Autowired//在⾃动装配之前,需要完成注⼊,我们再AppConfig中进⾏注⼊
private BCryptPasswordEncoder bCryptPasswordEncoder;
@RequestMapping("/login")

public ResponseBodyMessage<User> login(@RequestParam String username,

@RequestParam String password, HttpServletRequest request) {
User loginUser = new User();
loginUser.setUsername(username);
loginUser.setPassword(password);
System.out.println(loginUser);
User userInfo = userMapper.selectByName(username);
if(userInfo == null) {
return new ResponseBodyMessage<>(-1,"⽤⼾名或者密码错误",userInfo);
}else {

if(!bCryptPasswordEncoder.matches(password,userInfo.getPassword())) {
return new ResponseBodyMessage<>(-1,"⽤⼾名或者密码错
误",userInfo);
}

request.getSession().setAttribute(Constant.USERINFO_SESSION_KEY,userInfo);
return new ResponseBodyMessage<>(0,"登录成功",userInfo);
}
}
}

@Autowired:可以更准确地控制应该在何处以及如何进⾏⾃动装配。

此注解⽤于在setter⽅法,构造 函数,具有任意名称或多个参数的属性或⽅法上⾃动装配bean。默认情况下,它是类型驱动的注⼊ 

上面我们提到了在⾃动装配之前,需要完成注⼊,我们再AppConfig中进⾏注⼊

故创建包config,新建AppConfig类

@Configuration
public class AppConfig {
@Bean
public BCryptPasswordEncoder getBCryptPasswordEncoder() {
return new BCryptPasswordEncoder();
}
}

7. 启动类配置

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

四、密码加密原理

BCrypt vs MD5对比:

特性BCryptMD5
安全性 高(每次加密结果不同) 中(彩虹表可破解)
密文长度 60位 32位
盐值处理 自动生成随机盐 需手动加盐
破解难度 极高 中等
适用场景 高安全需求(如金融) 一般安全需求

五、功能测试

登录测试:

  • 使用Postman发送POST请求

  • URL:http://localhost:8080/user/login

  • 参数:username=bit&password=123456

  • 成功响应:

  • {
    "status": 0,
    "message": "登录成功",
    "data": {
    "id": ,
    "username": "",
    "password": ""
    }
    }

    这是我自己成功的数据

    这是错误的数据,因为数据库就没有这组

    所有内容在:Jared/音乐服务器 – 码云

    赞(0)
    未经允许不得转载:网硕互联帮助中心 » Spring Boot音乐服务器项目-登录模块
    分享到: 更多 (0)

    评论 抢沙发

    评论前必须登录!