1. 准备工作
1.1 项目创建

修改当前的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.7.17</version>
- <relativePath/> <!-- lookup parent from repository -->
- </parent>
- <groupId>com.example</groupId>
- <artifactId>musicServer</artifactId>
- <version>0.0.1-SNAPSHOT</version>
- <name>musicServer</name>
- <description>musicServer</description>
- <url/>
- <licenses>
- <license/>
- </licenses>
- <developers>
- <developer/>
- </developers>
- <scm>
- <connection/>
- <developerConnection/>
- <tag/>
- <url/>
- </scm>
- <properties>
- <java.version>8</java.version>
- </properties>
- <dependencies>
- <dependency>
- <groupId>org.springframework.boot</groupId>
- <artifactId>spring-boot-starter-web</artifactId>
- </dependency>
- <dependency>
- <groupId>org.springframework.boot</groupId>
- <artifactId>spring-boot-devtools</artifactId>
- <scope>runtime</scope>
- <optional>true</optional>
- </dependency>
- <dependency>
- <groupId>com.mysql</groupId>
- <artifactId>mysql-connector-j</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>
- <dependency>
- <groupId>org.mybatis.spring.boot</groupId>
- <artifactId>mybatis-spring-boot-starter</artifactId>
- <version>2.3.1</version>
- </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>
复制代码 1.2 数据库设计
1.2.1 user表
(id,username,password)
1.2.2 music表
(id,title,singer歌手,time上传时间,url音乐存储位置,未来需要播放的时间需要请求的地点,userid这首歌是是谁人用户上传的)
1.2.3 lovemusic表
(id,userid,music_id)绑定关系的表,即某用户喜欢某音乐的关系;
三个表设计如下代码所示:
- drop database if exists spring_musicserver;
- create database if not exists spring_musicserver character set utf8;
- use spring_musicserver;
- drop table if exists user;
- create table user (
- id int primary key auto_increment,
- username varchar(20) not null,
- password varchar(255) not null
- );
- drop table if exists music;
- 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
- );
- drop table if exists lovemusic;
- create table lovemusic(
- id int primary key auto_increment,
- user_id int(11) not null,
- music_id int(11) not null
- );
复制代码 1.3 举行properties配置
- server.port=8089
- #配置数据库
- spring.datasource.url=jdbc:mysql://127.0.0.1:3306/spring_musicserver?useUnicode=true&characterEncoding=UTF-8&userSSL=false&serverTimezone=GMT%2B8
- spring.datasource.username=root
- spring.datasource.password=111111
- spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
- #配置xml
- mybatis.mapper-locations=classpath:mybatis/**Mapper.xml
- #配置springboot上传⽂件的⼤⼩,默认每个⽂件的配置最⼤为15Mb,单次请求的⽂件的总数不能⼤于100Mb
- spring.servlet.multipart.max-file-size = 15MB
- spring.servlet.multipart.max-request-size=100MB
- #配置spring日志调试模式是否开启
- debug=true
- #⽇志级别:trace,debug,info,warn,error
- #基本⽇志
- logging.level.root=INFO
- logging.level.com.example.musicserver.mapper=debug
- #扫描的包:druid.sql.Statement类和frank包
- logging.level.druid.sql.Statement=DEBUG
- logging.level.com.example=DEBUG
复制代码 2. 登录模块设计
2.1创建User类
创建model包,将实体类都存放到该包内里;
- package com.example.spring_musicserver.model;
- import lombok.Data;
- /**
- * @version 1.0
- * @Author 上嘉路
- * @Date 2024/11/13 11:21
- * @注释
- */
- @Data
- public class User {
- private int id;
- private String username;
- private String password;
- }
复制代码 2.2创建接⼝UserMapper
新建mapper包,新建UserMapper
- @Mapper
- public interface UserMapper {
- User login(User loginUser);
- }
复制代码 2.3 创建UserMapper.xml
在resource⽬录下,新建mybatis⽂件夹,新建UserMapper.xml,下面代码是.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.spring_musicserver_1113.mapper.UserMapper">
- <select id="login" resultType="com.example.spring_musicserver_1113.model.User">
- select * from user where username=#{username} and password=#{password}
- </select>
- </mapper>
复制代码 3. 实现登录
3.1 登录的请求和响应设计
响应体设计字段表明:
1、状态码,为0代表乐成,负数代表失败
2、状态形貌信息,形貌此次请求乐成或者失败的缘故原由
3、返回的user范例的数据,请求乐成后,需要给前端的数据信息
对于数据库中的user表中数据添加乐成;
3.2 创建UserController类
在controller包下,创建UserController类
- package com.example.spring_musicserver_1113.controller;
- /**
- * @version 1.0
- * @Author 作者名
- * @Date 2024/11/13 14:48
- * @注释
- */
- import com.example.spring_musicserver_1113.mapper.UserMapper;
- import com.example.spring_musicserver_1113.model.User;
- import org.springframework.beans.factory.annotation.Autowired;
- import org.springframework.stereotype.Controller;
- import org.springframework.web.bind.annotation.RequestMapping;
- import org.springframework.web.bind.annotation.RequestParam;
- import org.springframework.web.bind.annotation.RestController;
- import javax.servlet.http.HttpServletRequest;
- @RestController
- @RequestMapping("/user")
- public class UserController {
- @Autowired
- private UserMapper userMapper;
- @RequestMapping("/login")
- public void login(@RequestParam String username,
- @RequestParam String password) {
- User loginUser = new User();
- loginUser.setUsername(username);
- loginUser.setPassword(password);
- User user = userMapper.login(loginUser);
- if (user != null) {
- System.out.println("登录成功");
- } else {
- System.out.println("登录失败");
- }
- }
- }
复制代码 向数据库中插入数据举行postman验证接口的精确性设计性:



