【项目实战】前后端分离的SpringCloud项目如何通过AES对称加密算法对登录密码加解密?
迪丽瓦拉
2024-05-12 03:48:57
0

一、AES对称加密算法简介

1.1 AES对称加密算法是什么?

AES(Advanced Encryption Standard,高级加密标准)是一种对称加密算法,常用于加密数据传输和数据存储。它采用了更高级的替代替代数据加密标准(DES)的技术,并且被认为是目前最安全的对称加密算法。

1.2 AES对称加密算法中基本概念

包括密钥长度、分组密码和循环。

概念解析
密钥SECRET_KEY
密钥长度可以是128、192或256位
分组密码意味着明文被分成若干个组,每组再分别加密。
循环循环指加密过程中重复运算的次数。
IV向量可以使用六位十六进制数作为密钥偏移量SECRET_IV

二、前端如何使用AES算法进行加密?

用户登录时,对登录密码进行加密传输,因此需要在前端提供简单的AES对称加密算法,实现加密,在后端实现解密。
以下是具体的步骤

2.1 定义前端配置文件

在前端配置文件project-ui\src\config\env.js中定义securityKey的值
注意key 和后端网关配置相同,这里打包混淆后,相对安全。

import {isSandEnv} from "@/util/util";
// 配置编译环境和线上环境之间的切换
const env = process.env
//前端密码密钥,必须16位,和nacos配置文件base-gateway-dev.yml中的security.encode.key对应
let securityKey = '1234567891234567'
if (env.NODE_ENV == 'development') {} else if (env.NODE_ENV == 'production') {} else if (env.NODE_ENV == 'test') {
}
export {env,securityKey
}

2.2 引入前端依赖crypto-js

"dependencies": {"crypto-js": "^3.1.9-1",

2.3 编写前端加密方法

import * as CryptoJS from'crypto-js'
/***加密处理*/
export const encryption = (params) => {let {data,type,param,key} = paramsconst result = JSON.parse(JSON.stringify(data))if (type === 'Base64') {param.forEach(ele => {result[ele] = btoa(result[ele])})} else {param.forEach(ele => {var data = result[ele]key = CryptoJS.enc.Latin1.parse(key)var iv = key// 加密var encrypted = CryptoJS.AES.encrypt(data,key, {iv: iv,mode: CryptoJS.mode.CBC,padding: CryptoJS.pad.ZeroPadding})result[ele] = encrypted.toString()})}return result
}

2.4 新建页面JS逻辑

project-ui\src\store\modules\user.js

2.5 引入securityKey字段和encryption方法

import { encryption} from '@/util/util'
import { securityKey } from '@/config/env'

2.6 使用securityKey 字段

  // 根据用户名登录LoginByUsername({commit}, userInfo) {const user = encryption({data: userInfo,key: securityKey,param: ['password']})return new Promise((resolve, reject) => {loginByUsername(user.username, user.password, user.code, user.randomStr).then(response => {const data = response.datacommit('SET_ACCESS_TOKEN', data.access_token)commit('SET_REFRESH_TOKEN', data.refresh_token)commit('SET_EXPIRES_IN', data.expires_in)commit('CLEAR_LOCK')resolve()}).catch(error => {reject(error)})})},

三、后端如何使用AES算法进行解密?

3.1 后端 网关定义迷药

在Nacos上的配置中 base-gateway-dev.yml,修改gateway上的配置文件,设置好密钥如下

security:encode:# 前端密码密钥,必须16位key: '1234567891234567'

3.2 使用hutool提供的工具类进行解密

public class PasswordDecoderFilter extends AbstractGatewayFilterFactory {private static final String PASSWORD = "password";private static final String KEY_ALGORITHM = "AES";@Value("${security.encode.key:1234567812345678}")private String encodeKey;@SneakyThrowsprivate static String decryptAES(String data, String pass) {AES aes = new AES(Mode.CBC,Padding.NoPadding,new SecretKeySpec(pass.getBytes(), KEY_ALGORITHM),new IvParameterSpec(pass.getBytes()));byte[] result = aes.decrypt(Base64.decode(data.getBytes(StandardCharsets.UTF_8)));return new String(result, StandardCharsets.UTF_8);}@Overridepublic GatewayFilter apply(Object config) {return (exchange, chain) -> {ServerHttpRequest request = exchange.getRequest();// 不是登录请求,直接向下执行if (!StrUtil.containsAnyIgnoreCase(request.getURI().getPath(), SecurityConstants.OAUTH_TOKEN_URL)) {return chain.filter(exchange);}URI uri = exchange.getRequest().getURI();String queryParam = uri.getRawQuery();Map paramMap = HttpUtil.decodeParamMap(queryParam, CharsetUtil.CHARSET_UTF_8);String password = paramMap.get(PASSWORD);if (StrUtil.isNotBlank(password)) {try {password = decryptAES(password, encodeKey);} catch (Exception e) {log.error("密码解密失败:{}", password);return Mono.error(e);}paramMap.put(PASSWORD, password.trim());}URI newUri = UriComponentsBuilder.fromUri(uri).replaceQuery(HttpUtil.toParams(paramMap)).build(true).toUri();ServerHttpRequest newRequest = exchange.getRequest().mutate().uri(newUri).build();return chain.filter(exchange.mutate().request(newRequest).build());};}
}

四、参考文档

crypto-js 加密、解密使用方法

相关内容