From f9524cb93e0067f79336953ef7614c6815839079 Mon Sep 17 00:00:00 2001 From: lihongjie0209 Date: Tue, 1 Aug 2023 10:02:05 +0800 Subject: [PATCH] =?UTF-8?q?=E6=A0=A1=E9=AA=8C=E7=94=A8=E6=88=B7=E6=AF=8F?= =?UTF-8?q?=E6=AC=A1=E8=AF=B7=E6=B1=82IP=E5=9C=B0=E5=9D=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../cn/lihongjie/coal/aop/ControllerAop.java | 45 +++++++------- .../coal/controller/LoginController.java | 6 +- .../java/cn/lihongjie/coal/dto/LoginDto.java | 4 ++ .../coal/service/SessionService.java | 61 ++++++++++++++++--- 4 files changed, 84 insertions(+), 32 deletions(-) diff --git a/src/main/java/cn/lihongjie/coal/aop/ControllerAop.java b/src/main/java/cn/lihongjie/coal/aop/ControllerAop.java index e6bb98c6..92a54265 100644 --- a/src/main/java/cn/lihongjie/coal/aop/ControllerAop.java +++ b/src/main/java/cn/lihongjie/coal/aop/ControllerAop.java @@ -53,6 +53,7 @@ public class ControllerAop { Method method = ((MethodSignature) proceedingJoinPoint.getSignature()).getMethod(); HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest(); + sessionService.rebuildSession(request.getHeader("X-Token")); @@ -65,7 +66,7 @@ public class ControllerAop { if (anonymous == null || !anonymous.value()) { - throw new BizException("invalidToken", "登录状态失效,请重新登录"); + throw new BizException("invalidToken", "登录状态失效,请重新登录"); } @@ -76,45 +77,49 @@ public class ControllerAop { if (!Ctx.isSysAdmin()) { - OrgAdmin orgAdmin = ObjectUtils.defaultIfNull(AnnotationUtils.findAnnotation(method, OrgAdmin.class), AnnotationUtils.findAnnotation(method.getClass(), OrgAdmin.class)); - if (orgAdmin != null && orgAdmin.value() && !Ctx.isOrgAdmin()) { + if (!Ctx.isSysAdmin()) { + + OrgAdmin orgAdmin = ObjectUtils.defaultIfNull(AnnotationUtils.findAnnotation(method, OrgAdmin.class), AnnotationUtils.findAnnotation(method.getClass(), OrgAdmin.class)); + + if (orgAdmin != null && orgAdmin.value() && !Ctx.isOrgAdmin()) { - throw new BizException("invalidAccess", "非法访问,请联系机构管理员。"); + throw new BizException("invalidAccess", "非法访问,请联系机构管理员。"); - } + } - SysAdmin sysAdmin = ObjectUtils.defaultIfNull(AnnotationUtils.findAnnotation(method, SysAdmin.class), AnnotationUtils.findAnnotation(method.getClass(), SysAdmin.class)); + SysAdmin sysAdmin = ObjectUtils.defaultIfNull(AnnotationUtils.findAnnotation(method, SysAdmin.class), AnnotationUtils.findAnnotation(method.getClass(), SysAdmin.class)); - if (sysAdmin != null && sysAdmin.value() && !Ctx.isSysAdmin()) { + if (sysAdmin != null && sysAdmin.value() && !Ctx.isSysAdmin()) { - throw new BizException("invalidAccess", "非法访问,请联系系统管理员。"); + throw new BizException("invalidAccess", "非法访问,请联系系统管理员。"); - } + } - UserEntity user = Ctx.currentUser(); + UserEntity user = Ctx.currentUser(); - if (ObjectUtils.>defaultIfNull(user.getRoles(), new ArrayList<>()) - .stream() - .flatMap((RoleEntity r) -> ObjectUtils.>defaultIfNull(r.getPermissions(), new ArrayList<>()).stream()) - .flatMap((PermissionEntity r) -> ObjectUtils.>defaultIfNull(r.getResources(), new ArrayList<>()).stream()) - .noneMatch(x -> x.getUrl().equalsIgnoreCase(request.getRequestURI().replaceAll(request.getContextPath(), "")))) { + if (ObjectUtils.>defaultIfNull(user.getRoles(), new ArrayList<>()) + .stream() + .flatMap((RoleEntity r) -> ObjectUtils.>defaultIfNull(r.getPermissions(), new ArrayList<>()).stream()) + .flatMap((PermissionEntity r) -> ObjectUtils.>defaultIfNull(r.getResources(), new ArrayList<>()).stream()) + .noneMatch(x -> x.getUrl().equalsIgnoreCase(request.getRequestURI().replaceAll(request.getContextPath(), "")))) { - } - { - throw new BizException("invalidAccess", "当前资源未授权,请联系机构管理员处理。"); + } + { + throw new BizException("invalidAccess", "当前资源未授权,请联系机构管理员处理。"); + + } } } - } @@ -136,8 +141,6 @@ public class ControllerAop { throw e; - - } finally { diff --git a/src/main/java/cn/lihongjie/coal/controller/LoginController.java b/src/main/java/cn/lihongjie/coal/controller/LoginController.java index a3fd388a..54752a70 100644 --- a/src/main/java/cn/lihongjie/coal/controller/LoginController.java +++ b/src/main/java/cn/lihongjie/coal/controller/LoginController.java @@ -9,6 +9,7 @@ import cn.lihongjie.coal.dto.UserDto; import cn.lihongjie.coal.service.SessionService; import cn.lihongjie.coal.service.UserService; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.security.core.context.SecurityContextHolder; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; @@ -45,7 +46,10 @@ public class LoginController { @PostMapping("/logout") @SysLog(action = "退出") public Object logout() { - this.service.logout(); + if (Ctx.isLoggedIn()) { + + this.service.logout(((SessionService.MyAuthentication) SecurityContextHolder.getContext().getAuthentication()).getSessionId()); + } return null; } diff --git a/src/main/java/cn/lihongjie/coal/dto/LoginDto.java b/src/main/java/cn/lihongjie/coal/dto/LoginDto.java index 07aa1f70..f34b8d47 100644 --- a/src/main/java/cn/lihongjie/coal/dto/LoginDto.java +++ b/src/main/java/cn/lihongjie/coal/dto/LoginDto.java @@ -10,4 +10,8 @@ public class LoginDto { private String password; private String captchaId; private String captcha; + private String ip; + private String ua; + private String userId; + private String sessionId; } diff --git a/src/main/java/cn/lihongjie/coal/service/SessionService.java b/src/main/java/cn/lihongjie/coal/service/SessionService.java index 52c62fd4..a6e7e308 100644 --- a/src/main/java/cn/lihongjie/coal/service/SessionService.java +++ b/src/main/java/cn/lihongjie/coal/service/SessionService.java @@ -1,14 +1,19 @@ package cn.lihongjie.coal.service; +import cn.lihongjie.coal.common.RequestUtils; import cn.lihongjie.coal.dto.CaptchaDto; import cn.lihongjie.coal.dto.LoginDto; import cn.lihongjie.coal.entity.OrganizationEntity; import cn.lihongjie.coal.entity.UserEntity; import cn.lihongjie.coal.exception.BizException; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; import com.wf.captcha.SpecCaptcha; import com.wf.captcha.base.Captcha; +import jakarta.servlet.http.HttpServletRequest; import lombok.Data; +import lombok.SneakyThrows; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; import org.springframework.beans.factory.annotation.Autowired; @@ -18,6 +23,8 @@ import org.springframework.security.core.GrantedAuthority; import org.springframework.security.core.context.SecurityContext; import org.springframework.security.core.context.SecurityContextHolder; import org.springframework.stereotype.Service; +import org.springframework.web.context.request.RequestContextHolder; +import org.springframework.web.context.request.ServletRequestAttributes; import java.util.Collection; import java.util.UUID; @@ -63,8 +70,12 @@ public class SessionService { @Autowired OrganizationService organizationService; - public void login(LoginDto dto) { + @Autowired + ObjectMapper objectMapper; + @SneakyThrows + public void login(LoginDto dto) { + HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest(); String captchaId = dto.getCaptchaId(); @@ -102,7 +113,13 @@ public class SessionService { context.setAuthentication(new MyAuthentication(dto, user, sessionId)); - stringRedisTemplate.opsForValue().set(sessionId, user.getId(), 1, TimeUnit.HOURS); + SecurityContextHolder.setContext(context); + dto.setUserId(user.getId()); + dto.setSessionId(sessionId); + dto.setUa(RequestUtils.getUa(request)); + dto.setIp(RequestUtils.getIp(request)); + + stringRedisTemplate.opsForValue().set(sessionId, objectMapper.writeValueAsString(dto), 1, TimeUnit.HOURS); } @@ -115,28 +132,52 @@ public class SessionService { } - String userId = stringRedisTemplate.opsForValue().getAndExpire(sessionId, 1, TimeUnit.HOURS); + String jsonstring = stringRedisTemplate.opsForValue().getAndExpire(sessionId, 1, TimeUnit.HOURS); - if (StringUtils.isEmpty(userId)) { - throw new BizException("会话已过期,请重新登录"); + if (StringUtils.isEmpty(jsonstring)) { + throw new BizException("invalidToken", "会话已过期,请重新登录"); + } + LoginDto loginDto = null; + + try { + loginDto = objectMapper.readValue(jsonstring, LoginDto.class); + } catch (JsonProcessingException e) { + throw new BizException("invalidToken", "会话异常,请重新登录"); } - UserEntity user = userService.get(userId); + HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest(); + String currentIp = RequestUtils.getIp(request); + String currentUa = RequestUtils.getUa(request); + if (!StringUtils.equalsIgnoreCase(currentIp, loginDto.getIp())) { + + log.warn("检测到IP变化: {} {}", loginDto, currentIp); + logout(loginDto.getSessionId()); + throw new BizException("invalidToken", "检测到IP发生变化,请重新登录"); + } + if (!StringUtils.equalsIgnoreCase(currentUa, loginDto.getUa())) { + + log.warn("检测到浏览器变化: {} {}", loginDto, currentUa); + logout(loginDto.getSessionId()); + throw new BizException("invalidToken", "检测到浏览器发生变化,请重新登录"); + } + + UserEntity user = userService.get(loginDto.getUserId()); SecurityContext context = SecurityContextHolder.createEmptyContext(); - context.setAuthentication(new MyAuthentication(null, user, sessionId)); + context.setAuthentication(new MyAuthentication(loginDto, user, sessionId)); SecurityContextHolder.setContext(context); } + public void logout(String sessionId) { - public void logout() { + if (sessionId != null) { - String sessionId = ((MyAuthentication) SecurityContextHolder.getContext().getAuthentication()).sessionId; - stringRedisTemplate.opsForValue().getAndDelete(sessionId); + stringRedisTemplate.opsForValue().getAndDelete(sessionId); + } }