commit
This commit is contained in:
@@ -41,15 +41,11 @@ import javax.servlet.http.HttpServletResponse;
|
||||
import javax.servlet.http.HttpSession;
|
||||
import java.net.URLEncoder;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.security.KeyFactory;
|
||||
import java.security.KeyPair;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.security.PrivateKey;
|
||||
import java.security.spec.InvalidKeySpecException;
|
||||
import java.security.spec.PKCS8EncodedKeySpec;
|
||||
import java.util.Base64;
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
|
||||
@IocBean
|
||||
@@ -58,6 +54,11 @@ import java.util.UUID;
|
||||
@Api(tags = "登录")
|
||||
public class SysLoginController {
|
||||
private static final Log log = Logs.get();
|
||||
private static final LoginRsaKeyRing LOGIN_RSA_KEY_RING = new LoginRsaKeyRing();
|
||||
/**
|
||||
* TODO: 临时屏蔽 localhost 平台登录验证码,恢复时改为 false。
|
||||
*/
|
||||
private static final boolean DISABLE_LOGIN_CAPTCHA = true;
|
||||
@Inject
|
||||
private SysUserService sysUserService;
|
||||
@Inject
|
||||
@@ -123,14 +124,20 @@ public class SysLoginController {
|
||||
}
|
||||
try {
|
||||
// 验证码校验
|
||||
try {
|
||||
validateService.checkCode(captchaKey, captchaCode);
|
||||
} catch (BaseException e) {
|
||||
return Result.error(e.getMessage());
|
||||
if (!isLoginCaptchaDisabled(req)) {
|
||||
try {
|
||||
validateService.checkCode(captchaKey, captchaCode);
|
||||
} catch (BaseException e) {
|
||||
return Result.error(e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
// 解密密码
|
||||
String decryptPwd = validateService.decryptPwd(keyId, password);
|
||||
LoginRsaKey rsaKey = LOGIN_RSA_KEY_RING.getPrivateKey(keyId);
|
||||
if (rsaKey == null) {
|
||||
throw new BaseException("Login key expired, please refresh the login page");
|
||||
}
|
||||
String decryptPwd = RsaUtils.decrypt(password, rsaKey.privateKey);
|
||||
if (decryptPwd == null) {
|
||||
throw new BaseException("用户登录失败");
|
||||
}
|
||||
@@ -153,6 +160,17 @@ public class SysLoginController {
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isLoginCaptchaDisabled(HttpServletRequest req) {
|
||||
if (!DISABLE_LOGIN_CAPTCHA || req == null) {
|
||||
return false;
|
||||
}
|
||||
String serverName = req.getServerName();
|
||||
return "localhost".equalsIgnoreCase(serverName)
|
||||
|| "127.0.0.1".equals(serverName)
|
||||
|| "0:0:0:0:0:0:0:1".equals(serverName)
|
||||
|| "::1".equals(serverName);
|
||||
}
|
||||
|
||||
@At(value = "/platform/sso/login", top = true)
|
||||
@Ok("re")
|
||||
@ApiOperation("用户cas登录统一入口")
|
||||
@@ -267,25 +285,89 @@ public class SysLoginController {
|
||||
@ApiOperation("获取公钥")
|
||||
public Object publicKey() {
|
||||
try {
|
||||
// 生成密钥对
|
||||
KeyPair keyPair = RsaUtils.generateKeyPair();
|
||||
String publicKeyStr = RsaUtils.getPublicKeyBase64(keyPair.getPublic());
|
||||
String privateKeyStr = RsaUtils.getPrivateKeyBase64(keyPair.getPrivate());
|
||||
|
||||
// 生成 UUID 作为 keyId
|
||||
String keyId = UUID.randomUUID().toString().replace("-", "");
|
||||
|
||||
// 私钥存入 Redis,5 分钟过期,也防止恶意刷密钥
|
||||
redisService.setex(RedisConstant.RSA_KEY_PREFIX + keyId, 5 * 60, privateKeyStr);
|
||||
|
||||
// 返回给前端
|
||||
LoginRsaKey rsaKey = LOGIN_RSA_KEY_RING.currentKey();
|
||||
return Result.success(Map.of(
|
||||
"publicKey", publicKeyStr,
|
||||
"keyId", keyId
|
||||
"publicKey", rsaKey.publicKey,
|
||||
"keyId", rsaKey.keyId,
|
||||
"expireAt", rsaKey.encryptExpireAt
|
||||
));
|
||||
} catch (Exception e) {
|
||||
log.error("生成 RSA 密钥失败", e);
|
||||
return Result.error("系统异常");
|
||||
}
|
||||
}
|
||||
|
||||
private static class LoginRsaKeyRing {
|
||||
private static final long ACTIVE_MILLIS = 30 * 60 * 1000L;
|
||||
private static final long DECRYPT_GRACE_MILLIS = 10 * 60 * 1000L;
|
||||
private final ConcurrentHashMap<String, LoginRsaKey> keys = new ConcurrentHashMap<>();
|
||||
private volatile LoginRsaKey current;
|
||||
|
||||
LoginRsaKey currentKey() throws Exception {
|
||||
long now = System.currentTimeMillis();
|
||||
LoginRsaKey key = current;
|
||||
if (key != null && now < key.encryptExpireAt) {
|
||||
return key;
|
||||
}
|
||||
synchronized (this) {
|
||||
key = current;
|
||||
now = System.currentTimeMillis();
|
||||
if (key == null || now >= key.encryptExpireAt) {
|
||||
key = generateKey(now);
|
||||
current = key;
|
||||
keys.put(key.keyId, key);
|
||||
cleanup(now);
|
||||
}
|
||||
return key;
|
||||
}
|
||||
}
|
||||
|
||||
LoginRsaKey getPrivateKey(String keyId) {
|
||||
if (StrUtil.isBlank(keyId)) {
|
||||
return null;
|
||||
}
|
||||
long now = System.currentTimeMillis();
|
||||
LoginRsaKey key = keys.get(keyId);
|
||||
if (key == null) {
|
||||
return null;
|
||||
}
|
||||
if (now >= key.decryptExpireAt) {
|
||||
keys.remove(keyId);
|
||||
return null;
|
||||
}
|
||||
return key;
|
||||
}
|
||||
|
||||
private LoginRsaKey generateKey(long now) throws Exception {
|
||||
KeyPair keyPair = RsaUtils.generateKeyPair();
|
||||
String keyId = UUID.randomUUID().toString().replace("-", "");
|
||||
return new LoginRsaKey(
|
||||
keyId,
|
||||
RsaUtils.getPublicKeyBase64(keyPair.getPublic()),
|
||||
keyPair.getPrivate(),
|
||||
now + ACTIVE_MILLIS,
|
||||
now + ACTIVE_MILLIS + DECRYPT_GRACE_MILLIS
|
||||
);
|
||||
}
|
||||
|
||||
private void cleanup(long now) {
|
||||
keys.entrySet().removeIf(entry -> now >= entry.getValue().decryptExpireAt);
|
||||
}
|
||||
}
|
||||
|
||||
private static class LoginRsaKey {
|
||||
private final String keyId;
|
||||
private final String publicKey;
|
||||
private final PrivateKey privateKey;
|
||||
private final long encryptExpireAt;
|
||||
private final long decryptExpireAt;
|
||||
|
||||
private LoginRsaKey(String keyId, String publicKey, PrivateKey privateKey, long encryptExpireAt, long decryptExpireAt) {
|
||||
this.keyId = keyId;
|
||||
this.publicKey = publicKey;
|
||||
this.privateKey = privateKey;
|
||||
this.encryptExpireAt = encryptExpireAt;
|
||||
this.decryptExpireAt = decryptExpireAt;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+5
-45
@@ -25,7 +25,6 @@ import org.nutz.dao.util.cri.SqlExpressionGroup;
|
||||
import org.nutz.ioc.aop.Aop;
|
||||
import org.nutz.ioc.loader.annotation.Inject;
|
||||
import org.nutz.ioc.loader.annotation.IocBean;
|
||||
import org.nutz.lang.Strings;
|
||||
import org.nutz.mvc.annotation.At;
|
||||
import org.nutz.mvc.annotation.Ok;
|
||||
|
||||
@@ -69,15 +68,11 @@ public class TeacherCongressInstitutionController {
|
||||
Teacher_congress_institution rootInstitution = new Teacher_congress_institution();
|
||||
rootInstitution.setId("0");
|
||||
rootInstitution.setParentId("");
|
||||
rootInstitution.setName("两代会组织机构");
|
||||
rootInstitution.setName("教代会机构");
|
||||
rootInstitution.setLocation(0);
|
||||
institutionList.add(rootInstitution);
|
||||
|
||||
List<TreeNode<String>> treeNodes = institutionList.stream().map(institution -> {
|
||||
TreeNode<String> treeNode = new TreeNode<>(institution.getId(), institution.getParentId(), institution.getName(), institution.getLocation());
|
||||
treeNode.setExtra(Map.of("code", Strings.sNull(institution.getCode())));
|
||||
return treeNode;
|
||||
}).toList();
|
||||
List<TreeNode<String>> treeNodes = institutionList.stream().map(institution -> new TreeNode<>(institution.getId(), institution.getParentId(), institution.getName(), institution.getLocation())).toList();
|
||||
List<Tree<String>> treeList = TreeUtil.build(treeNodes, "");
|
||||
return Result.success(treeList);
|
||||
}
|
||||
@@ -102,16 +97,6 @@ public class TeacherCongressInstitutionController {
|
||||
return Result.success(Map.of("treeFlat", children, "treeList", treeList));
|
||||
}
|
||||
|
||||
@At
|
||||
@SaCheckPermission("tc.institution")
|
||||
public Result specialCommitteeRoleOptions() {
|
||||
Sys_dict parent = sysDictService.fetch(Cnd.where(Sys_dict::getCode, "=", "SPECIAL_COMMITTEE_ROLES"));
|
||||
if (ObjectUtil.isEmpty(parent)) {
|
||||
return Result.success(List.of());
|
||||
}
|
||||
List<Sys_dict> children = sysDictService.query(Cnd.where(Sys_dict::getPath, "like", parent.getPath() + "%").and(Sys_dict::getId, "!=", parent.getId()).asc(Sys_dict::getLocation));
|
||||
return Result.success(children);
|
||||
}
|
||||
|
||||
/**
|
||||
* 机构分页查询
|
||||
@@ -128,7 +113,6 @@ public class TeacherCongressInstitutionController {
|
||||
cnd.and("parentId", "=", parentId);
|
||||
cnd.and("sessionId", "=", sessionId);
|
||||
cnd.asc("location");
|
||||
cnd.asc("code");
|
||||
Pagination pagination = baseService.listPage(pageForm.getPageNumber(), pageForm.getPageSize(), "teacher_congress_institution", cnd);
|
||||
return Result.success(pagination);
|
||||
}
|
||||
@@ -145,7 +129,7 @@ public class TeacherCongressInstitutionController {
|
||||
if (dao.count(Teacher_congress_institution.class, Cnd.where(Teacher_congress_institution::getCode, "=", institution.getCode()).and(Teacher_congress_institution::getSessionId, "=", institution.getSessionId())) > 0) {
|
||||
return Result.error("机构已存在");
|
||||
}
|
||||
if (StrUtil.isNotBlank(institution.getParentId()) && !institution.getParentId().equals("0") && dao.count(Teacher_congress_institution.class, Cnd.where(Teacher_congress_institution::getId, "=", institution.getParentId()).and(Teacher_congress_institution::getSessionId, "=", institution.getSessionId())) == 0) {
|
||||
if (StrUtil.isNotBlank(institution.getParentId()) && !institution.getParentId().equals("0")) {
|
||||
Sys_dict sysDict = sysDictService.fetch(Cnd.where(Sys_dict::getId, "=", institution.getParentId()));
|
||||
Teacher_congress_institution parentInstitution = dao.fetch(Teacher_congress_institution.class,
|
||||
Cnd.where(Teacher_congress_institution::getCode, "=", sysDict.getCode())
|
||||
@@ -167,34 +151,10 @@ public class TeacherCongressInstitutionController {
|
||||
* @param id
|
||||
* @return
|
||||
*/
|
||||
@At
|
||||
@SaCheckPermission("tc.institution")
|
||||
public Result update(Teacher_congress_institution institution) {
|
||||
Teacher_congress_institution dbInstitution = dao.fetch(Teacher_congress_institution.class, institution.getId());
|
||||
if (ObjectUtil.isEmpty(dbInstitution)) {
|
||||
return Result.error("机构不存在");
|
||||
}
|
||||
dbInstitution.setName(institution.getName());
|
||||
dbInstitution.setIntroduce(institution.getIntroduce());
|
||||
dbInstitution.setLocation(institution.getLocation());
|
||||
dao.update(dbInstitution);
|
||||
return Result.success();
|
||||
}
|
||||
|
||||
@At
|
||||
@SaCheckPermission("tc.institution")
|
||||
@Aop(TransAop.READ_COMMITTED)
|
||||
public Result delete(@Valid String id) {
|
||||
Teacher_congress_institution institution = dao.fetch(Teacher_congress_institution.class, id);
|
||||
if (ObjectUtil.isEmpty(institution)) {
|
||||
return Result.error("机构不存在");
|
||||
}
|
||||
List<Teacher_congress_institution> siblingList = dao.query(Teacher_congress_institution.class, Cnd.where(Teacher_congress_institution::getParentId, "=", institution.getParentId()).and(Teacher_congress_institution::getSessionId, "=", institution.getSessionId()).asc(Teacher_congress_institution::getLocation).asc(Teacher_congress_institution::getCode));
|
||||
for (int i = 0; i < siblingList.size() && i < 6; i++) {
|
||||
if (id.equals(siblingList.get(i).getId())) {
|
||||
return Result.error("你选择的组织机构是两代会基本机构,不允许删除。");
|
||||
}
|
||||
}
|
||||
dao.delete(Teacher_congress_institution.class, id);
|
||||
dao.clear(Teacher_congress_institution_user.class, Cnd.where("institutionId", "=", id));
|
||||
return Result.success();
|
||||
@@ -254,8 +214,8 @@ public class TeacherCongressInstitutionController {
|
||||
@SaCheckPermission("tc.institution")
|
||||
@SLog(tag = "教代会-机构设置", msg = "添加人员")
|
||||
@Aop(TransAop.READ_COMMITTED)
|
||||
public Result userInsert(@Valid String userId, @Valid String institutionId, @Valid String sessionId, @Valid String identity, String roleCode) {
|
||||
teacherCongressInstitutionUserService.userInsert(userId, institutionId, sessionId, identity, roleCode);
|
||||
public Result userInsert(@Valid String userId, @Valid String institutionId, @Valid String sessionId, @Valid String identity) {
|
||||
teacherCongressInstitutionUserService.userInsert(userId, institutionId, sessionId, identity);
|
||||
return Result.success();
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -14,7 +14,7 @@ public interface TeacherCongressInstitutionUserService extends BaseService<Teach
|
||||
* @param sessionId 届次id
|
||||
* @param identity 身份 主任|副主任|成员
|
||||
*/
|
||||
void userInsert(String userId, String institutionId, String sessionId, String identity, String roleCode);
|
||||
void userInsert(String userId, String institutionId, String sessionId, String identity);
|
||||
|
||||
/**
|
||||
* 删除机构成员
|
||||
|
||||
+1
-24
@@ -1,6 +1,5 @@
|
||||
package com.budwk.app.zhgh.democratic.teachercongress.institution.service.impl;
|
||||
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import com.budwk.app.base.constant.RoleConstant;
|
||||
import com.budwk.app.base.exception.BaseException;
|
||||
import com.budwk.app.base.service.impl.BaseServiceImpl;
|
||||
@@ -31,7 +30,7 @@ public class TeacherCongressInstitutionUserServiceImpl extends BaseServiceImpl<T
|
||||
|
||||
@Override
|
||||
@Aop(TransAop.READ_COMMITTED)
|
||||
public void userInsert(String userId, String institutionId, String sessionId, String identity, String roleCode) {
|
||||
public void userInsert(String userId, String institutionId, String sessionId, String identity) {
|
||||
int count = dao().count(Teacher_congress_institution_user.class,
|
||||
Cnd.where(Teacher_congress_institution_user::getInstitutionId, "=", institutionId)
|
||||
.and(Teacher_congress_institution_user::getUserId, "=", userId)
|
||||
@@ -50,28 +49,6 @@ public class TeacherCongressInstitutionUserServiceImpl extends BaseServiceImpl<T
|
||||
dao().insert(institutionUser);
|
||||
|
||||
Teacher_congress_institution institution = dao().fetch(Teacher_congress_institution.class, institutionId);
|
||||
if ("ZWH001".equals(institution.getCode()) || "ZXWYH".equals(institution.getCode()) || "DBZGSCXZ".equals(institution.getCode())) {
|
||||
if (StrUtil.isBlank(roleCode)) {
|
||||
throw new BaseException("请选择角色");
|
||||
}
|
||||
Sys_role sysRole = sysRoleService.fetch(Cnd.where(Sys_role::getCode, "=", roleCode));
|
||||
if (sysRole == null) {
|
||||
throw new BaseException("无法找到" + roleCode + "对应编码的角色");
|
||||
}
|
||||
int existsRole = dao().count(Sys_user_role.class, Cnd.where(Sys_user_role::getUserId, "=", userId)
|
||||
.and(Sys_user_role::getTcSessionId, "=", sessionId)
|
||||
.and(Sys_user_role::getRoleId, "=", sysRole.getId())
|
||||
);
|
||||
if (existsRole == 0) {
|
||||
Sys_user_role insertSysUserRole = new Sys_user_role();
|
||||
insertSysUserRole.setRoleId(sysRole.getId());
|
||||
insertSysUserRole.setUserId(userId);
|
||||
insertSysUserRole.setTcSessionId(sessionId);
|
||||
dao().insert(insertSysUserRole);
|
||||
sysRoleService.clearCache();
|
||||
sysUserService.clearCache();
|
||||
}
|
||||
}
|
||||
if (institution.getCode().contains("TEACHER_CONGRESS_INSTITUTION_PROPOSAL_COMMITTEE") && identity.equals("主任")) {
|
||||
Sys_role sysRole = sysRoleService.getByCode(RoleConstant.PROPOSAL_COMMITTEE_DIRECTOR);
|
||||
int existsRole = dao().count(Sys_user_role.class, Cnd.where(Sys_user_role::getUserId, "=", userId)
|
||||
|
||||
Reference in New Issue
Block a user