由此可知当前的代码畅通无阻;
3.3 设计同一的的响应体类工具类
将服务器向客户端给出的响应举行封装;
新建tools工具包,新建ResponseBodyMessage类;
- package com.example.spring_musicserver_1113.tools;
- import lombok.Data;
- /**
- * @version 1.0
- * @Author 作者名
- * @Date 2024/11/13 18:40
- * @注释
- */
- @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;
- }
- }
复制代码 对于usercontroller类举行更新:
- @RestController
- @RequestMapping("/user")
- public class UserController {
- @Autowired
- private UserMapper userMapper;
- @RequestMapping("/login")
- public ResponseBodyMessage<User> login(@RequestParam String username,
- @RequestParam String password) {
- User loginUser = new User();
- loginUser.setUsername(username);
- loginUser.setPassword(password);
- User user = userMapper.login(loginUser);
- if (user == null) {
- System.out.println("登录失败!");
- return new ResponseBodyMessage<>(-1,"登录失败",loginUser);
- } else {
- return new ResponseBodyMessage<>(0,"登录成功",loginUser);
- }
- }
- }
复制代码 使用postman举行测试:
此时我们针对响应封装的使用乐成运行,根据响应可以看到,我们的数据容易泄露,且等登录乐成之后就需要把用户信息写到新创建的httpsession内里,修改代码如下所示:
创建constant类,界说常量字符串:
- public class Constant {
- public static final String USERINFO_SESSION_KEY = "USERINFO_SESSION_KEY";
- }
复制代码 修改的usercontroller:
- @RestController
- @RequestMapping("/user")
- public class UserController {
- @Autowired
- private UserMapper userMapper;
- @RequestMapping("/login")
- public ResponseBodyMessage<User> login(@RequestParam String username,
- @RequestParam String password,
- HttpServletRequest request) {
- User loginUser = new User();
- loginUser.setUsername(username);
- loginUser.setPassword(password);
- User user = userMapper.login(loginUser);
- if (user == null) {
- System.out.println("登录失败!");
- return new ResponseBodyMessage<>(-1,"登录失败",loginUser);
- } else {
- //request.getSession().setAttribute("USERINFO_SESSION_KEY",user);
- //上述代码由于USERINFO_SESSION_KEY是字符串由于容易写错,所以
- //创建枚举类constant,来定义一个常量USERINFO_SESSION_KEY为一个字符串,这样就方便我们后期调用
- request.getSession().setAttribute(Constant.USERINFO_SESSION_KEY,user);
- return new ResponseBodyMessage<>(0,"登录成功",loginUser);
- }
- }
- }
复制代码 HttpServletRequest对象代表客户端的请求,当客户端通过HTTP协议访问服务器时,HTTP请求头中的全部信息都封装在这个对象中,通过这个对象提供的方法,可以获得客户端请求的全部信息。该对象的getsession,即用于获取与当前请求关联的会话对象, 如果不存在会话对象(第一次登录),则创建一个新的会话。
我们使用postman举行登录验证:
3.4 md5加密使用
MD5是⼀个安全的散列算法,输⼊两个差别的明⽂不会得到类似的输出值,根据输出值,不能得到原 始的明⽂,即其过程不可逆;但是虽然不可逆,但是不是说就是安全的。因为⾃从出现彩虹表后,这 样的密码也"不安全"。
更安全的做法是加盐或者⻓密码等做法,让整个加密的字符串变的更⻓,破解时间变慢。密码学的应 ⽤安全,是建⽴在破解所要付出的成本远超出能得到的利益上的。 这⾥我们使用加盐的做法:盐是在每个密码中加⼊⼀些单词来变成⼀个新的密码,存⼊数据库当中。 添加依靠:
- <!-- 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>
复制代码 加盐加密的逻辑:
第一次加盐加密:模仿前端对密码举行 使用,加盐(在原始密码中添加一些元素),加密(对加盐之后的二次密码举行加密);
第二次加盐加密:对于第一次加盐加密的密码举行第二次使用;
终极得到我们想要的加密字符串,在tools包下面新建MD5Util类,代码如下:
- public class MD5Util {
- //定义⼀个固定的盐值
- private static final String salt = "1b2i3t4e";
- //进行加密的成员方法
- public static String md5(String src) {
- return DigestUtils.md5Hex(src);
- }
- //第⼀次加密:模拟前端⾃⼰加密,然后传到后端
- 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加密前端加密过的密码,传给后端进⾏第2次加密
- ⽤⼾数据库当中的盐值
- * @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"));
- }
- }
复制代码 运行结果如下:

