校验用户每次请求IP地址

This commit is contained in:
2023-08-01 10:02:05 +08:00
parent c10e46fe1e
commit f9524cb93e
4 changed files with 84 additions and 32 deletions

View File

@@ -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.<List<RoleEntity>>defaultIfNull(user.getRoles(), new ArrayList<>())
.stream()
.flatMap((RoleEntity r) -> ObjectUtils.<List<PermissionEntity>>defaultIfNull(r.getPermissions(), new ArrayList<>()).stream())
.flatMap((PermissionEntity r) -> ObjectUtils.<List<ResourceEntity>>defaultIfNull(r.getResources(), new ArrayList<>()).stream())
.noneMatch(x -> x.getUrl().equalsIgnoreCase(request.getRequestURI().replaceAll(request.getContextPath(), "")))) {
if (ObjectUtils.<List<RoleEntity>>defaultIfNull(user.getRoles(), new ArrayList<>())
.stream()
.flatMap((RoleEntity r) -> ObjectUtils.<List<PermissionEntity>>defaultIfNull(r.getPermissions(), new ArrayList<>()).stream())
.flatMap((PermissionEntity r) -> ObjectUtils.<List<ResourceEntity>>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 {

View File

@@ -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;
}

View File

@@ -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;
}

View File

@@ -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);
}
}