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 {@Autowiredprivate UserMapper userMapper;@Autowiredprivate 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);//返回trueSystem.out.println("加密的密码和正确密码对比结果: "+same_password_result);boolean other_password_result = bCryptPasswordEncoder.matches("987654",newPassword);//返回falseSystem.out.println("加密的密码和错误的密码对比结果: " + other_password_result);}
}
基于此我们来实现加密登录!
UserMapper新增逻辑
@Mapperpublic 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 {@Autowiredprivate 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 {@Beanpublic 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对比:
特性 | BCrypt | MD5 |
---|---|---|
安全性 | 高(每次加密结果不同) | 中(彩虹表可破解) |
密文长度 | 60位 | 32位 |
盐值处理 | 自动生成随机盐 | 需手动加盐 |
破解难度 | 极高 | 中等 |
适用场景 | 高安全需求(如金融) | 一般安全需求 |
五、功能测试
登录测试:
-
使用Postman发送POST请求
-
URL:
http://localhost:8080/user/login
-
参数:
username=bit&password=123456
-
成功响应:
{"status": 0,"message": "登录成功","data": {"id": ,"username": "","password": ""} }
这是我自己成功的数据
这是错误的数据,因为数据库就没有这组
所有内容在:Jared/音乐服务器 - 码云