mirror of
				https://gitee.com/hhyykk/ipms-sjy.git
				synced 2025-10-31 18:28:43 +08:00 
			
		
		
		
	接入登陆日志
This commit is contained in:
		| @@ -24,9 +24,6 @@ import org.aspectj.lang.reflect.MethodSignature; | ||||
| import org.springframework.core.annotation.AnnotationUtils; | ||||
| import org.springframework.web.bind.annotation.RequestMapping; | ||||
| import org.springframework.web.bind.annotation.RequestMethod; | ||||
| import org.springframework.web.context.request.RequestAttributes; | ||||
| import org.springframework.web.context.request.RequestContextHolder; | ||||
| import org.springframework.web.context.request.ServletRequestAttributes; | ||||
| import org.springframework.web.multipart.MultipartFile; | ||||
|  | ||||
| import javax.annotation.Resource; | ||||
| @@ -196,11 +193,10 @@ public class OperateLogAspect { | ||||
|  | ||||
|     private static void fillRequestFields(SysOperateLogCreateReqVO operateLogVO) { | ||||
|         // 获得 Request 对象 | ||||
|         RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes(); | ||||
|         if (!(requestAttributes instanceof ServletRequestAttributes)) { | ||||
|         HttpServletRequest request = ServletUtils.getRequest(); | ||||
|         if (request == null) { | ||||
|             return; | ||||
|         } | ||||
|         HttpServletRequest request = ((ServletRequestAttributes) requestAttributes).getRequest(); | ||||
|         // 补全请求信息 | ||||
|         operateLogVO.setRequestMethod(request.getMethod()); | ||||
|         operateLogVO.setRequestUrl(request.getRequestURI()); | ||||
|   | ||||
| @@ -0,0 +1,4 @@ | ||||
| package cn.iocoder.dashboard.modules.system.controller.logger; | ||||
|  | ||||
| public class SysLoginLogController { | ||||
| } | ||||
| @@ -15,27 +15,23 @@ import javax.validation.constraints.Size; | ||||
| @Data | ||||
| public class SysLoginLogBaseVO { | ||||
|  | ||||
|     @ApiModelProperty(value = "日志类型", required = true, example = "1", notes = "参见 SysLoginLogTypeEnum 枚举类") | ||||
|     @NotNull(message = "日志类型不能为空") | ||||
|     private Integer logType; | ||||
|  | ||||
|     @ApiModelProperty(value = "链路追踪编号", required = true, example = "89aca178-a370-411c-ae02-3f0d672be4ab") | ||||
|     @NotEmpty(message = "链路追踪编号不能为空") | ||||
|     private String traceId; | ||||
|  | ||||
|     @ApiModelProperty(value = "用户编号", required = true, example = "1024") | ||||
|     @NotNull(message = "用户编号不能为空") | ||||
|     private Long userId; | ||||
|  | ||||
|     @ApiModelProperty(value = "用户账号", required = true, example = "yudao") | ||||
|     @NotBlank(message = "用户账号不能为空") | ||||
|     @Size(max = 30, message = "用户账号长度不能超过30个字符") | ||||
|     private String username; | ||||
|  | ||||
|  | ||||
|     @ApiModelProperty(value = "登陆结果", required = true, example = "1", notes = "参见 SysLoginResultEnum 枚举类") | ||||
|     @NotNull(message = "登陆结果不能为空") | ||||
|     private Integer result; | ||||
|  | ||||
|     @ApiModelProperty(value = "操作明细", example = "修改编号为 1 的用户信息,将性别从男改成女,将姓名从芋道改成源码。") | ||||
|     private String content; | ||||
|  | ||||
|     @ApiModelProperty(value = "用户 IP", required = true, example = "127.0.0.1") | ||||
|     @NotEmpty(message = "用户 IP 不能为空") | ||||
|     private String userIp; | ||||
|   | ||||
| @@ -1,6 +1,5 @@ | ||||
| package cn.iocoder.dashboard.modules.system.controller.logger.vo.loginlog; | ||||
|  | ||||
| import cn.iocoder.dashboard.modules.system.controller.logger.vo.operatelog.SysOperateLogCreateReqVO; | ||||
| import io.swagger.annotations.ApiModel; | ||||
| import lombok.Data; | ||||
| import lombok.EqualsAndHashCode; | ||||
| @@ -11,5 +10,5 @@ import lombok.ToString; | ||||
| @Data | ||||
| @EqualsAndHashCode(callSuper = true) | ||||
| @ToString(callSuper = true) | ||||
| public class SysLoginLogCreateReqVO extends SysOperateLogCreateReqVO { | ||||
| public class SysLoginLogCreateReqVO extends SysLoginLogBaseVO { | ||||
| } | ||||
|   | ||||
| @@ -0,0 +1,15 @@ | ||||
| package cn.iocoder.dashboard.modules.system.convert.logger; | ||||
|  | ||||
| import cn.iocoder.dashboard.modules.system.controller.logger.vo.loginlog.SysLoginLogCreateReqVO; | ||||
| import cn.iocoder.dashboard.modules.system.dal.mysql.dataobject.logger.SysLoginLogDO; | ||||
| import org.mapstruct.Mapper; | ||||
| import org.mapstruct.factory.Mappers; | ||||
|  | ||||
| @Mapper | ||||
| public interface SysLoginLogConvert { | ||||
|  | ||||
|     SysLoginLogConvert INSTANCE = Mappers.getMapper(SysLoginLogConvert.class); | ||||
|  | ||||
|     SysLoginLogDO convert(SysLoginLogCreateReqVO bean); | ||||
|  | ||||
| } | ||||
| @@ -0,0 +1,9 @@ | ||||
| package cn.iocoder.dashboard.modules.system.dal.mysql.dao.logger; | ||||
|  | ||||
| import cn.iocoder.dashboard.framework.mybatis.core.mapper.BaseMapperX; | ||||
| import cn.iocoder.dashboard.modules.system.dal.mysql.dataobject.logger.SysLoginLogDO; | ||||
| import org.apache.ibatis.annotations.Mapper; | ||||
|  | ||||
| @Mapper | ||||
| public interface SysLoginLogMapper extends BaseMapperX<SysLoginLogDO> { | ||||
| } | ||||
| @@ -1,32 +1,40 @@ | ||||
| package cn.iocoder.dashboard.modules.system.dal.mysql.dataobject.logger; | ||||
|  | ||||
| import cn.iocoder.dashboard.framework.mybatis.core.dataobject.BaseDO; | ||||
| import cn.iocoder.dashboard.modules.system.dal.mysql.dataobject.user.SysUserDO; | ||||
| import cn.iocoder.dashboard.modules.system.enums.logger.SysLoginLogTypeEnum; | ||||
| import cn.iocoder.dashboard.modules.system.enums.logger.SysLoginResultEnum; | ||||
| import com.baomidou.mybatisplus.annotation.TableName; | ||||
| import lombok.Data; | ||||
| import lombok.EqualsAndHashCode; | ||||
| import lombok.ToString; | ||||
|  | ||||
| /** | ||||
|  * 系统访问记录表 | ||||
|  * 登陆日志表 | ||||
|  * | ||||
|  * 注意,包括登陆和登出两种行为 | ||||
|  * | ||||
|  * @author ruoyi | ||||
|  */ | ||||
| @TableName("用户登陆日志") | ||||
| @TableName("sys_login_log") | ||||
| @Data | ||||
| @EqualsAndHashCode(callSuper = true) | ||||
| @ToString(callSuper = true) | ||||
| public class SysLoginLogDO extends BaseDO { | ||||
|  | ||||
|     /** | ||||
|      * 日志主键 | ||||
|      */ | ||||
|     private Long id; | ||||
|     /** | ||||
|      * 日志类型 | ||||
|      * | ||||
|      * 枚举 {@link SysLoginLogTypeEnum} | ||||
|      */ | ||||
|     private Integer logType; | ||||
|     /** | ||||
|      * 链路追踪编号 | ||||
|      */ | ||||
|     private String traceId; | ||||
|     /** | ||||
|      * 用户编号 | ||||
|      * | ||||
|      * 外键 {@link SysUserDO#getId()} | ||||
|      */ | ||||
|     private Long userId; | ||||
|     /** | ||||
|      * 用户账号 | ||||
|      * | ||||
| @@ -39,12 +47,10 @@ public class SysLoginLogDO extends BaseDO { | ||||
|      * 枚举 {@link SysLoginResultEnum} | ||||
|      */ | ||||
|     private Integer result; | ||||
|  | ||||
|     /** | ||||
|      * 用户 IP | ||||
|      */ | ||||
|     private String userIp; | ||||
|  | ||||
|     /** | ||||
|      * 浏览器 UA | ||||
|      */ | ||||
|   | ||||
| @@ -13,6 +13,8 @@ public interface SysErrorCodeConstants { | ||||
|     ErrorCode AUTH_LOGIN_BAD_CREDENTIALS = new ErrorCode(1002000000, "登录失败,账号密码不正确"); | ||||
|     ErrorCode AUTH_LOGIN_USER_DISABLED = new ErrorCode(1002000001, "登录失败,账号被禁用"); | ||||
|     ErrorCode AUTH_LOGIN_FAIL_UNKNOWN = new ErrorCode(1002000002, "登录失败"); // 登陆失败的兜底,位置原因 | ||||
|     ErrorCode AUTH_LOGIN_CAPTCHA_NOT_FOUND = new ErrorCode(1002000003, "验证码不存在"); | ||||
|     ErrorCode AUTH_LOGIN_CAPTCHA_CODE_ERROR = new ErrorCode(1002000004, "验证码不正确"); | ||||
|  | ||||
|     // ========== TOKEN 模块 1002001000 ========== | ||||
|     ErrorCode TOKEN_EXPIRED = new ErrorCode(1002001000, "Token 已经过期"); | ||||
|   | ||||
| @@ -0,0 +1,21 @@ | ||||
| package cn.iocoder.dashboard.modules.system.enums.logger; | ||||
|  | ||||
| import lombok.AllArgsConstructor; | ||||
| import lombok.Getter; | ||||
|  | ||||
| /** | ||||
|  * 登陆日志的类型枚举 | ||||
|  */ | ||||
| @Getter | ||||
| @AllArgsConstructor | ||||
| public enum SysLoginLogTypeEnum { | ||||
|  | ||||
|     LOGIN(1), | ||||
|     LOGOUT(2); | ||||
|  | ||||
|     /** | ||||
|      * 日志类型 | ||||
|      */ | ||||
|     private final Integer type; | ||||
|  | ||||
| } | ||||
| @@ -11,6 +11,12 @@ import lombok.Getter; | ||||
| public enum SysLoginResultEnum { | ||||
|  | ||||
|     SUCCESS(0), // 成功 | ||||
|     BAD_CREDENTIALS(10), // 账号或密码不正确 | ||||
|     USER_DISABLED(20), // 账号或密码不正确 | ||||
|     CAPTCHA_NOT_FOUND(30), // 验证码不存在 | ||||
|     CAPTCHA_CODE_ERROR(31), // 验证码不正确 | ||||
|  | ||||
|     UNKNOWN_ERROR(100), // 未知异常 | ||||
|     ; | ||||
|  | ||||
|     /** | ||||
|   | ||||
| @@ -3,16 +3,24 @@ package cn.iocoder.dashboard.modules.system.service.auth.impl; | ||||
| import cn.hutool.core.util.IdUtil; | ||||
| import cn.hutool.core.util.StrUtil; | ||||
| import cn.iocoder.dashboard.common.enums.CommonStatusEnum; | ||||
| import cn.iocoder.dashboard.common.exception.util.ServiceExceptionUtil; | ||||
| import cn.iocoder.dashboard.framework.security.config.SecurityProperties; | ||||
| import cn.iocoder.dashboard.framework.security.core.LoginUser; | ||||
| import cn.iocoder.dashboard.framework.tracer.core.util.TracerUtils; | ||||
| import cn.iocoder.dashboard.modules.system.controller.logger.vo.loginlog.SysLoginLogCreateReqVO; | ||||
| import cn.iocoder.dashboard.modules.system.convert.auth.SysAuthConvert; | ||||
| import cn.iocoder.dashboard.modules.system.dal.mysql.dataobject.user.SysUserDO; | ||||
| import cn.iocoder.dashboard.modules.system.dal.redis.dao.auth.SysLoginUserRedisDAO; | ||||
| import cn.iocoder.dashboard.modules.system.enums.logger.SysLoginLogTypeEnum; | ||||
| import cn.iocoder.dashboard.modules.system.enums.logger.SysLoginResultEnum; | ||||
| import cn.iocoder.dashboard.modules.system.service.auth.SysAuthService; | ||||
| import cn.iocoder.dashboard.modules.system.service.auth.SysTokenService; | ||||
| import cn.iocoder.dashboard.modules.system.service.common.SysCaptchaService; | ||||
| import cn.iocoder.dashboard.modules.system.service.logger.SysLoginLogService; | ||||
| import cn.iocoder.dashboard.modules.system.service.permission.SysPermissionService; | ||||
| import cn.iocoder.dashboard.modules.system.service.user.SysUserService; | ||||
| import cn.iocoder.dashboard.util.date.DateUtils; | ||||
| import cn.iocoder.dashboard.util.servlet.ServletUtils; | ||||
| import io.jsonwebtoken.Claims; | ||||
| import io.jsonwebtoken.JwtException; | ||||
| import lombok.extern.slf4j.Slf4j; | ||||
| @@ -55,6 +63,10 @@ public class SysAuthServiceImpl implements SysAuthService { | ||||
|     private SysUserService userService; | ||||
|     @Resource | ||||
|     private SysPermissionService permissionService; | ||||
|     @Resource | ||||
|     private SysCaptchaService captchaService; | ||||
|     @Resource | ||||
|     private SysLoginLogService loginLogService; | ||||
|  | ||||
|     @Resource | ||||
|     private SysLoginUserRedisDAO loginUserRedisDAO; | ||||
| @@ -87,7 +99,7 @@ public class SysAuthServiceImpl implements SysAuthService { | ||||
|     @Override | ||||
|     public String login(String username, String password, String captchaUUID, String captchaCode) { | ||||
|         // 判断验证码是否正确 | ||||
|         this.verifyCaptcha(captchaUUID, captchaCode); | ||||
|         this.verifyCaptcha(username, captchaUUID, captchaCode); | ||||
|  | ||||
|         // 使用账号密码,进行登陆。 | ||||
|         LoginUser loginUser = this.login0(username, password); | ||||
| @@ -102,18 +114,20 @@ public class SysAuthServiceImpl implements SysAuthService { | ||||
|         return tokenService.createToken(sessionId); | ||||
|     } | ||||
|  | ||||
|     private void verifyCaptcha(String captchaUUID, String captchaCode) { | ||||
|         //        String verifyKey = Constants.CAPTCHA_CODE_KEY + captchaUUID; | ||||
| //        String captcha = redisCache.getCacheObject(verifyKey); | ||||
| //        redisCache.deleteObject(verifyKey); | ||||
| //        if (captcha == null) { | ||||
| //            AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_FAIL, MessageUtils.message("user.jcaptcha.expire"))); | ||||
| //            throw new CaptchaExpireException(); | ||||
| //        } | ||||
| //        if (!code.equalsIgnoreCase(captcha)) { | ||||
| //            AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_FAIL, MessageUtils.message("user.jcaptcha.error"))); | ||||
| //            throw new CaptchaException(); | ||||
| //        } | ||||
|     private void verifyCaptcha(String username, String captchaUUID, String captchaCode) { | ||||
|         String code = captchaService.getCaptchaCode(captchaUUID); | ||||
|         // 验证码不存在 | ||||
|         if (code == null) { | ||||
|             this.createLoginLog(username, SysLoginResultEnum.CAPTCHA_NOT_FOUND); | ||||
|             throw ServiceExceptionUtil.exception(AUTH_LOGIN_CAPTCHA_NOT_FOUND); | ||||
|         } | ||||
|         // 验证码不正确 | ||||
|         if (!code.equals(captchaCode)) { | ||||
|             this.createLoginLog(username, SysLoginResultEnum.CAPTCHA_CODE_ERROR); | ||||
|             throw ServiceExceptionUtil.exception(AUTH_LOGIN_CAPTCHA_CODE_ERROR); | ||||
|         } | ||||
|         // 正确,所以要删除下验证码 | ||||
|         captchaService.deleteCaptchaCode(captchaUUID); | ||||
|     } | ||||
|  | ||||
|     private LoginUser login0(String username, String password) { | ||||
| @@ -124,22 +138,33 @@ public class SysAuthServiceImpl implements SysAuthService { | ||||
|             // 在其内部,会调用到 loadUserByUsername 方法,获取 User 信息 | ||||
|             authentication = authenticationManager.authenticate(new UsernamePasswordAuthenticationToken(username, password)); | ||||
|         } catch (BadCredentialsException badCredentialsException) { | ||||
|             // TODO 日志优化 | ||||
| //            AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_FAIL, MessageUtils.message("user.password.not.match"))); | ||||
|             this.createLoginLog(username, SysLoginResultEnum.BAD_CREDENTIALS); | ||||
|             throw exception(AUTH_LOGIN_BAD_CREDENTIALS); | ||||
|         } catch (DisabledException disabledException) { | ||||
|             // TODO 日志优化 | ||||
|             this.createLoginLog(username, SysLoginResultEnum.USER_DISABLED); | ||||
|             throw exception(AUTH_LOGIN_USER_DISABLED); | ||||
|         } catch (AuthenticationException authenticationException) { | ||||
|             // TODO 日志优化 | ||||
|             log.error("[login0][username({}) 发生未知异常]", username, authenticationException); | ||||
|             this.createLoginLog(username, SysLoginResultEnum.UNKNOWN_ERROR); | ||||
|             throw exception(AUTH_LOGIN_FAIL_UNKNOWN); | ||||
|         } | ||||
|         // TODO 需要优化 | ||||
| //        AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_SUCCESS, MessageUtils.message("user.login.success"))); | ||||
|         // 登陆成功 | ||||
|         Assert.notNull(authentication.getPrincipal(), "Principal 不会为空"); | ||||
|         this.createLoginLog(username, SysLoginResultEnum.SUCCESS); | ||||
|         return (LoginUser) authentication.getPrincipal(); | ||||
|     } | ||||
|  | ||||
|     private void createLoginLog(String username, SysLoginResultEnum loginResult) { | ||||
|         SysLoginLogCreateReqVO reqVO = new SysLoginLogCreateReqVO(); | ||||
|         reqVO.setLogType(SysLoginLogTypeEnum.LOGIN.getType()); | ||||
|         reqVO.setTraceId(TracerUtils.getTraceId()); | ||||
|         reqVO.setUsername(username); | ||||
|         reqVO.setUserAgent(ServletUtils.getUserAgent()); | ||||
|         reqVO.setUserIp(ServletUtils.getClientIP()); | ||||
|         reqVO.setResult(loginResult.getResult()); | ||||
|         loginLogService.createLoginLog(reqVO); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 获得 User 拥有的角色编号数组 | ||||
|      * | ||||
|   | ||||
| @@ -7,6 +7,26 @@ import cn.iocoder.dashboard.modules.system.controller.common.vo.SysCaptchaImageR | ||||
|  */ | ||||
| public interface SysCaptchaService { | ||||
|  | ||||
|     /** | ||||
|      * 获得验证码图片 | ||||
|      * | ||||
|      * @return 验证码图片 | ||||
|      */ | ||||
|     SysCaptchaImageRespVO getCaptchaImage(); | ||||
|  | ||||
|     /** | ||||
|      * 获得 uuid 对应的验证码 | ||||
|      * | ||||
|      * @param uuid 验证码编号 | ||||
|      * @return 验证码 | ||||
|      */ | ||||
|     String getCaptchaCode(String uuid); | ||||
|  | ||||
|     /** | ||||
|      * 删除 uuid 对应的验证码 | ||||
|      * | ||||
|      * @param uuid 验证码编号 | ||||
|      */ | ||||
|     void deleteCaptchaCode(String uuid); | ||||
|  | ||||
| } | ||||
|   | ||||
| @@ -35,4 +35,14 @@ public class SysCaptchaServiceImpl implements SysCaptchaService { | ||||
|         return SysCaptchaConvert.INSTANCE.convert(uuid, captcha); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public String getCaptchaCode(String uuid) { | ||||
|         return captchaRedisDAO.get(uuid); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public void deleteCaptchaCode(String uuid) { | ||||
|         captchaRedisDAO.delete(uuid); | ||||
|     } | ||||
|  | ||||
| } | ||||
|   | ||||
| @@ -0,0 +1,17 @@ | ||||
| package cn.iocoder.dashboard.modules.system.service.logger; | ||||
|  | ||||
| import cn.iocoder.dashboard.modules.system.controller.logger.vo.loginlog.SysLoginLogCreateReqVO; | ||||
|  | ||||
| /** | ||||
|  * 登陆日志 Service 接口 | ||||
|  */ | ||||
| public interface SysLoginLogService { | ||||
|  | ||||
|     /** | ||||
|      * 创建登陆日志 | ||||
|      * | ||||
|      * @param reqVO 日志信息 | ||||
|      */ | ||||
|     void createLoginLog(SysLoginLogCreateReqVO reqVO); | ||||
|  | ||||
| } | ||||
| @@ -0,0 +1,27 @@ | ||||
| package cn.iocoder.dashboard.modules.system.service.logger.impl; | ||||
|  | ||||
| import cn.iocoder.dashboard.modules.system.controller.logger.vo.loginlog.SysLoginLogCreateReqVO; | ||||
| import cn.iocoder.dashboard.modules.system.convert.logger.SysLoginLogConvert; | ||||
| import cn.iocoder.dashboard.modules.system.dal.mysql.dao.logger.SysLoginLogMapper; | ||||
| import cn.iocoder.dashboard.modules.system.dal.mysql.dataobject.logger.SysLoginLogDO; | ||||
| import cn.iocoder.dashboard.modules.system.service.logger.SysLoginLogService; | ||||
| import org.springframework.stereotype.Service; | ||||
|  | ||||
| import javax.annotation.Resource; | ||||
|  | ||||
| /** | ||||
|  * 登陆日志 Service 实现 | ||||
|  */ | ||||
| @Service | ||||
| public class SysLoginLogServiceImpl implements SysLoginLogService { | ||||
|  | ||||
|     @Resource | ||||
|     private SysLoginLogMapper loginLogMapper; | ||||
|  | ||||
|     @Override | ||||
|     public void createLoginLog(SysLoginLogCreateReqVO reqVO) { | ||||
|         SysLoginLogDO loginLog = SysLoginLogConvert.INSTANCE.convert(reqVO); | ||||
|         loginLogMapper.insert(loginLog); | ||||
|     } | ||||
|  | ||||
| } | ||||
| @@ -4,6 +4,9 @@ import cn.hutool.core.io.IoUtil; | ||||
| import cn.hutool.extra.servlet.ServletUtil; | ||||
| import com.alibaba.fastjson.JSON; | ||||
| import org.springframework.http.MediaType; | ||||
| import org.springframework.web.context.request.RequestAttributes; | ||||
| import org.springframework.web.context.request.RequestContextHolder; | ||||
| import org.springframework.web.context.request.ServletRequestAttributes; | ||||
|  | ||||
| import javax.servlet.http.HttpServletRequest; | ||||
| import javax.servlet.http.HttpServletResponse; | ||||
| @@ -54,4 +57,33 @@ public class ServletUtils { | ||||
|         return ua != null ? ua : ""; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 获得请求 | ||||
|      * | ||||
|      * @return HttpServletRequest | ||||
|      */ | ||||
|     public static HttpServletRequest getRequest() { | ||||
|         RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes(); | ||||
|         if (!(requestAttributes instanceof ServletRequestAttributes)) { | ||||
|             return null; | ||||
|         } | ||||
|         return ((ServletRequestAttributes) requestAttributes).getRequest(); | ||||
|     } | ||||
|  | ||||
|     public static String getUserAgent() { | ||||
|         HttpServletRequest request = getRequest(); | ||||
|         if (request == null) { | ||||
|             return null; | ||||
|         } | ||||
|         return getUserAgent(request); | ||||
|     } | ||||
|  | ||||
|     public static String getClientIP() { | ||||
|         HttpServletRequest request = getRequest(); | ||||
|         if (request == null) { | ||||
|             return null; | ||||
|         } | ||||
|         return ServletUtil.getClientIP(request); | ||||
|     } | ||||
|  | ||||
| } | ||||
|   | ||||
		Reference in New Issue
	
	Block a user
	 YunaiV
					YunaiV