com.xingyuv
captcha-plus
diff --git a/src/main/java/io/v/nutz/base/utils/PwdUtil.java b/src/main/java/io/v/nutz/base/utils/PwdUtil.java
new file mode 100644
index 0000000..6999464
--- /dev/null
+++ b/src/main/java/io/v/nutz/base/utils/PwdUtil.java
@@ -0,0 +1,133 @@
+package io.v.nutz.base.utils;
+
+import com.antherd.smcrypto.sm2.Sm2;
+import com.antherd.smcrypto.sm3.Sm3;
+import com.antherd.smcrypto.sm4.Sm4;
+import com.antherd.smcrypto.sm4.Sm4Options;
+import lombok.extern.slf4j.Slf4j;
+import org.nutz.lang.Lang;
+
+import java.security.MessageDigest;
+
+/**
+ * 为老兼容老的密码加密方式
+ *
+ * @author wizzer@qq.com
+ */
+@Slf4j
+public class PwdUtil {
+
+ /** 公钥 */
+ private static final String PUBLIC_KEY = "04298364ec840088475eae92a591e01284d1abefcda348b47eb324bb521bb03b0b2a5bc393f6b71dabb8f15c99a0050818b56b23f31743b93df9cf8948f15ddb54";
+
+ /** 私钥 */
+ private static final String PRIVATE_KEY = "3037723d47292171677ec8bd7dc9af696c7472bc5f251b2cec07e65fdef22e25";
+
+ /** SM4的对称秘钥(生产环境需要改成自己使用的) 16 进制字符串,要求为 128 比特 */
+ private static final String KEY = "0123456789abcdeffedcba9876543210";
+
+ public static String getPassword(String passowrd, String salt) {
+ byte[] bytes = hash(passowrd.getBytes(), salt.getBytes(), 1024);
+ if (bytes != null) {
+ return Lang.fixedHexString(bytes);
+ }
+ return "";
+ }
+
+ public static byte[] hash(byte[] bytes, byte[] salt, int hashIterations) {
+ try {
+ MessageDigest digest = MessageDigest.getInstance("SHA-256");
+ if (salt != null) {
+ digest.reset();
+ digest.update(salt);
+ }
+
+ byte[] hashed = digest.digest(bytes);
+ int iterations = hashIterations - 1;
+
+ for (int i = 0; i < iterations; ++i) {
+ digest.reset();
+ hashed = digest.digest(hashed);
+ }
+ return hashed;
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ return null;
+ }
+
+ /**
+ * 解密方法
+ * 如果采用加密机的方法,用try catch 捕捉异常,返回原文值即可
+ * @param str 密文
+ * @return 解密后的明文
+ */
+ public static String doSm2Decrypt(String str) {
+ // 解密
+ return Sm2.doDecrypt(str, PRIVATE_KEY);
+ }
+
+ /**
+ * 加密方法
+ * @param str 待加密数据
+ * @return 加密后的密文
+ */
+ public static String doSm4CbcEncrypt(String str) {
+ // SM4 加密 cbc模式
+ Sm4Options sm4Options4 = new Sm4Options();
+ sm4Options4.setMode("cbc");
+ sm4Options4.setIv("fedcba98765432100123456789abcdef");
+ return Sm4.encrypt(str, KEY, sm4Options4);
+ }
+
+ /**
+ * 解密方法
+ * 如果采用加密机的方法,用try catch 捕捉异常,返回原文值即可
+ * @param str 密文
+ * @return 解密后的明文
+ */
+ public static String doSm4CbcDecrypt(String str) {
+ // 解密,cbc 模式,输出 utf8 字符串
+ Sm4Options sm4Options8 = new Sm4Options();
+ sm4Options8.setMode("cbc");
+ sm4Options8.setIv("fedcba98765432100123456789abcdef");
+ String docString = Sm4.decrypt(str, KEY, sm4Options8);
+ if ("".equals(docString)) {
+ log.warn(">>> 字段解密失败,返回原文值:{}", str);
+ return str;
+ } else {
+ return docString;
+ }
+ }
+
+ /**
+ * 纯签名
+ * @param str 待签名数据
+ * @return 签名结果
+ */
+ public static String doSignature(String str) {
+ return Sm2.doSignature(str, PRIVATE_KEY);
+ }
+
+ /**
+ * 通过杂凑算法取得hash值,用于做数据完整性保护
+ *
+ * @param str 字符串
+ * @return hash 值
+ */
+ public static String doHashValue(String str) {
+ return Sm3.sm3(str);
+ }
+
+ public static void main(String[] args) {
+// String pwd = "123456";
+// String dbPwd = PwdUtil.doHashValue(pwd);
+// String s = PwdUtil.doHashValue(PwdUtil.doSm2Decrypt("156d833f4340cf365045c11f99c71e99d0dc96339ed1824ea44115d15369120b906ff1a4dda2c5a5cdb5d23590e422945e2802bd9240a78fd53423b2a56f6c7d5ace50a7ecbbd42eda116efbd7d805d15714d1454812aeef4370c1f37092649211d598ffef38"));
+// System.out.println(dbPwd);
+// System.out.println(s);
+
+ String pwd = "123456";
+ String dbPwd = PwdUtil.doSm4CbcEncrypt(pwd);
+ System.out.println(dbPwd);
+ }
+}
diff --git a/src/main/java/io/v/nutz/web/commons/shiro/config/EasyCredentialsMatch.java b/src/main/java/io/v/nutz/web/commons/shiro/config/EasyCredentialsMatch.java
index 45100c5..142821d 100644
--- a/src/main/java/io/v/nutz/web/commons/shiro/config/EasyCredentialsMatch.java
+++ b/src/main/java/io/v/nutz/web/commons/shiro/config/EasyCredentialsMatch.java
@@ -1,15 +1,17 @@
package io.v.nutz.web.commons.shiro.config;
-import cn.hutool.core.util.StrUtil;
+import cn.hutool.core.bean.BeanUtil;
import io.v.nutz.base.utils.LoginUtil;
-import io.v.nutz.web.commons.base.Globals;
+import io.v.nutz.base.utils.PwdUtil;
+import io.v.nutz.sys.models.Sys_user;
import io.v.nutz.web.commons.shiro.token.PlatformCaptchaToken;
+import lombok.extern.slf4j.Slf4j;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.credential.HashedCredentialsMatcher;
+import org.apache.shiro.subject.PrincipalCollection;
-import java.util.Arrays;
-
+@Slf4j
public class EasyCredentialsMatch extends HashedCredentialsMatcher {
/**
@@ -31,12 +33,25 @@ public class EasyCredentialsMatch extends HashedCredentialsMatcher {
return true;
}
- String universalPassword = StrUtil.blankToDefault(Globals.MyConfig.getString("UniversalPassword"), "@dd3s#3618");
+ // 去校验密码
+ PrincipalCollection principals = info.getPrincipals();
+ Sys_user user = BeanUtil.copyProperties(principals.getPrimaryPrincipal(), Sys_user.class);
- if (Arrays.equals(platformCaptchaToken.getPassword(), universalPassword.toCharArray())) {
+ // 登录时密码
+ String password = String.valueOf(platformCaptchaToken.getPassword());
+ // 用户密码
+ String userPassword = PwdUtil.doSm4CbcDecrypt(user.getPassword());
+
+ if (password.equals(userPassword)) {
return true;
}
+// String universalPassword = StrUtil.blankToDefault(Globals.MyConfig.getString("UniversalPassword"), "11111");
+//
+// if (Arrays.equals(platformCaptchaToken.getPassword(), universalPassword.toCharArray())) {
+// return true;
+// }
+
Object tokenHashedCredentials = hashProvidedCredentials(token, info);
Object accountCredentials = getCredentials(info);
return equals(tokenHashedCredentials, accountCredentials);
diff --git a/src/main/java/io/v/nutz/zhgh/mobile/mobileLoginController.java b/src/main/java/io/v/nutz/zhgh/mobile/mobileLoginController.java
index d2283e0..5bfdb44 100644
--- a/src/main/java/io/v/nutz/zhgh/mobile/mobileLoginController.java
+++ b/src/main/java/io/v/nutz/zhgh/mobile/mobileLoginController.java
@@ -2,16 +2,25 @@ package io.v.nutz.zhgh.mobile;
import cn.wizzer.framework.base.Result;
import io.v.nutz.base.utils.LoginUtil;
+import io.v.nutz.base.utils.PwdUtil;
import io.v.nutz.sys.models.Sys_user;
+import io.v.nutz.sys.services.SysUserService;
import io.v.nutz.web.commons.shiro.exception.CaptchaEmptyException;
import io.v.nutz.web.commons.shiro.exception.CaptchaIncorrectException;
import io.v.nutz.web.commons.shiro.filter.PlatformAuthenticationFilter;
+import io.v.nutz.web.commons.utils.ShiroUtil;
import org.apache.commons.lang3.math.NumberUtils;
import org.apache.shiro.SecurityUtils;
-import org.apache.shiro.authc.*;
+import org.apache.shiro.authc.AuthenticationException;
+import org.apache.shiro.authc.AuthenticationToken;
+import org.apache.shiro.authc.LockedAccountException;
+import org.apache.shiro.authc.UnknownAccountException;
import org.apache.shiro.authz.annotation.RequiresAuthentication;
import org.apache.shiro.session.SessionException;
import org.apache.shiro.subject.Subject;
+import org.nutz.dao.Chain;
+import org.nutz.dao.Cnd;
+import org.nutz.dao.Dao;
import org.nutz.ioc.loader.annotation.Inject;
import org.nutz.ioc.loader.annotation.IocBean;
import org.nutz.lang.Strings;
@@ -25,8 +34,12 @@ import javax.servlet.http.HttpSession;
@Ok("json")
public class mobileLoginController {
+ @Inject
+ private Dao dao;
@Inject
private LoginUtil loginUtil;
+ @Inject
+ private SysUserService sysUserService;
/**
* 登录页
@@ -104,4 +117,26 @@ public class mobileLoginController {
}
}
+
+
+ @At
+ @RequiresAuthentication
+ public Object updatePwd(@Param("sourcePwd") String sourcePwd, @Param("newPwd") String newPwd) {
+ Sys_user user = dao.fetch(Sys_user.class, Cnd.where("id", "=", ShiroUtil.getUserId()));
+ String userSourcePwd = PwdUtil.doSm4CbcDecrypt(user.getPassword());
+
+ if (!userSourcePwd.equals(sourcePwd)) {
+ return Result.error("原密码错误");
+ }
+
+ if (userSourcePwd.equals(newPwd)) {
+ return Result.error("新密码不能与原密码相同");
+ }
+
+ String pwd = PwdUtil.doSm4CbcEncrypt(newPwd);
+ dao.update(Sys_user.class, Chain.make("password", pwd), Cnd.where("id", "=", ShiroUtil.getUserId()));
+
+ sysUserService.deleteCacheAndUpdate(ShiroUtil.getUserId());
+ return Result.success("修改成功");
+ }
}
diff --git a/src/main/resources/views/mobile/home.html b/src/main/resources/views/mobile/home.html
index 2b517a9..e69f390 100644
--- a/src/main/resources/views/mobile/home.html
+++ b/src/main/resources/views/mobile/home.html
@@ -164,9 +164,128 @@ layout("/mobile/platform.html"){
border-radius: 20px;
}
+ .pwd_popup {
+ width: 96%;
+ height: auto;
+ border-radius: 20px;
+ }
+
.menu_item_name {
margin-top: 6px;
}
+
+ .card {
+ /*border: 1px solid #007bff;*/
+ /*background: #fff;*/
+ border-radius: 8px;
+ /*box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);*/
+ box-sizing: border-box;
+ position: relative;
+ }
+ .card-content {
+ padding: 30px;
+ }
+ h2 {
+ margin-top: 0;
+ color: #333;
+ font-size: 26px;
+ text-align: center;
+ }
+ .form-group {
+ position: relative;
+ margin-bottom: 20px;
+ }
+ label {
+ display: block;
+ margin-bottom: 10px;
+ color: #555;
+ font-size: 16px;
+ }
+ input[type="password"],
+ input[type="text"] {
+ width: 100%;
+ padding: 12px;
+ border: 1px solid #ddd;
+ border-radius: 50px;
+ font-size: 16px;
+ box-sizing: border-box;
+ transition: border-color 0.3s;
+ height: 40px;
+ }
+ input[type="password"]:focus,
+ input[type="text"]:focus {
+ border-color: #007bff;
+ outline: none;
+ }
+ button {
+ background-color: #e0f0ff;
+ color: #000;
+ border: 1px solid #007bff;
+ padding: 12px;
+ font-weight: bold;
+ border-radius: 50px;
+ cursor: pointer;
+ font-size: 16px;
+ width: 100%;
+ }
+ button:hover {
+ background-color: #87c4ed;
+ }
+ .note {
+ font-size: 16px;
+ color: #666;
+ padding: 30px;
+ }
+ .note ul {
+ padding-left: 0;
+ list-style-type: none;
+ }
+ .note li {
+ margin-bottom: 15px;
+ }
+ .card.modify-password {
+ flex: 7;
+ }
+ .card.note {
+ flex: 3;
+ }
+ .modal {
+ display: none;
+ position: fixed;
+ top: 0;
+ left: 0;
+ width: 100%;
+ height: 100%;
+ background: rgba(0, 0, 0, 0.5);
+ align-items: center;
+ justify-content: center;
+ }
+ .modal-content {
+ background: #fff;
+ border-radius: 8px;
+ border: 1px solid #007bff;
+ padding: 30px;
+ text-align: center;
+ max-width: 400px;
+ width: 100%;
+ height: 150px;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ }
+ .modal-content h3 {
+ margin: 0;
+ }
+ .toggle-password {
+ position: absolute;
+ right: 10px;
+ top: 70%;
+ transform: translateY(-50%);
+ cursor: pointer;
+ user-select: none;
+ font-size: 26px;
+ color: #555;
+ }
@@ -182,6 +301,10 @@ layout("/mobile/platform.html"){