mirror of
http://192.168.1.205:9980/cf_devdept2/cf_imes_server.git
synced 2026-08-12 21:02:08 +08:00
1、移除登录地址位置检查;2、登录登出增加地理位置入库;3、组织机构支持省市县持久化和查询;4、permission-info增加返回ip、地域、组织有效期;
This commit is contained in:
+27
-4
@@ -8,6 +8,8 @@ import com.cf.imes.framework.common.exception.ServiceException;
|
||||
import com.cf.imes.framework.common.exception.enums.GlobalErrorCodeConstants;
|
||||
import com.cf.imes.framework.common.pojo.CommonResult;
|
||||
import com.cf.imes.framework.common.validation.Mobile;
|
||||
import com.cf.imes.framework.ip.core.service.IPQueryService;
|
||||
import com.cf.imes.framework.ip.core.service.dto.IPQueryDataRespDTO;
|
||||
import com.cf.imes.framework.operatelog.core.annotations.OperateLog;
|
||||
import com.cf.imes.framework.security.config.SecurityProperties;
|
||||
import com.cf.imes.framework.security.core.LoginUser;
|
||||
@@ -18,11 +20,13 @@ import com.cf.imes.module.system.controller.admin.auth.vo.AuthLoginSmsCheckReqVO
|
||||
import com.cf.imes.module.system.controller.admin.auth.vo.AuthPermissionInfoRespVO;
|
||||
import com.cf.imes.module.system.controller.admin.auth.vo.AuthSocialLoginReqVO;
|
||||
import com.cf.imes.module.system.convert.auth.AuthConvert;
|
||||
import com.cf.imes.module.system.dal.dataobject.organ.OrganizationDO;
|
||||
import com.cf.imes.module.system.dal.dataobject.permission.MenuDO;
|
||||
import com.cf.imes.module.system.dal.dataobject.permission.RoleDO;
|
||||
import com.cf.imes.module.system.dal.dataobject.user.AdminUserDO;
|
||||
import com.cf.imes.module.system.enums.logger.LoginLogTypeEnum;
|
||||
import com.cf.imes.module.system.service.auth.AdminAuthService;
|
||||
import com.cf.imes.module.system.service.organ.OrganService;
|
||||
import com.cf.imes.module.system.service.permission.MenuService;
|
||||
import com.cf.imes.module.system.service.permission.PermissionService;
|
||||
import com.cf.imes.module.system.service.permission.RoleService;
|
||||
@@ -39,6 +43,7 @@ import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.ibatis.annotations.Param;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
@@ -81,12 +86,23 @@ public class AuthController {
|
||||
@Resource
|
||||
private SmsCodeService smsCodeService;
|
||||
|
||||
@Resource
|
||||
private OrganService organService;
|
||||
|
||||
@Resource
|
||||
private IPQueryService ipQueryService;
|
||||
|
||||
/**
|
||||
* ip服务开关,默认为 false不开启
|
||||
*/
|
||||
@Value("${chenfeng.ipquery.enable:false}")
|
||||
private boolean ipQueryEnable;
|
||||
|
||||
@PostMapping("/login")
|
||||
@PermitAll
|
||||
@Operation(summary = "使用账号密码登录")
|
||||
@OperateLog(enable = false) // 避免 Post 请求被记录操作日志
|
||||
public CommonResult<AuthLoginRespVO> login(@Valid @RequestBody AuthLoginReqVO reqVO, HttpServletRequest request) {
|
||||
reqVO.setIp(getClientIP(request));
|
||||
return success(authService.login(reqVO));
|
||||
}
|
||||
|
||||
@@ -132,7 +148,7 @@ public class AuthController {
|
||||
|
||||
@GetMapping("/get-permission-info")
|
||||
@Operation(summary = "获取登录用户的权限信息")
|
||||
public CommonResult<AuthPermissionInfoRespVO> getPermissionInfo() {
|
||||
public CommonResult<AuthPermissionInfoRespVO> getPermissionInfo(HttpServletRequest request) {
|
||||
LoginUser loginUser = SecurityFrameworkUtils.getLoginUser();
|
||||
if (ObjectUtil.isNull(loginUser)) {
|
||||
throw new ServiceException(GlobalErrorCodeConstants.UNAUTHORIZED);
|
||||
@@ -143,11 +159,18 @@ public class AuthController {
|
||||
if (user == null) {
|
||||
return null;
|
||||
}
|
||||
// 获取机构的有效期
|
||||
OrganizationDO organizationDO = organService.validOrgan(user.getOrganId());
|
||||
IPQueryDataRespDTO ipQueryDataRespDTO = null;
|
||||
if (ipQueryService.serviceEnable()) {
|
||||
// 从ip获取地域信息
|
||||
ipQueryDataRespDTO = ipQueryService.querySource(getClientIP(request));
|
||||
}
|
||||
|
||||
// 1.2 获得角色列表
|
||||
Set<Long> roleIds = permissionService.getUserRoleIdListByUserId(userId);
|
||||
if (CollUtil.isEmpty(roleIds)) {
|
||||
return success(AuthConvert.INSTANCE.convert(user, Collections.emptyList(), Collections.emptyList()));
|
||||
return success(AuthConvert.INSTANCE.convert(user, organizationDO, ipQueryDataRespDTO, Collections.emptyList(), Collections.emptyList()));
|
||||
}
|
||||
List<RoleDO> roles = roleService.getRoleList1(roleIds);
|
||||
roles.removeIf(role -> !CommonStatusEnum.ENABLE.getStatus().equals(role.getStatus())); // 移除禁用的角色
|
||||
@@ -158,7 +181,7 @@ public class AuthController {
|
||||
menuList.removeIf(menu -> !CommonStatusEnum.ENABLE.getStatus().equals(menu.getStatus())); // 移除禁用的菜单
|
||||
|
||||
// 2. 拼接结果返回
|
||||
return success(AuthConvert.INSTANCE.convert(user, roles, menuList));
|
||||
return success(AuthConvert.INSTANCE.convert(user, organizationDO, ipQueryDataRespDTO, roles, menuList));
|
||||
}
|
||||
|
||||
// ========== 短信登录相关 ==========
|
||||
|
||||
-3
@@ -51,9 +51,6 @@ public class AuthLoginReqVO {
|
||||
@Schema(description = "state", requiredMode = Schema.RequiredMode.REQUIRED, example = "9b2ffbc1-7425-4155-9894-9d5c08541d62")
|
||||
private String socialState;
|
||||
|
||||
@Schema(hidden = true)
|
||||
private String ip;
|
||||
|
||||
/**
|
||||
* 开启验证码的 Group
|
||||
*/
|
||||
|
||||
+10
@@ -6,6 +6,7 @@ import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
@@ -49,6 +50,15 @@ public class AuthPermissionInfoRespVO {
|
||||
|
||||
@Schema(description = "是否需要设置密码")
|
||||
private boolean needSetPwd;
|
||||
|
||||
@Schema(description = "ip地址")
|
||||
private String ip;
|
||||
|
||||
@Schema(description = "所属区域")
|
||||
private String region;
|
||||
|
||||
@Schema(description = "有效期限")
|
||||
private LocalDateTime expireTime;
|
||||
}
|
||||
|
||||
@Schema(description = "管理后台 - 登录用户的菜单信息 Response VO")
|
||||
|
||||
+4
@@ -54,4 +54,8 @@ public class LoginLogRespVO {
|
||||
@ExcelProperty("登录时间")
|
||||
private LocalDateTime createTime;
|
||||
|
||||
@Schema(description = "所属地区")
|
||||
@ExcelProperty("所属地区")
|
||||
private String region;
|
||||
|
||||
}
|
||||
|
||||
+15
@@ -40,10 +40,25 @@ public class OrganPageReqVO extends PageParam {
|
||||
/**
|
||||
* 拼音首字母
|
||||
*/
|
||||
@Schema(hidden = true)
|
||||
private String pyFirstChar;
|
||||
|
||||
/**
|
||||
* 全拼
|
||||
*/
|
||||
@Schema(hidden = true)
|
||||
private String pyAll;
|
||||
|
||||
@Schema(description = "省")
|
||||
@Size(max = 64, message = "省名称长度不能超过64个字符")
|
||||
private String province;
|
||||
|
||||
@Schema(description = "市")
|
||||
@Size(max = 64, message = "市名称长度不能超过64个字符")
|
||||
private String city;
|
||||
|
||||
@Schema(description = "区")
|
||||
@Size(max = 64, message = "区名称长度不能超过64个字符")
|
||||
private String county;
|
||||
|
||||
}
|
||||
|
||||
+24
@@ -65,4 +65,28 @@ public class OrganRespVO {
|
||||
@ExcelProperty("备注")
|
||||
private String remark;
|
||||
|
||||
@Schema(description = "省")
|
||||
@ExcelProperty("省")
|
||||
private String province;
|
||||
|
||||
@Schema(description = "市")
|
||||
@ExcelProperty("市")
|
||||
private String city;
|
||||
|
||||
@Schema(description = "区")
|
||||
@ExcelProperty("区")
|
||||
private String county;
|
||||
|
||||
@Schema(description = "地区编码")
|
||||
@ExcelProperty("地区编码")
|
||||
private String areaCode;
|
||||
|
||||
@Schema(description = "经度")
|
||||
@ExcelProperty("经度")
|
||||
private String longitude;
|
||||
|
||||
@Schema(description = "纬度")
|
||||
@ExcelProperty("纬度")
|
||||
private String latitude;
|
||||
|
||||
}
|
||||
|
||||
+9
-2
@@ -1,6 +1,8 @@
|
||||
package com.cf.imes.module.system.convert.auth;
|
||||
|
||||
import cn.hutool.core.collection.CollUtil;
|
||||
import cn.hutool.core.util.ObjectUtil;
|
||||
import com.cf.imes.framework.ip.core.service.dto.IPQueryDataRespDTO;
|
||||
import com.cf.imes.module.system.api.sms.dto.code.SmsCodeSendReqDTO;
|
||||
import com.cf.imes.module.system.api.sms.dto.code.SmsCodeUseReqDTO;
|
||||
import com.cf.imes.module.system.api.social.dto.SocialUserBindReqDTO;
|
||||
@@ -10,6 +12,7 @@ import com.cf.imes.module.system.controller.admin.auth.vo.AuthSmsLoginReqVO;
|
||||
import com.cf.imes.module.system.controller.admin.auth.vo.AuthSmsSendReqVO;
|
||||
import com.cf.imes.module.system.controller.admin.auth.vo.AuthSocialLoginReqVO;
|
||||
import com.cf.imes.module.system.dal.dataobject.oauth2.OAuth2AccessTokenDO;
|
||||
import com.cf.imes.module.system.dal.dataobject.organ.OrganizationDO;
|
||||
import com.cf.imes.module.system.dal.dataobject.permission.MenuDO;
|
||||
import com.cf.imes.module.system.dal.dataobject.permission.RoleDO;
|
||||
import com.cf.imes.module.system.dal.dataobject.user.AdminUserDO;
|
||||
@@ -31,10 +34,14 @@ public interface AuthConvert {
|
||||
|
||||
AuthLoginRespVO convert(OAuth2AccessTokenDO bean);
|
||||
|
||||
default AuthPermissionInfoRespVO convert(AdminUserDO user, List<RoleDO> roleList, List<MenuDO> menuList) {
|
||||
default AuthPermissionInfoRespVO convert(AdminUserDO user, OrganizationDO organizationDO, IPQueryDataRespDTO ipQueryDataRespDTO, List<RoleDO> roleList, List<MenuDO> menuList) {
|
||||
boolean ipQuerySuccess = ObjectUtil.isNotNull(ipQueryDataRespDTO);
|
||||
return AuthPermissionInfoRespVO.builder()
|
||||
.user(AuthPermissionInfoRespVO.UserVO.builder()
|
||||
.id(user.getId()).nickname(user.getNickname()).avatar(user.getAvatar()).organId(user.getOrganId()).needSetPwd(StringUtils.isEmpty(user.getPassword())).build())
|
||||
.id(user.getId()).nickname(user.getNickname()).avatar(user.getAvatar()).organId(user.getOrganId()).needSetPwd(StringUtils.isEmpty(user.getPassword()))
|
||||
.expireTime(organizationDO.getExpireTime()).ip(ipQuerySuccess ? ipQueryDataRespDTO.getIp() : "")
|
||||
.region(ipQuerySuccess ? ipQueryDataRespDTO.getProv() + "/" + ipQueryDataRespDTO.getCity() + "/" + ipQueryDataRespDTO.getArea() : "")
|
||||
.build())
|
||||
.roles(convertSet(roleList, RoleDO::getCode))
|
||||
// 权限标识信息
|
||||
.permissions(convertSet(menuList, MenuDO::getPermission))
|
||||
|
||||
+4
@@ -69,4 +69,8 @@ public class LoginLogDO extends BaseDO {
|
||||
*/
|
||||
private String userAgent;
|
||||
|
||||
/**
|
||||
* 所属地区
|
||||
*/
|
||||
private String region;
|
||||
}
|
||||
|
||||
+3
@@ -31,6 +31,9 @@ public interface OrganMapper extends BaseMapperX<OrganizationDO> {
|
||||
.likeIfPresent(OrganizationDO::getContactMobile, reqVO.getContactMobile())
|
||||
.eqIfPresent(OrganizationDO::getStatus, reqVO.getStatus())
|
||||
.eqIfPresent(OrganizationDO::getName, reqVO.getExactName())
|
||||
.eqIfPresent(OrganizationDO::getProvince, reqVO.getProvince())
|
||||
.eqIfPresent(OrganizationDO::getCity, reqVO.getCity())
|
||||
.eqIfPresent(OrganizationDO::getCounty, reqVO.getCounty())
|
||||
.and(CharSequenceUtil.isNotBlank(reqVO.getName()), wrapper ->{
|
||||
wrapper.or(Boolean.TRUE).like(OrganizationDO::getName, reqVO.getName());
|
||||
wrapper.or(CharSequenceUtil.isNotBlank(reqVO.getPyAll())).like(OrganizationDO::getPinyinFull, reqVO.getPyAll());
|
||||
|
||||
+16
-53
@@ -6,13 +6,11 @@ import com.cf.imes.framework.common.enums.UserTypeEnum;
|
||||
import com.cf.imes.framework.common.exception.util.ServiceExceptionUtil;
|
||||
import com.cf.imes.framework.common.util.monitor.TracerUtils;
|
||||
import com.cf.imes.framework.common.util.servlet.ServletUtils;
|
||||
import com.cf.imes.framework.common.util.string.StrUtils;
|
||||
import com.cf.imes.framework.common.util.validation.ValidationUtils;
|
||||
import com.cf.imes.framework.ip.core.service.IPQueryService;
|
||||
import com.cf.imes.framework.ip.core.service.dto.IPQueryDataRespDTO;
|
||||
import com.cf.imes.module.system.api.logger.dto.LoginLogCreateReqDTO;
|
||||
import com.cf.imes.module.system.api.sms.SmsCodeApi;
|
||||
import com.cf.imes.module.system.api.social.dto.SocialUserBindReqDTO;
|
||||
import com.cf.imes.module.system.api.social.dto.SocialUserRespDTO;
|
||||
import com.cf.imes.module.system.controller.admin.auth.vo.AuthLoginReqVO;
|
||||
import com.cf.imes.module.system.controller.admin.auth.vo.AuthLoginRespVO;
|
||||
@@ -95,12 +93,6 @@ public class AdminAuthServiceImpl implements AdminAuthService {
|
||||
@Value("${chenfeng.captcha.enable:true}")
|
||||
private Boolean captchaEnable;
|
||||
|
||||
/**
|
||||
* 登录ip地址位置校验,默认为 false不开启
|
||||
*/
|
||||
@Value("${chenfeng.ipquery.enable:false}")
|
||||
private boolean ipQueryEnable;
|
||||
|
||||
@Override
|
||||
public AdminUserDO authenticate(AuthLoginReqVO reqVO) {
|
||||
String username = reqVO.getUsername();
|
||||
@@ -114,11 +106,7 @@ public class AdminAuthServiceImpl implements AdminAuthService {
|
||||
throw ServiceExceptionUtil.exception(ErrorCodeConstants.AUTH_LOGIN_BAD_CREDENTIALS);
|
||||
}
|
||||
// 校验机构有效性
|
||||
OrganizationDO organizationDO = organService.validOrgan(user.getOrganId());
|
||||
// 校验机构地理位置
|
||||
if (ipQueryEnable && !checkGeo(organizationDO, ServletUtils.getClientIP())) {
|
||||
throw ServiceExceptionUtil.exception(ErrorCodeConstants.AUTH_LOGIN_GEO_UNCORRECT);
|
||||
}
|
||||
organService.validOrgan(user.getOrganId());
|
||||
// 校验密码
|
||||
if (!userService.isPasswordMatch(password, user.getPassword())) {
|
||||
createLoginLog(user.getId(), username, logTypeEnum, LoginResultEnum.BAD_CREDENTIALS);
|
||||
@@ -132,38 +120,6 @@ public class AdminAuthServiceImpl implements AdminAuthService {
|
||||
return user;
|
||||
}
|
||||
|
||||
/**
|
||||
* 校验地理位置
|
||||
* 省市正确或地区代码对上了就校验通过
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
private boolean checkGeo(OrganizationDO organizationDO, String ip) {
|
||||
// 检查组织的地理信息
|
||||
if (ObjectUtil.isAllEmpty(organizationDO.getProvince(), organizationDO.getCity(), organizationDO.getAreaCode())) {
|
||||
throw ServiceExceptionUtil.exception(ErrorCodeConstants.AUTH_LOGIN_ORG_GEO_EMPTY);
|
||||
}
|
||||
|
||||
IPQueryDataRespDTO ipQueryDataRespDTO = ipQueryService.querySource(ip);
|
||||
|
||||
// 省名称和市名称包含了ip定位服务返回的省和市即位置正确
|
||||
boolean provinceAndCityMatch = false;
|
||||
if (StrUtils.contains(organizationDO.getProvince(), ipQueryDataRespDTO.getProv()) && StrUtils.contains(organizationDO.getCity(), ipQueryDataRespDTO.getCity())) {
|
||||
provinceAndCityMatch = true;
|
||||
}
|
||||
|
||||
// 行政区编码等于ip定位服务返回的编码即位置正确
|
||||
boolean areaCodeMatch = false;
|
||||
if (ObjectUtil.equal(organizationDO.getAreaCode(), ipQueryDataRespDTO.getPostCode())) {
|
||||
areaCodeMatch = true;
|
||||
}
|
||||
|
||||
if (provinceAndCityMatch || areaCodeMatch) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public AuthLoginRespVO login(AuthLoginReqVO reqVO) {
|
||||
@@ -173,11 +129,6 @@ public class AdminAuthServiceImpl implements AdminAuthService {
|
||||
// 使用账号密码,进行登录
|
||||
AdminUserDO user = authenticate(reqVO);
|
||||
|
||||
// 如果 socialType 非空,说明需要绑定社交用户
|
||||
if (reqVO.getSocialType() != null) {
|
||||
socialUserService.bindSocialUser(new SocialUserBindReqDTO(user.getId(), getUserType().getValue(),
|
||||
reqVO.getSocialType(), reqVO.getSocialCode(), reqVO.getSocialState()));
|
||||
}
|
||||
Long organId = user.getOrganId();
|
||||
OrganizationDO organ = organService.getOrgan(organId);
|
||||
String dataSourceCode = organ.getDataSourceCode();
|
||||
@@ -252,6 +203,7 @@ public class AdminAuthServiceImpl implements AdminAuthService {
|
||||
|
||||
private void createLoginLog(Long userId, String username,
|
||||
LoginLogTypeEnum logTypeEnum, LoginResultEnum loginResult) {
|
||||
String clientIP = getClientIP();
|
||||
// 插入登录日志
|
||||
LoginLogCreateReqDTO reqDTO = new LoginLogCreateReqDTO();
|
||||
reqDTO.setLogType(logTypeEnum.getType());
|
||||
@@ -260,12 +212,17 @@ public class AdminAuthServiceImpl implements AdminAuthService {
|
||||
reqDTO.setUserType(getUserType().getValue());
|
||||
reqDTO.setUsername(username);
|
||||
reqDTO.setUserAgent(ServletUtils.getUserAgent());
|
||||
reqDTO.setUserIp(ServletUtils.getClientIP());
|
||||
reqDTO.setUserIp(clientIP);
|
||||
reqDTO.setResult(loginResult.getResult());
|
||||
IPQueryDataRespDTO ipQueryDataRespDTO = ipQueryService.querySource(clientIP);
|
||||
// 设置登录时通过ip云服务查询到的地域信息
|
||||
if (ipQueryService.serviceEnable() && ObjectUtil.isNotNull(ipQueryDataRespDTO)) {
|
||||
reqDTO.setRegion(StringUtils.join(ipQueryDataRespDTO.getProv(), ipQueryDataRespDTO.getCity(), ipQueryDataRespDTO.getArea()));
|
||||
}
|
||||
loginLogService.createLoginLog(reqDTO);
|
||||
// 更新最后登录时间
|
||||
if (userId != null && Objects.equals(LoginResultEnum.SUCCESS.getResult(), loginResult.getResult())) {
|
||||
userService.updateUserLogin(userId, ServletUtils.getClientIP());
|
||||
userService.updateUserLogin(userId, clientIP);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -360,6 +317,7 @@ public class AdminAuthServiceImpl implements AdminAuthService {
|
||||
}
|
||||
|
||||
private void createLogoutLog(Long userId, Integer userType, Integer logType) {
|
||||
String clientIP = getClientIP();
|
||||
LoginLogCreateReqDTO reqDTO = new LoginLogCreateReqDTO();
|
||||
reqDTO.setLogType(logType);
|
||||
reqDTO.setTraceId(TracerUtils.getTraceId());
|
||||
@@ -370,8 +328,13 @@ public class AdminAuthServiceImpl implements AdminAuthService {
|
||||
} else {
|
||||
reqDTO.setUsername(memberService.getMemberUserMobile(userId));
|
||||
}
|
||||
IPQueryDataRespDTO ipQueryDataRespDTO = ipQueryService.querySource(clientIP);
|
||||
// 设置登录时通过ip云服务查询到的地域信息
|
||||
if (ipQueryService.serviceEnable() && ObjectUtil.isNotNull(ipQueryDataRespDTO)) {
|
||||
reqDTO.setRegion(StringUtils.join(ipQueryDataRespDTO.getProv(), ipQueryDataRespDTO.getCity(), ipQueryDataRespDTO.getArea()));
|
||||
}
|
||||
reqDTO.setUserAgent(ServletUtils.getUserAgent());
|
||||
reqDTO.setUserIp(ServletUtils.getClientIP());
|
||||
reqDTO.setUserIp(clientIP);
|
||||
reqDTO.setResult(LoginResultEnum.SUCCESS.getResult());
|
||||
loginLogService.createLoginLog(reqDTO);
|
||||
}
|
||||
|
||||
@@ -213,4 +213,8 @@ chenfeng:
|
||||
encrypt:
|
||||
enable: false
|
||||
publicKey: cfimes
|
||||
ipquery:
|
||||
enable: true
|
||||
apiUrl: https://ipquery.market.alicloudapi.com/query
|
||||
appCode: hBeRhmOnCR8f/XiD8zJ3lDaBSjbBA5ZZA2OEGswEOYQOK/hXVaT8E+AUOnEBcgFiw0R+39BvQ6TOVe2k
|
||||
debug: false
|
||||
|
||||
Reference in New Issue
Block a user