3.5 BCrypt加密设计
Bcrypt就是⼀款加密⼯具,可以⽐较⽅便地实现数据的加密⼯作。你也可以简单明白为它内部⾃⼰实 现了随机加盐处置惩罚。我们使⽤MD5加密,每次加密后的密⽂其实都是⼀样的,这样就⽅便了MD5通过 ⼤数据的⽅式进⾏破解。Bcrypt⽣成的密⽂是60位的。⽽MD5的是32位的。Bcrypt破解难度更⼤。
添加依靠:
- <!-- 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>
复制代码 在springboot启动类添加相关的代码:
- @SpringBootApplication(exclude =
- {org.springframework.boot.autoconfigure.security.servlet.SecurityAutoConfiguration.class})
- public class SpringMusicserver1113Application {
- public static void main(String[] args) {
- SpringApplication.run(SpringMusicserver1113Application.class, args);
- }
- }
复制代码 bcrypt加密测试代码如下:
- 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);
- }
- }
复制代码 BCrypt加密:⼀种加盐的单向Hash,不可逆的加密算法,同⼀种明⽂(plaintext),每次加密后的 密⽂都不⼀样,⽽且不可反向破解⽣成明⽂,破解难度很⼤。
MD5加密:是不加盐的单向Hash,不可逆的加密算法,同⼀个密码经过hash的时间⽣成的是同⼀个 hash值,在⼤多数的情况下,有些经过md5加密的⽅法将会被破解。
Bcrypt⽣成的密⽂是60位的。⽽MD5的是32位的。
⽬前,MD5和BCrypt⽐较流⾏。相对来说,BCrypt⽐MD5更安全,但加密更慢。 虽然BCrpyt也是输⼊的字符串+盐,但是与MD5+盐的重要区别是:每次加的盐差别,导致每次⽣成的 结果也不类似。⽆法⽐对!
3.6 加密登录实现
3.6.1 数据库插⼊数据
将上述BCryptTest运⾏⽣成的对123456加密后的结果,插⼊到数据库当中
3.6.2 UserMapper类新增⽅法
- @Mapper
- public interface UserMapper {
- User login(User loginUser);
- User selectByName(String username);
- }
复制代码 3.6.3 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.spring_musicserver_1113.mapper.UserMapper">
- <select id="login" resultType="com.example.spring_musicserver_1113.model.User">
- select * from user where username=#{username} and password=#{password};
- </select>
- <select id="selectByName" resultType="com.example.spring_musicserver_1113.model.User">
- select * from user where username = #{username};
- </select>
- </mapper>
复制代码 3.6.4 修改UserController类
- @RestController
- @RequestMapping("/user")
- public class UserController {
- @Autowired
- private UserMapper userMapper;
- @Autowired
- private BCryptPasswordEncoder bCryptPasswordEncoder;
- @RequestMapping("/login")
- public ResponseBodyMessage<User> login(@RequestParam String username,
- @RequestParam String password,
- HttpServletRequest request) {
- User user = userMapper.selectByName(username);
- if (user == null) {
- System.out.println("登录失败!");
- return new ResponseBodyMessage<>(-1,"用户名或密码错误",user);
- } else {
- boolean flag = bCryptPasswordEncoder.matches(password,user.getPassword());
- if(!flag){
- return new ResponseBodyMessage<>(-1,"用户名或密码错误!",user);
- }
- request.getSession().setAttribute(Constant.USERINFO_SESSION_KEY,user);
- return new ResponseBodyMessage<>(0,"登录成功",user);
- }
- }
- }
复制代码 我们这里将创建BCryptPasswordEncoder对象变成了注入该对象,以是就需要举行创建配置相对用类,然后使用注解来注入;
3.6.5 创建包config,新建AppConfig类
- @Configuration
- public class AppConfig {
- @Bean
- public BCryptPasswordEncoder getBCryptPasswordEncoder(){
- return new BCryptPasswordEncoder();
- }
- }
复制代码 注解介绍:
@Configuration:表明当前类是⼀个配置类,被注解的类内部包罗有⼀个或多个被@Bean注解的⽅法,⽤于构建bean界说,初始化Spring容器。
@Bean注解:⽤于告诉⽅法,产⽣⼀个Bean对象,然后这个Bean对象交给Spring管理。产⽣这个 Bean对象的⽅法Spring只会调⽤⼀次,随后这个Spring将会将这个Bean对象放在⾃⼰的IOC容器中。
SpringIOC 容器管理⼀个或者多个bean,这些bean都需要在@Configuration注解下进⾏创建,在⼀ 个⽅法上使⽤@Bean注解就表明这个⽅法需要交给Spring进⾏管理。
3.6.6 spring-boot启动类注解
- @SpringBootApplication(exclude =
- {org.springframework.boot.autoconfigure.security.servlet.SecurityAutoConfiguration.class})
复制代码 当启动类,没有加这个过滤的时间,我们发现不能进⾏登录 ,来由如下:
我们在pom文件内里添加依靠的时间,添加的是spring-security的依靠,但是spring-security是一个很大的框架,我们所使用的org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;(BCryptPasswordEncoder类是spring-security框架下的一个包内里的类,在整个大框架下我们仅仅使用BCryptPasswordEncoder这一个类),以是我们要添加这一行代码来禁止启动步伐扫描spring-security的默认路径,因为在SpringBoot中,默认的SpringSecurity是⽣效了的,此时的接⼝都是被保护的,我们需要通过验证才气正常的访问。此时通过上述配置,即可禁⽤默认的登录验证。
测试登录:
ps:未完待续
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。 |