项目主要实现了:
注册:
普通用户在使用时,需要先进行注册,注册之后才可以登录使用。注册的时候通过 BCrypt 加密,保证用户密码的安全性:
登录之后的列表页面 :
因为是普通用户,所以不能删除音乐,只能喜欢、播放、搜索和添加音乐。
喜欢列表 :
搜索功能 :
添加音乐 :
注册 :
管理员可以通过管理员注册页面进行注册:
音乐列表:
管理员可以对音乐进行单个删除和批量删除。
其它 :
管理员在其他方面的功能和普通用户是一样的。
主要就是对注册密码进行加密,防止在登陆的时候,别人一抓包,就抓到我们的账号和密码。加密的时候,有 MD5 和 BCrypt 两种加密方式。
MD5是一个安全的散列算法。
MD5 不安全的原因:
让 MD5 更安全的方法: 主要就是通过加盐或者使用长密码等算法,让整个加密字符串变得更长,破解时间变慢。如果破解密码时间足够长,就说明密码是安全的。
加盐的过程 :
添加 MD5 依赖:
<dependency>
<groupId>commons-codecgroupId>
<artifactId>commons-codecartifactId>
dependency>
<dependency>
<groupId>org.apache.commonsgroupId>
<artifactId>commons-lang3artifactId>
<version>3.9version>
dependency>
创建一个 MD5 类:
public class MD5Util {
//定义一个固定的盐值
private static final String salt = "Lockey123";
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"),
"Lockey123"));
System.out.println("对用户输入密码进行第2次加密:"+inputPassToDbPass("123456", "Lockey123"));
}
}
进行两次加密是为了说明,MD5 的两次分开加密和一次加密两次的结果是一样的:
发现密码不一样,也就说明了加密的不安全性。
当每次都可以生成一个随机的盐值,就可以有效防止这样的问题的产生。所以也就用到了 BCrypt 加密。
BCrypt 加密是一种比 MD5 刚安全的一种加密方式,也就是加的盐是随机的,这样的话,破解的时间成本就会大很多。
BCrypt 生成的密文是 60 位的,而 MD5 是 32 位的,所以 BCrypt 的破解难度更大。
导入依赖:
<dependency>
<groupId>org.springframework.securitygroupId>
<artifactId>spring-security-webartifactId>
dependency>
<dependency>
<groupId>org.springframework.securitygroupId>
<artifactId>spring-security-configartifactId>
dependency>
在 SpringBoot 启动类当中,加上一个 exclude :exclude = {org.springframework.boot.autoconfigure.security.servlet.SecurityAutoConfiguration.class}
如果不加的话,会导致项目报错。
创建一个类来测试:
public class BCryptUtil {
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 的使用比 MD5 简单很多,encode 方法就直接完成了加密,加密的运行结果如下:
再加密一次,结果如下:
虽然原始密码一样,但是每次加密的结果都不一样,所以 BCrypt 更安全。也就是每次加密的时候,都是随即加盐处理。密码安全的原因就是,破解的成本比收益高,就说明密码是安全的。
BCrypt 加密:
是一种加盐的单向 Hash,不可逆的加密算法,同一种明文(plaintext),每次加密后的密文都不一样,而且不可反向破解生成明文,破解难度很大。
MD5 加密:
是不加盐的单向 Hash,不可逆的加密算法,同一个密码经过 hash 的时候生成的是同一个 hash 值,在大多数的情况下,有些经过 md5 加密的方法将会被破解。
目前来说,MD5 和 BCrypt 都比较流行。相对来说,BCrypt 比 MD5 更安全,但加密更慢。虽然 BCrpyt 也是输入的字符串+盐,但是与 MD5+盐 的主要区别是:每次加的盐不同,导致每次生成的结果也不相同。无法比对!
主要就是对 MP3 后缀名的文件进行校验,看是不是真的 MP3 文件。
MP3 文件大体分为三部分:TAG_V2(ID3V2),Frame, TAG_V1(ID3V1) :
也就是说,每个Frame都由帧头和数据部分组成。那么每个帧头的数据格式如下,如图片所示:使用字符 A 到 M 表示不同的区域。在表格中可以看到每一区域的详细内容(只截取部分,详细参考点这里 :
提到 ID3V1 和 ID3V2 就不得不提 MPEG 音频标签 。ID3V1 和 ID3V2 是 MPEG标签 的两种。
这种是存在于 文件尾部,长度是 128字节。用来描述 MPEG 音频文件,包含艺术家,标题,唱片集,发布年代和流派,还有额外的注释空间,位于音频文件的最后。固定为 128 字节。可以读取该文件的最后这 128 字节,来获得标签,结构如下:
AAABBBBB BBBBBBBB BBBBBBBB BBBBBBBB
BCCCCCCC CCCCCCCC CCCCCCCC CCCCCCCD
DDDDDDDD DDDDDDDD DDDDDDDD DDDDDEEE
EFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFG
所以看了上面那张表,是不是就可以认为:我们只需要查看文件尾部的128个字节里面,有没有 TAG 字样就可以了。事实上就是这样的,如果三个字节中有 “TAG” 字样(标记)。就说明它是一个 音频文件。反之,如果不包含,则说明它不是一个 音频文件。存放“ TAG ”字符,表示 ID3 V1.0 标准 ,根据是否包含这个字符,判断是不是音频文件。
是对 ID3V1 的一种扩展,存在文件头部,长度不定。所以就很难判断文件是否是音频文件。
参考资料:
https://www.cnblogs.com/ranson7zop/p/7655474.html
https://blog.csdn.net/sunshine1314/article/details/2514322
代码如下:
import lombok.Data;
import java.io.*;
import java.util.HashMap;
@Data
public class GetFileType {
private static HashMap<String,String> fileHeadMap = new HashMap<>();
static {
//检测音频,分别是 两种的 ID3 类型
fileHeadMap.put("494433030000","mp3");
fileHeadMap.put("494433040000","MP3");
}
/**
* 获取文件类型
* @param filePath 文件路径
* @return 文件类型
*/
public static String getFileHead(String filePath)throws IOException {
//获取文件头
File file = new File(filePath);
FileReader reader = new FileReader(file);
BufferedReader br = new BufferedReader(reader);
StringBuilder fileHead = new StringBuilder();
for(int i = 0 ; i<=5;i++ ){
int flag = br.read();
if(Integer.toHexString(flag).length()==1){
fileHead.append(0);
}
fileHead.append(Integer.toHexString(flag));
}
br.close();
//查询文件类型
return fileHeadMap.get(fileHead.toString());
}
public static void main(String[] args) throws IOException {
System.out.println(getFileHead("D:/下载/Crush.mp3"));
}
}
测试 MP3 文件:
运行结果如下:
测试改后缀名的文件:
运行结果如下: