Spring?后端安全雙劍之JWT?無狀態(tài)認證?+?密碼加鹽加密實戰(zhàn)指南
引言
在 Java Spring 后端開發(fā)中,“安全” 永遠是繞不開的話題,用戶登錄如何免 Session 認證?用戶密碼如何防止泄露?我們通過上篇令牌技術下篇加鹽/加密,這兩個核心技術,來聊聊關于如何讓后端的認證體系更安全、更可靠
加密/加鹽
加密的必要性
在 MySQL 數(shù)據庫的日常使用過程中,用戶密碼、身份證號碼、手機號碼這類敏感數(shù)據的加密處理至關重要,這是保障數(shù)據安全的核心環(huán)節(jié)
倘若直接以明文形式存儲這些信息,一旦數(shù)據庫遭遇黑客攻擊并被非法侵入,攻擊者就能輕易竊取到用戶的各類敏感信息。這種情況的發(fā)生,不僅會導致用戶個人信息泄露,還可能給用戶自身或所屬企業(yè)帶來財產方面的損失,造成難以估量的后果
密碼算法分類
密碼算法主要分為三類:對稱密碼算法,?對稱密碼算法,摘要算法

1. 對稱加密算法
- 核心特性:加密、解密使用同一密鑰,運算速度快、效率高。
- 子類型:
- 分組密碼算法:將數(shù)據分割為固定長度的塊進行加密(如 AES、DES)。
- 流密碼算法:逐字節(jié)生成密鑰流,與明文逐位加密(如 ChaCha)。
- 適用場景:大數(shù)據量加密(如文件、數(shù)據庫字段),需注意密鑰安全管理。
2. 非對稱加密算法
- 核心特性:使用公鑰 + 私鑰的密鑰對,公鑰可公開、私鑰需保密;公鑰加密的數(shù)據僅能通過對應私鑰解密(反之亦然)。
- 優(yōu)勢:解決了對稱加密的 “密鑰分發(fā)” 問題,支持數(shù)字簽名(私鑰簽名、公鑰驗證)。
- 不足:加解密速度遠慢于對稱加密。
- 適用場景:小數(shù)據加密(如密鑰交換、數(shù)字簽名),典型算法如 RSA、ECC。
3. 摘要算法
- 核心特性:單向哈希運算,將任意長度數(shù)據轉換為固定長度的 “摘要值”;無法從摘要反推原文,數(shù)據微小變化會導致摘要完全不同。
- 子類型:
- MD(Message Digest):消息摘要算法(如 MD5)。
- SHA-1(Secure Hash Algorithm):安全散列算法。
- MAC(Message Authentication Code):消息認證碼算法。
- 適用場景:數(shù)據完整性驗證、密碼存儲(存摘要而非明文)、數(shù)字簽名組件。
加密思路
本篇文字主要以MD5算法來講解加密
MD5可加密原理:加鹽
MD5本身是不可逆的,加上相同的密碼經過MD5哈希之后的密?是相同的,就很有可能被破解,但是我們可以采?為?個密碼拼接?個隨機字符來進?加密,這個隨機字符我們稱之為 “鹽”,這樣子即使黑客拿到數(shù)據庫的數(shù)據,也是加密后字符串和鹽的組合的字符串

密?相同,鹽值相同,則證明 明?相同
運用加密/加鹽
寫加密/解密?具類
public class SecurityUtil {
//加密
//返回鹽值+md5(鹽值+明文)
public static String encrypt(String password) {
String salt = UUID.randomUUID().toString().replace("-", "");
String securityPassword = DigestUtils.md5DigestAsHex((salt + password).getBytes(StandardCharsets.UTF_8));
return salt + securityPassword;
}
//解密
public static boolean verify(String inputPassword, String sqlPassword){
if(!StringUtils.hasLength(inputPassword)){
return false;
}
if(sqlPassword==null||sqlPassword.length()!=64){
return false;
}
String salt = sqlPassword.substring(0,32);
String securityPassword = DigestUtils.md5DigestAsHex((salt + inputPassword).getBytes(StandardCharsets.UTF_8));
return sqlPassword.equals(salt + securityPassword);
}
}工具解析:

使用加密/解密?具類簡單測試:
public static void main(String[] args) {
String encrypt = encrypt("123456");
boolean verify = verify("123456", encrypt);
System.out.println(verify);
}測試結果:

運用實戰(zhàn)
創(chuàng)建響應和請求實體類:
@Data
public class UserLoginRequest {
@NotNull(message = "用戶名不能為空")
private String userName;
@NotNull(message = "密碼不能為空")
private String password;
}
@Data
@AllArgsConstructor
public class UserLoginResponse {
private Integer userId;
private String token;
}UserLoginResponse 接口類:
@RequestMapping("/login")
public UserLoginResponse login(@RequestBody @Validated UserLoginRequest userLoginRequest){
log.info("用戶登錄,用戶名:{}",userLoginRequest.getUserName());
return userService.checkPassword(userLoginRequest);
}
UserServiceImpl Serviece類:
@Service
public class UserServiceImpl implements UserService {
@Autowired
private UserInfoMapper userInfoMapper;
@Resource(name = "blogServiceImpl")
private BlogService blogService;
@Override
public UserLoginResponse checkPassword(UserLoginRequest userLoginRequest) {
QueryWrapper<UserInfo> queryWrapper = new QueryWrapper<>();
queryWrapper.lambda().eq(UserInfo::getUserName,userLoginRequest.getUserName())
.eq(UserInfo::getDeleteFlag,0);
UserInfo userInfo = userInfoMapper.selectOne(queryWrapper);
if(userInfo==null){
//用戶不存在
throw new BlogException("用戶不存在");
}
//判斷密碼是否一致
if(!SecurityUtil.verify(userLoginRequest.getPassword(),userInfo.getPassword())){
throw new BlogException("用戶密碼錯誤");
}
//密碼正確
Map<String,Object> map=new HashMap<>();
map.put("id",userInfo.getId());
map.put("name",userInfo.getUserName());
String token = JwtUtils.genToken(map);
return new UserLoginResponse(userInfo.getId(),token);
}使?測試類給密碼123456?成密?,寫到數(shù)據庫:

測試:
當密碼輸入123456時,可以登錄
當輸入不為123456時提示密碼輸入錯誤,

加密成功
到此這篇關于Spring 后端安全雙劍JWT 無狀態(tài)認證 + 密碼加鹽加密實戰(zhàn)的文章就介紹到這了,更多相關spring jwt無狀態(tài)認證內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
SpringBoot 整合 Netty 多端口監(jiān)聽的操作方法
Netty提供異步的、基于事件驅動的網絡應用程序框架,用以快速開發(fā)高性能、高可靠性的網絡 IO 程序,是目前最流行的 NIO 框架,這篇文章主要介紹了SpringBoot 整和 Netty 并監(jiān)聽多端口,需要的朋友可以參考下2023-10-10
在Spring中給HttpServletRequest添加自定義Header的完整指南
在Spring應用開發(fā)中,我們經常需要在請求處理過程中添加自定義的 HTTP Header,由于HttpServletRequest對象在設計上是只讀的,直接添加Header會遇到困難,本文將詳細介紹如何通過Filter和RequestWrapper的方式優(yōu)雅地解決這個問題,需要的朋友可以參考下2025-10-10
解析SpringBoot中@Autowire注解的實現(xiàn)原理
在開發(fā)Java項目時,依賴注入是一種常見的實現(xiàn)方式,SpringBoot框架通過@Autowired注解來實現(xiàn)依賴注入的功能,本文將介紹SpringBoot中 Autowired注解實現(xiàn)的原理2023-06-06
Mybatis resultType返回結果為null的問題排查方式
這篇文章主要介紹了Mybatis resultType返回結果為null的問題排查方式,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2022-03-03

