diff --git a/hyp-admin/pom.xml b/hyp-admin/pom.xml index 10c1199..b092b09 100644 --- a/hyp-admin/pom.xml +++ b/hyp-admin/pom.xml @@ -68,6 +68,13 @@ 2.1.0 + + + org.bouncycastle + bcprov-jdk15on + 1.59 + + org.springframework.boot diff --git a/hyp-admin/src/main/java/com/hyp/web/controller/system/SysLoginController.java b/hyp-admin/src/main/java/com/hyp/web/controller/system/SysLoginController.java index e5109fd..cddd900 100644 --- a/hyp-admin/src/main/java/com/hyp/web/controller/system/SysLoginController.java +++ b/hyp-admin/src/main/java/com/hyp/web/controller/system/SysLoginController.java @@ -4,6 +4,7 @@ import java.util.List; import java.util.Set; import com.hyp.common.utils.sign.RsaUtils; +import com.hyp.common.utils.sign.Sm4Util; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PostMapping; @@ -47,7 +48,7 @@ public class SysLoginController AjaxResult ajax = AjaxResult.success(); // 生成令牌 String token = loginService.login(loginBody.getUsername(), - RsaUtils.decryptByPrivateKey(loginBody.getPassword()), loginBody.getCode()); + Sm4Util.decryptEcb(loginBody.getPassword()), loginBody.getCode()); ajax.put(Constants.TOKEN, token); return ajax; } @@ -85,4 +86,14 @@ public class SysLoginController List menus = menuService.selectMenuTreeByUserId(userId); return AjaxResult.success(menuService.buildMenus(menus)); } + + /** + * 获取公钥 前端用来密码加密 + * + * @return + */ + @GetMapping("/publicKey") + public String publicKey() throws Exception { + return Sm4Util.hexKey; + } } diff --git a/hyp-admin/src/main/java/com/hyp/web/controller/system/SysProfileController.java b/hyp-admin/src/main/java/com/hyp/web/controller/system/SysProfileController.java index d19400d..3bac90d 100644 --- a/hyp-admin/src/main/java/com/hyp/web/controller/system/SysProfileController.java +++ b/hyp-admin/src/main/java/com/hyp/web/controller/system/SysProfileController.java @@ -1,5 +1,6 @@ package com.hyp.web.controller.system; +import com.hyp.common.utils.sign.Sm4Util; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PostMapping; @@ -25,13 +26,12 @@ import com.hyp.system.service.ISysUserService; /** * 个人信息 业务处理 - * + * * @author ruoyi */ @RestController @RequestMapping("/system/user/profile") -public class SysProfileController extends BaseController -{ +public class SysProfileController extends BaseController { @Autowired private ISysUserService userService; @@ -42,8 +42,7 @@ public class SysProfileController extends BaseController * 个人信息 */ @GetMapping - public AjaxResult profile() - { + public AjaxResult profile() { LoginUser loginUser = getLoginUser(); SysUser user = loginUser.getUser(); AjaxResult ajax = AjaxResult.success(user); @@ -57,24 +56,20 @@ public class SysProfileController extends BaseController */ @Log(title = "个人信息", businessType = BusinessType.UPDATE) @PutMapping - public AjaxResult updateProfile(@RequestBody SysUser user) - { + public AjaxResult updateProfile(@RequestBody SysUser user) { LoginUser loginUser = getLoginUser(); SysUser currentUser = loginUser.getUser(); currentUser.setNickName(user.getNickName()); currentUser.setEmail(user.getEmail()); currentUser.setPhonenumber(user.getPhonenumber()); currentUser.setSex(user.getSex()); - if (StringUtils.isNotEmpty(user.getPhonenumber()) && !userService.checkPhoneUnique(currentUser)) - { + if (StringUtils.isNotEmpty(user.getPhonenumber()) && !userService.checkPhoneUnique(currentUser)) { return error("修改用户'" + loginUser.getUsername() + "'失败,手机号码已存在"); } - if (StringUtils.isNotEmpty(user.getEmail()) && !userService.checkEmailUnique(currentUser)) - { + if (StringUtils.isNotEmpty(user.getEmail()) && !userService.checkEmailUnique(currentUser)) { return error("修改用户'" + loginUser.getUsername() + "'失败,邮箱账号已存在"); } - if (userService.updateUserProfile(currentUser) > 0) - { + if (userService.updateUserProfile(currentUser) > 0) { // 更新缓存用户信息 tokenService.setLoginUser(loginUser); return success(); @@ -87,24 +82,22 @@ public class SysProfileController extends BaseController */ @Log(title = "个人信息", businessType = BusinessType.UPDATE) @PutMapping("/updatePwd") - public AjaxResult updatePwd(String oldPassword, String newPassword) - { + public AjaxResult updatePwd(String oldPassword, String newPassword) throws Exception { LoginUser loginUser = getLoginUser(); String userName = loginUser.getUsername(); String password = loginUser.getPassword(); - if (!SecurityUtils.matchesPassword(oldPassword, password)) - { + //解密 + oldPassword = Sm4Util.decryptEcb(oldPassword); + newPassword = Sm4Util.decryptEcb(newPassword); + if (!SecurityUtils.matchesPassword(oldPassword, password)) { return error("修改密码失败,旧密码错误"); } - if (SecurityUtils.matchesPassword(newPassword, password)) - { + if (SecurityUtils.matchesPassword(newPassword, password)) { return error("新密码不能与旧密码相同"); } - newPassword = SecurityUtils.encryptPassword(newPassword); - if (userService.resetUserPwd(userName, newPassword) > 0) - { + if (userService.resetUserPwd(userName, SecurityUtils.encryptPassword(newPassword)) > 0) { // 更新缓存用户密码 - loginUser.getUser().setPassword(newPassword); + loginUser.getUser().setPassword(SecurityUtils.encryptPassword(newPassword)); tokenService.setLoginUser(loginUser); return success(); } @@ -116,14 +109,11 @@ public class SysProfileController extends BaseController */ @Log(title = "用户头像", businessType = BusinessType.UPDATE) @PostMapping("/avatar") - public AjaxResult avatar(@RequestParam("avatarfile") MultipartFile file) throws Exception - { - if (!file.isEmpty()) - { + public AjaxResult avatar(@RequestParam("avatarfile") MultipartFile file) throws Exception { + if (!file.isEmpty()) { LoginUser loginUser = getLoginUser(); String avatar = FileUploadUtils.upload(HypConfig.getAvatarPath(), file, MimeTypeUtils.IMAGE_EXTENSION); - if (userService.updateUserAvatar(loginUser.getUsername(), avatar)) - { + if (userService.updateUserAvatar(loginUser.getUsername(), avatar)) { AjaxResult ajax = AjaxResult.success(); ajax.put("imgUrl", avatar); // 更新缓存用户头像 diff --git a/hyp-admin/src/main/java/com/hyp/web/controller/system/SysRegisterController.java b/hyp-admin/src/main/java/com/hyp/web/controller/system/SysRegisterController.java index 55fa340..f64a30f 100644 --- a/hyp-admin/src/main/java/com/hyp/web/controller/system/SysRegisterController.java +++ b/hyp-admin/src/main/java/com/hyp/web/controller/system/SysRegisterController.java @@ -13,12 +13,11 @@ import com.hyp.system.service.ISysConfigService; /** * 注册验证 - * + * * @author ruoyi */ @RestController -public class SysRegisterController extends BaseController -{ +public class SysRegisterController extends BaseController { @Autowired private SysRegisterService registerService; @@ -26,10 +25,8 @@ public class SysRegisterController extends BaseController private ISysConfigService configService; @PostMapping("/register") - public AjaxResult register(@RequestBody RegisterBody user) - { - if (!("true".equals(configService.selectConfigByKey("sys.account.registerUser")))) - { + public AjaxResult register(@RequestBody RegisterBody user) throws Exception { + if (!("true".equals(configService.selectConfigByKey("sys.account.registerUser")))) { return error("当前系统没有开启注册功能!"); } String msg = registerService.register(user); diff --git a/hyp-common/pom.xml b/hyp-common/pom.xml index a24d821..bf31cf4 100644 --- a/hyp-common/pom.xml +++ b/hyp-common/pom.xml @@ -143,6 +143,13 @@ 2.5.1 + + + org.bouncycastle + bcprov-jdk15on + 1.59 + + org.projectlombok lombok diff --git a/hyp-common/src/main/java/com/hyp/common/constant/UserConstants.java b/hyp-common/src/main/java/com/hyp/common/constant/UserConstants.java index aebf442..8e68c7a 100644 --- a/hyp-common/src/main/java/com/hyp/common/constant/UserConstants.java +++ b/hyp-common/src/main/java/com/hyp/common/constant/UserConstants.java @@ -74,5 +74,5 @@ public class UserConstants * 密码长度限制 */ public static final int PASSWORD_MIN_LENGTH = 5; - public static final int PASSWORD_MAX_LENGTH = 20; + public static final int PASSWORD_MAX_LENGTH = 20000; } diff --git a/hyp-common/src/main/java/com/hyp/common/utils/sign/Sm4Util.java b/hyp-common/src/main/java/com/hyp/common/utils/sign/Sm4Util.java new file mode 100644 index 0000000..ba63544 --- /dev/null +++ b/hyp-common/src/main/java/com/hyp/common/utils/sign/Sm4Util.java @@ -0,0 +1,175 @@ +package com.hyp.common.utils.sign; + +import java.security.*; +import java.util.Arrays; +import javax.crypto.Cipher; +import javax.crypto.KeyGenerator; +import javax.crypto.spec.SecretKeySpec; +import org.bouncycastle.jce.provider.BouncyCastleProvider; +import org.bouncycastle.pqc.math.linearalgebra.ByteUtils; + +/** + * ClassName: Sm4Util + * Package: com.hyp.common.utils.sign + * sm4加密算法工具类 + * @explain sm4加密、解密与加密结果验证 可逆算法 + * + * @Author wangxy + * @Create 2024/11/28 14:44 + * @Version 1.0 + */ +public class Sm4Util { + + static { + Security.addProvider(new BouncyCastleProvider()); + } + private static final String ENCODING = "UTF-8"; + public static final String ALGORITHM_NAME = "SM4"; + // 加密算法/分组加密模式/分组填充方式 + // PKCS5Padding-以8个字节为一组进行分组加密 + // 定义分组加密模式使用:PKCS5Padding + public static final String ALGORITHM_NAME_ECB_PADDING = "SM4/ECB/PKCS5Padding"; + // 128-32位16进制;256-64位16进制 + public static final int DEFAULT_KEY_SIZE = 128; + + /** + * 当时用ECB模式的时候,和前端key一致 + */ + public static final String hexKey = "6fb7b3dcaa041c798c3798abe6f9575c"; + + /** + * 生成ECB暗号 + * @explain ECB模式(电子密码本模式:Electronic codebook) + * @param algorithmName 算法名称 + * @param mode 模式 + * @param key + * @return + * @throws Exception + */ + private static Cipher generateEcbCipher(String algorithmName, int mode, byte[] key) throws Exception { + Cipher cipher = Cipher.getInstance(algorithmName, BouncyCastleProvider.PROVIDER_NAME); + Key sm4Key = new SecretKeySpec(key, ALGORITHM_NAME); + cipher.init(mode, sm4Key); + return cipher; + } + + /** + * 自动生成密钥 + * @explain + * @return + * @throws NoSuchAlgorithmException + * @throws NoSuchProviderException + */ + public static byte[] generateKey() throws Exception { + return generateKey(DEFAULT_KEY_SIZE); + } + + + //加密****************************************** + /** + * @explain 系统产生秘钥 + * @param keySize + * @return + * @throws Exception + */ + public static byte[] generateKey(int keySize) throws Exception { + KeyGenerator kg = KeyGenerator.getInstance(ALGORITHM_NAME, BouncyCastleProvider.PROVIDER_NAME); + kg.init(keySize, new SecureRandom()); + return kg.generateKey().getEncoded(); + } + + /** + * sm4加密 + * @explain 加密模式:ECB 密文长度不固定,会随着被加密字符串长度的变化而变化 + * @param + * @param paramStr 待加密字符串 + * @return 返回16进制的加密字符串 + * @throws Exception + */ + public static String encryptEcb(String paramStr) throws Exception { + String cipherText = ""; + // 16进制字符串-->byte[] + byte[] keyData = ByteUtils.fromHexString(hexKey); + // String-->byte[] + byte[] srcData = paramStr.getBytes(ENCODING); + // 加密后的数组 + byte[] cipherArray = encrypt_Ecb_Padding(keyData, srcData); + // byte[]-->hexString + cipherText = ByteUtils.toHexString(cipherArray); + return cipherText; + } + + /** + * 加密模式之Ecb + * @param key + * @param data + * @return + * @throws Exception + */ + public static byte[] encrypt_Ecb_Padding(byte[] key, byte[] data) throws Exception { + Cipher cipher = generateEcbCipher(ALGORITHM_NAME_ECB_PADDING, Cipher.ENCRYPT_MODE, key);//声称Ecb暗号,通过第二个参数判断加密还是解密 + return cipher.doFinal(data); + } + + //解密**************************************** + /** + * sm4解密 + * @explain 解密模式:采用ECB + * @param + * @param cipherText 16进制的加密字符串(忽略大小写) + * @return 解密后的字符串 + * @throws Exception + */ + public static String decryptEcb(String cipherText) throws Exception { + // 用于接收解密后的字符串 + String decryptStr = ""; + // hexString-->byte[] + byte[] keyData = ByteUtils.fromHexString(hexKey); + // hexString-->byte[] + byte[] cipherData = ByteUtils.fromHexString(cipherText); + // 解密 + byte[] srcData = decrypt_Ecb_Padding(keyData, cipherData); + // byte[]-->String + decryptStr = new String(srcData, ENCODING); + return decryptStr; + } + + /** + * 解密 + * @explain + * @param key + * @param cipherText + * @return + * @throws Exception + */ + public static byte[] decrypt_Ecb_Padding(byte[] key, byte[] cipherText) throws Exception { + Cipher cipher = generateEcbCipher(ALGORITHM_NAME_ECB_PADDING, Cipher.DECRYPT_MODE, key);//生成Ecb暗号,通过第二个参数判断加密还是解密 + return cipher.doFinal(cipherText); + } + + /** + * 校验加密前后的字符串是否为同一数据 + * @explain + * @param + * @param cipherText 16进制加密后的字符串 + * @param paramStr 加密前的字符串 + * @return 是否为同一数据 + * @throws Exception + */ + public static boolean verifyEcb(String cipherText, String paramStr) throws Exception { + // 用于接收校验结果 + boolean flag = false; + // hexString-->byte[] + byte[] keyData = ByteUtils.fromHexString(hexKey); + // 将16进制字符串转换成数组 + byte[] cipherData = ByteUtils.fromHexString(cipherText); + // 解密 + byte[] decryptData = decrypt_Ecb_Padding(keyData, cipherData); + // 将原字符串转换成byte[] + byte[] srcData = paramStr.getBytes(ENCODING); + // 判断2个数组是否一致 + flag = Arrays.equals(decryptData, srcData); + return flag; + } + +} diff --git a/hyp-framework/src/main/java/com/hyp/framework/config/SecurityConfig.java b/hyp-framework/src/main/java/com/hyp/framework/config/SecurityConfig.java index d824481..389ca33 100644 --- a/hyp-framework/src/main/java/com/hyp/framework/config/SecurityConfig.java +++ b/hyp-framework/src/main/java/com/hyp/framework/config/SecurityConfig.java @@ -111,7 +111,7 @@ public class SecurityConfig extends WebSecurityConfigurerAdapter // 过滤请求 .authorizeRequests() // 对于登录login 注册register 滑块验证码/captcha/get /captcha/check 获取验证码开关 /captchaEnabled 允许匿名访问 - .antMatchers("/login", "/register", "/captcha/get", "/captcha/check", "/captchaEnabled","/system/dict/data/type/**").permitAll() + .antMatchers("/login", "/register", "/captcha/get", "/captcha/check", "/captchaEnabled","/publicKey","/system/dict/data/type/**").permitAll() // 静态资源,可匿名访问 .antMatchers(HttpMethod.GET, "/", "/*.html", "/**/*.html", "/**/*.css", "/**/*.js", "/profile/**").permitAll() .antMatchers("/swagger-ui.html", "/swagger-resources/**", "/webjars/**", "/*/api-docs", "/druid/**").permitAll() diff --git a/hyp-framework/src/main/java/com/hyp/framework/web/service/SysRegisterService.java b/hyp-framework/src/main/java/com/hyp/framework/web/service/SysRegisterService.java index ad67523..520e9a9 100644 --- a/hyp-framework/src/main/java/com/hyp/framework/web/service/SysRegisterService.java +++ b/hyp-framework/src/main/java/com/hyp/framework/web/service/SysRegisterService.java @@ -1,6 +1,7 @@ package com.hyp.framework.web.service; import com.hyp.common.core.domain.entity.SysRole; +import com.hyp.common.utils.sign.Sm4Util; import com.hyp.system.domain.SysUserRole; import com.hyp.system.mapper.SysUserRoleMapper; import com.hyp.system.service.ISysRoleService; @@ -55,8 +56,8 @@ public class SysRegisterService * 注册 */ @Transactional(rollbackFor = Exception.class) - public String register(RegisterBody registerBody) { - String msg = "", username = registerBody.getUsername(), password = registerBody.getPassword(); + public String register(RegisterBody registerBody) throws Exception { + String msg = "", username = registerBody.getUsername(), password = Sm4Util.decryptEcb(registerBody.getPassword()); SysUser sysUser = new SysUser(); sysUser.setUserName(username);