适配了Task新的数据结构,完成了限流控制并通过了测试,实现了多次登录失败banIP,为MybatisPlus添加了防全表更新及删除的插件
parent
8cc1111489
commit
1a001fb599
|
@ -22,4 +22,8 @@ group /project/{projectId}/group
|
||||||
项目日志 项目统计 克隆项目 项目公告
|
项目日志 项目统计 克隆项目 项目公告
|
||||||
|
|
||||||
---
|
---
|
||||||
导入账户 大权限
|
导入账户 大权限
|
||||||
|
|
||||||
|
工作进度统计
|
||||||
|
个人/项目工作项具体完成统计
|
||||||
|
工作项时间进度统计
|
||||||
|
|
|
@ -26,26 +26,28 @@ public class ExceptionHandlerAdvice {
|
||||||
@ResponseStatus(HttpStatus.UNAUTHORIZED)
|
@ResponseStatus(HttpStatus.UNAUTHORIZED)
|
||||||
public ResponseMap handleUnauthorizedException(Exception e) {
|
public ResponseMap handleUnauthorizedException(Exception e) {
|
||||||
// log.error(ExceptionUtils.getStackTrace(e));
|
// log.error(ExceptionUtils.getStackTrace(e));
|
||||||
// log.error(e.getMessage());
|
log.error(e.getMessage(), e);
|
||||||
return ResponseMap.of(HttpStatus.UNAUTHORIZED.value(), e.getMessage());
|
return ResponseMap.of(HttpStatus.UNAUTHORIZED.value(), e.getMessage());
|
||||||
}
|
}
|
||||||
|
|
||||||
@ExceptionHandler(BadRequestException.class)
|
@ExceptionHandler(BadRequestException.class)
|
||||||
@ResponseStatus(HttpStatus.BAD_REQUEST)
|
@ResponseStatus(HttpStatus.BAD_REQUEST)
|
||||||
public ResponseMap handleBadRequestException(BadRequestException e) {
|
public ResponseMap handleBadRequestException(BadRequestException e) {
|
||||||
// log.error(e.getMessage());
|
log.error(e.getMessage(), e);
|
||||||
return ResponseMap.of(HttpStatus.BAD_REQUEST.value(), e.getMessage());
|
return ResponseMap.of(HttpStatus.BAD_REQUEST.value(), e.getMessage());
|
||||||
}
|
}
|
||||||
|
|
||||||
@ExceptionHandler(ForbiddenException.class)
|
@ExceptionHandler(ForbiddenException.class)
|
||||||
@ResponseStatus(HttpStatus.FORBIDDEN)
|
@ResponseStatus(HttpStatus.FORBIDDEN)
|
||||||
public ResponseMap handleForbiddenException(ForbiddenException e) {
|
public ResponseMap handleForbiddenException(ForbiddenException e) {
|
||||||
|
log.error(e.getMessage(), e);
|
||||||
return ResponseMap.of(HttpStatus.FORBIDDEN.value(), e.getMessage());
|
return ResponseMap.of(HttpStatus.FORBIDDEN.value(), e.getMessage());
|
||||||
}
|
}
|
||||||
|
|
||||||
@ExceptionHandler(BindException.class)
|
@ExceptionHandler(BindException.class)
|
||||||
@ResponseStatus(HttpStatus.BAD_REQUEST)
|
@ResponseStatus(HttpStatus.BAD_REQUEST)
|
||||||
public ResponseMap handleBindException(BindException e) {
|
public ResponseMap handleBindException(BindException e) {
|
||||||
|
log.error(e.getMessage(), e);
|
||||||
return ResponseMap.of(HttpStatus.BAD_REQUEST.value(),
|
return ResponseMap.of(HttpStatus.BAD_REQUEST.value(),
|
||||||
e.getAllErrors().stream()
|
e.getAllErrors().stream()
|
||||||
.map(DefaultMessageSourceResolvable::getDefaultMessage)
|
.map(DefaultMessageSourceResolvable::getDefaultMessage)
|
||||||
|
@ -56,6 +58,7 @@ public class ExceptionHandlerAdvice {
|
||||||
@ExceptionHandler(TooManyRequestException.class)
|
@ExceptionHandler(TooManyRequestException.class)
|
||||||
@ResponseStatus(HttpStatus.TOO_MANY_REQUESTS)
|
@ResponseStatus(HttpStatus.TOO_MANY_REQUESTS)
|
||||||
public ResponseMap handleTooManyRequestException(TooManyRequestException e) {
|
public ResponseMap handleTooManyRequestException(TooManyRequestException e) {
|
||||||
|
log.error(e.getMessage(), e);
|
||||||
return ResponseMap.of(HttpStatus.TOO_MANY_REQUESTS.value(), e.getMessage());
|
return ResponseMap.of(HttpStatus.TOO_MANY_REQUESTS.value(), e.getMessage());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,6 +7,7 @@ import java.util.concurrent.TimeUnit;
|
||||||
* @author 佘语殊
|
* @author 佘语殊
|
||||||
* @since 2022/7/11 16:57
|
* @since 2022/7/11 16:57
|
||||||
*/
|
*/
|
||||||
|
//TODO: 加到代码里
|
||||||
@Retention(RetentionPolicy.RUNTIME)
|
@Retention(RetentionPolicy.RUNTIME)
|
||||||
@Documented
|
@Documented
|
||||||
@Target({ElementType.METHOD})
|
@Target({ElementType.METHOD})
|
||||||
|
|
|
@ -38,7 +38,6 @@ public class RateLimitAOP {
|
||||||
if (limiter == null) {
|
if (limiter == null) {
|
||||||
limiter = RateLimiter.create(limit.permitsPerSecond());
|
limiter = RateLimiter.create(limit.permitsPerSecond());
|
||||||
Class<? extends RateLimiter> clazz = limiter.getClass();
|
Class<? extends RateLimiter> clazz = limiter.getClass();
|
||||||
//TODO: DEBUG TEST
|
|
||||||
Field burstSecondsField = clazz.getDeclaredField("maxBurstSeconds");
|
Field burstSecondsField = clazz.getDeclaredField("maxBurstSeconds");
|
||||||
burstSecondsField.setAccessible(true);
|
burstSecondsField.setAccessible(true);
|
||||||
burstSecondsField.set(limiter, limit.maxBurstSeconds());
|
burstSecondsField.set(limiter, limit.maxBurstSeconds());
|
||||||
|
|
|
@ -2,6 +2,7 @@ package cn.edu.hfut.rmdjzz.projectmanagement.config;
|
||||||
|
|
||||||
import com.baomidou.mybatisplus.annotation.DbType;
|
import com.baomidou.mybatisplus.annotation.DbType;
|
||||||
import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
|
import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
|
||||||
|
import com.baomidou.mybatisplus.extension.plugins.inner.BlockAttackInnerInterceptor;
|
||||||
import com.baomidou.mybatisplus.extension.plugins.inner.OptimisticLockerInnerInterceptor;
|
import com.baomidou.mybatisplus.extension.plugins.inner.OptimisticLockerInnerInterceptor;
|
||||||
import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;
|
import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;
|
||||||
import org.mybatis.spring.annotation.MapperScan;
|
import org.mybatis.spring.annotation.MapperScan;
|
||||||
|
@ -23,6 +24,7 @@ public class MybatisPlusConfig {
|
||||||
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
|
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
|
||||||
interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));
|
interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));
|
||||||
interceptor.addInnerInterceptor(new OptimisticLockerInnerInterceptor());
|
interceptor.addInnerInterceptor(new OptimisticLockerInnerInterceptor());
|
||||||
|
interceptor.addInnerInterceptor(new BlockAttackInnerInterceptor());
|
||||||
return interceptor;
|
return interceptor;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
package cn.edu.hfut.rmdjzz.projectmanagement.controller;
|
package cn.edu.hfut.rmdjzz.projectmanagement.controller;
|
||||||
|
|
||||||
|
import cn.edu.hfut.rmdjzz.projectmanagement.annotation.RateLimit;
|
||||||
import cn.edu.hfut.rmdjzz.projectmanagement.entity.Project;
|
import cn.edu.hfut.rmdjzz.projectmanagement.entity.Project;
|
||||||
import cn.edu.hfut.rmdjzz.projectmanagement.entity.dto.ProjectDTO;
|
import cn.edu.hfut.rmdjzz.projectmanagement.entity.dto.ProjectDTO;
|
||||||
import cn.edu.hfut.rmdjzz.projectmanagement.exception.BadRequestException;
|
import cn.edu.hfut.rmdjzz.projectmanagement.exception.BadRequestException;
|
||||||
|
@ -33,6 +34,7 @@ public class ProjectController {
|
||||||
private IProjectGroupService projectGroupService;
|
private IProjectGroupService projectGroupService;
|
||||||
|
|
||||||
@Operation(summary = "根据Token获取该员工的ProjectList")
|
@Operation(summary = "根据Token获取该员工的ProjectList")
|
||||||
|
//@RateLimit(permitsPerSecond = 1, maxBurstSeconds = 5)
|
||||||
@SneakyThrows
|
@SneakyThrows
|
||||||
@GetMapping
|
@GetMapping
|
||||||
public ResponseList<ProjectDTO> getProjectListOfStaff(
|
public ResponseList<ProjectDTO> getProjectListOfStaff(
|
||||||
|
|
|
@ -111,6 +111,7 @@ public class ProjectGroupController {
|
||||||
return ResponseMap.ofSuccess(projectGroupService.collectStatsForGroupPositions(token, projectId));
|
return ResponseMap.ofSuccess(projectGroupService.collectStatsForGroupPositions(token, projectId));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//FIXME: DELETE
|
||||||
@SneakyThrows
|
@SneakyThrows
|
||||||
@GetMapping("/{staffId}/stats")
|
@GetMapping("/{staffId}/stats")
|
||||||
public ResponseList<StaffProcessDTO> getProjectProcessOfStaff(
|
public ResponseList<StaffProcessDTO> getProjectProcessOfStaff(
|
||||||
|
|
|
@ -7,6 +7,7 @@ import cn.edu.hfut.rmdjzz.projectmanagement.exception.TokenException;
|
||||||
import cn.edu.hfut.rmdjzz.projectmanagement.service.IStaffService;
|
import cn.edu.hfut.rmdjzz.projectmanagement.service.IStaffService;
|
||||||
import cn.edu.hfut.rmdjzz.projectmanagement.utils.FileUtils;
|
import cn.edu.hfut.rmdjzz.projectmanagement.utils.FileUtils;
|
||||||
import cn.edu.hfut.rmdjzz.projectmanagement.utils.TokenUtils;
|
import cn.edu.hfut.rmdjzz.projectmanagement.utils.TokenUtils;
|
||||||
|
import cn.edu.hfut.rmdjzz.projectmanagement.utils.http.HttpUtils;
|
||||||
import cn.edu.hfut.rmdjzz.projectmanagement.utils.http.ResponseMap;
|
import cn.edu.hfut.rmdjzz.projectmanagement.utils.http.ResponseMap;
|
||||||
import io.swagger.v3.oas.annotations.Parameter;
|
import io.swagger.v3.oas.annotations.Parameter;
|
||||||
import lombok.SneakyThrows;
|
import lombok.SneakyThrows;
|
||||||
|
@ -15,6 +16,7 @@ import org.springframework.util.DigestUtils;
|
||||||
import org.springframework.web.bind.annotation.*;
|
import org.springframework.web.bind.annotation.*;
|
||||||
import org.springframework.web.multipart.MultipartFile;
|
import org.springframework.web.multipart.MultipartFile;
|
||||||
|
|
||||||
|
import javax.servlet.http.HttpServletRequest;
|
||||||
import javax.servlet.http.HttpServletResponse;
|
import javax.servlet.http.HttpServletResponse;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
|
|
||||||
|
@ -32,9 +34,12 @@ public class StaffController {
|
||||||
@PostMapping("/login")
|
@PostMapping("/login")
|
||||||
public ResponseMap login(
|
public ResponseMap login(
|
||||||
@Parameter(description = "只需要传入staffUsername和staffPassword两个属性即可,staffPassword需要md5加密后传输")
|
@Parameter(description = "只需要传入staffUsername和staffPassword两个属性即可,staffPassword需要md5加密后传输")
|
||||||
@RequestBody Staff staff
|
@RequestBody Staff staff,
|
||||||
|
HttpServletRequest request
|
||||||
) {
|
) {
|
||||||
return ResponseMap.ofSuccess("登录成功", staffService.login(staff.getStaffUsername(), staff.getStaffPassword()));
|
String requestIpAddress = HttpUtils.getRequestIpAddress(request);
|
||||||
|
return ResponseMap.ofSuccess("登录成功",
|
||||||
|
staffService.login(requestIpAddress, staff.getStaffUsername(), staff.getStaffPassword()));
|
||||||
}
|
}
|
||||||
|
|
||||||
@SneakyThrows
|
@SneakyThrows
|
||||||
|
|
|
@ -25,6 +25,7 @@ public class TaskController {
|
||||||
private ITaskService taskService;
|
private ITaskService taskService;
|
||||||
@Autowired
|
@Autowired
|
||||||
private IProjectService projectService;
|
private IProjectService projectService;
|
||||||
|
|
||||||
@SneakyThrows
|
@SneakyThrows
|
||||||
@GetMapping("/{fatherId}/subtask")
|
@GetMapping("/{fatherId}/subtask")
|
||||||
public ResponseList<TaskDTO> getSubTaskList(
|
public ResponseList<TaskDTO> getSubTaskList(
|
||||||
|
@ -61,7 +62,7 @@ public class TaskController {
|
||||||
@PathVariable("projectId") Integer projectId,
|
@PathVariable("projectId") Integer projectId,
|
||||||
@RequestBody Task task
|
@RequestBody Task task
|
||||||
) {
|
) {
|
||||||
if(!projectService.checkOpenStatus(projectId))
|
if (!projectService.checkOpenStatus(projectId))
|
||||||
throw new BadRequestException(IProjectService.PROJECT_UNOPENED);
|
throw new BadRequestException(IProjectService.PROJECT_UNOPENED);
|
||||||
task.setTaskProjectId(projectId);
|
task.setTaskProjectId(projectId);
|
||||||
taskService.insertTask(token, task);
|
taskService.insertTask(token, task);
|
||||||
|
@ -76,7 +77,7 @@ public class TaskController {
|
||||||
@PathVariable("taskId") Long taskId,
|
@PathVariable("taskId") Long taskId,
|
||||||
@RequestBody Task task
|
@RequestBody Task task
|
||||||
) {
|
) {
|
||||||
if(!projectService.checkOpenStatus(projectId))
|
if (!projectService.checkOpenStatus(projectId))
|
||||||
throw new BadRequestException(IProjectService.PROJECT_UNOPENED);
|
throw new BadRequestException(IProjectService.PROJECT_UNOPENED);
|
||||||
task.setTaskProjectId(projectId);
|
task.setTaskProjectId(projectId);
|
||||||
task.setTaskId(taskId);
|
task.setTaskId(taskId);
|
||||||
|
@ -91,22 +92,32 @@ public class TaskController {
|
||||||
@PathVariable("projectId") Integer projectId,
|
@PathVariable("projectId") Integer projectId,
|
||||||
@PathVariable("taskId") Long taskId
|
@PathVariable("taskId") Long taskId
|
||||||
) {
|
) {
|
||||||
if(!projectService.checkOpenStatus(projectId))
|
if (!projectService.checkOpenStatus(projectId))
|
||||||
throw new BadRequestException(IProjectService.PROJECT_UNOPENED);
|
throw new BadRequestException(IProjectService.PROJECT_UNOPENED);
|
||||||
taskService.deleteTaskAndSubTask(token, projectId, taskId);
|
taskService.deleteTaskAndSubTask(token, projectId, taskId);
|
||||||
return ResponseMap.ofSuccess();
|
return ResponseMap.ofSuccess();
|
||||||
}
|
}
|
||||||
|
|
||||||
@SneakyThrows
|
@SneakyThrows
|
||||||
@GetMapping("/stats")
|
@GetMapping("/stats/trend")
|
||||||
public ResponseMap getTaskTrend(
|
public ResponseMap getTaskTrend(
|
||||||
@RequestHeader(TokenUtils.HEADER_TOKEN) String token,
|
@RequestHeader(TokenUtils.HEADER_TOKEN) String token,
|
||||||
@PathVariable Integer projectId
|
@PathVariable Integer projectId
|
||||||
) {
|
) {
|
||||||
if(!projectService.checkOpenStatus(projectId)) {
|
if (!projectService.checkOpenStatus(projectId)) {
|
||||||
throw new BadRequestException(IProjectService.PROJECT_UNOPENED);
|
throw new BadRequestException(IProjectService.PROJECT_UNOPENED);
|
||||||
}
|
}
|
||||||
return ResponseMap.ofSuccess("查询成功", taskService.getProjectTaskTrend(token, projectId));
|
return ResponseMap.ofSuccess("查询成功", taskService.getProjectTaskTrend(token, projectId));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//TODO:
|
||||||
|
@GetMapping({"/stats", "/stats/{staffId}"})
|
||||||
|
public ResponseMap getProjectStatistics(
|
||||||
|
@RequestHeader(TokenUtils.HEADER_TOKEN) String token,
|
||||||
|
@PathVariable Integer projectId,
|
||||||
|
@PathVariable(required = false) Integer staffId
|
||||||
|
) {
|
||||||
|
return ResponseMap.ofSuccess();
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,7 +27,6 @@ public class TaskDTO {
|
||||||
private LocalDateTime taskClosedTime;
|
private LocalDateTime taskClosedTime;
|
||||||
private Integer taskPriority;
|
private Integer taskPriority;
|
||||||
private String taskDescription;
|
private String taskDescription;
|
||||||
@TableField(typeHandler = JacksonTypeHandler.class)
|
|
||||||
private Map<String, Object> attachedInfo;
|
private Map<String, Object> attachedInfo;
|
||||||
private Boolean hasChildren;
|
private Integer childrenCount;
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,7 +17,7 @@ public interface IStaffService extends IService<Staff> {
|
||||||
|
|
||||||
String STAFF_DOES_NOT_EXIST = "用户不存在";
|
String STAFF_DOES_NOT_EXIST = "用户不存在";
|
||||||
|
|
||||||
Map<String, Object> login(String username, String password) throws BadRequestException, TokenException;
|
Map<String, Object> login(String requestIpAddress, String username, String password) throws BadRequestException, TokenException, ForbiddenException;
|
||||||
|
|
||||||
Boolean logout(String token) throws TokenException;
|
Boolean logout(String token) throws TokenException;
|
||||||
|
|
||||||
|
|
|
@ -7,6 +7,7 @@ import cn.edu.hfut.rmdjzz.projectmanagement.mapper.StaffMapper;
|
||||||
import cn.edu.hfut.rmdjzz.projectmanagement.service.IStaffService;
|
import cn.edu.hfut.rmdjzz.projectmanagement.service.IStaffService;
|
||||||
import cn.edu.hfut.rmdjzz.projectmanagement.utils.BeanUtils;
|
import cn.edu.hfut.rmdjzz.projectmanagement.utils.BeanUtils;
|
||||||
import cn.edu.hfut.rmdjzz.projectmanagement.utils.MapBuilder;
|
import cn.edu.hfut.rmdjzz.projectmanagement.utils.MapBuilder;
|
||||||
|
import cn.edu.hfut.rmdjzz.projectmanagement.utils.TimeUtils;
|
||||||
import cn.edu.hfut.rmdjzz.projectmanagement.utils.TokenUtils;
|
import cn.edu.hfut.rmdjzz.projectmanagement.utils.TokenUtils;
|
||||||
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
|
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
|
||||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||||
|
@ -35,26 +36,44 @@ import java.util.concurrent.TimeUnit;
|
||||||
@Service
|
@Service
|
||||||
public class StaffServiceImpl extends ServiceImpl<StaffMapper, Staff> implements IStaffService {
|
public class StaffServiceImpl extends ServiceImpl<StaffMapper, Staff> implements IStaffService {
|
||||||
private static final Long tokenDuration = 5 * 60 * 60L;
|
private static final Long tokenDuration = 5 * 60 * 60L;
|
||||||
|
private static final int LOGIN_TRY_COUNT_TIMEOUT = 15; //minutes
|
||||||
|
private static final int LOGIN_MAX_TRY_COUNT = 5;
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
private RedisTemplate<Object, Object> redisTemplate;
|
private RedisTemplate<Object, Object> redisTemplate;
|
||||||
|
|
||||||
//TODO: ban掉多次登录失败的IP
|
@SuppressWarnings("ConstantConditions")
|
||||||
@Override
|
@Override
|
||||||
public Map<String, Object> login(String staffUsername, String password) throws BadRequestException {
|
public Map<String, Object> login(String requestIpAddress, String staffUsername, String password) throws BadRequestException, ForbiddenException {
|
||||||
|
if (Boolean.FALSE.equals(redisTemplate.hasKey(requestIpAddress))) {
|
||||||
|
redisTemplate.opsForValue().set(requestIpAddress, 0, LOGIN_TRY_COUNT_TIMEOUT, TimeUnit.MINUTES);
|
||||||
|
}
|
||||||
|
int loginCount = (int) redisTemplate.opsForValue().get(requestIpAddress);
|
||||||
|
|
||||||
|
if (loginCount >= LOGIN_MAX_TRY_COUNT) {
|
||||||
|
throw new ForbiddenException(String.format("还需要等待%s才能登录"
|
||||||
|
, TimeUtils.secondsFormat(redisTemplate.getExpire(requestIpAddress))));
|
||||||
|
}
|
||||||
|
|
||||||
if (staffUsername == null || staffUsername.strip().length() == 0)
|
if (staffUsername == null || staffUsername.strip().length() == 0)
|
||||||
throw new BadRequestException("用户名为空");
|
//throw new BadRequestException("用户名为空");
|
||||||
else if (!staffUsername.equals(staffUsername.replaceAll("[^a-zA-Z0-9]", "")))
|
throwLoginException(requestIpAddress, loginCount);
|
||||||
throw new BadRequestException("用户名格式错误");
|
if (!staffUsername.equals(staffUsername.replaceAll("[^a-zA-Z0-9]", "")))
|
||||||
else if (password == null || password.trim().length() != 32)
|
//throw new BadRequestException("用户名格式错误");
|
||||||
throw new BadRequestException("密码格式错误");
|
throwLoginException(requestIpAddress, loginCount);
|
||||||
|
if (password == null || password.trim().length() != 32)
|
||||||
|
//throw new BadRequestException("密码格式错误");
|
||||||
|
throwLoginException(requestIpAddress, loginCount);
|
||||||
|
|
||||||
Staff staff = getOne(Wrappers.<Staff>lambdaQuery().eq(Staff::getStaffUsername, staffUsername));
|
Staff staff = getOne(Wrappers.<Staff>lambdaQuery().eq(Staff::getStaffUsername, staffUsername));
|
||||||
if (staff == null)
|
if (staff == null)
|
||||||
throw new BadRequestException(STAFF_DOES_NOT_EXIST);
|
//throw new BadRequestException(STAFF_DOES_NOT_EXIST);
|
||||||
|
throwLoginException(requestIpAddress, loginCount);
|
||||||
|
|
||||||
password = DigestUtils.md5DigestAsHex((password + staff.getStaffSalt()).getBytes());
|
password = DigestUtils.md5DigestAsHex((password + staff.getStaffSalt()).getBytes());
|
||||||
if (!staff.getStaffPassword().equals(password))
|
if (!staff.getStaffPassword().equals(password)) {
|
||||||
throw new BadRequestException("密码错误");
|
throwLoginException(requestIpAddress, loginCount);
|
||||||
|
}
|
||||||
String token = TokenUtils.getToken(staff.getStaffUsername(), staff.getStaffId(), staff.getStaffGlobalLevel(), tokenDuration);
|
String token = TokenUtils.getToken(staff.getStaffUsername(), staff.getStaffId(), staff.getStaffGlobalLevel(), tokenDuration);
|
||||||
redisTemplate.opsForValue().set(
|
redisTemplate.opsForValue().set(
|
||||||
Objects.<Integer>requireNonNull(TokenUtils.getStaffId(token)),
|
Objects.<Integer>requireNonNull(TokenUtils.getStaffId(token)),
|
||||||
|
@ -67,6 +86,11 @@ public class StaffServiceImpl extends ServiceImpl<StaffMapper, Staff> implements
|
||||||
.build();
|
.build();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void throwLoginException(String requestIpAddress, int loginCount) throws BadRequestException {
|
||||||
|
redisTemplate.opsForValue().set(requestIpAddress, ++loginCount, LOGIN_TRY_COUNT_TIMEOUT, TimeUnit.MINUTES);
|
||||||
|
throw new BadRequestException(String.format("登录失败,%d分钟内还有%d次登录机会", LOGIN_TRY_COUNT_TIMEOUT, LOGIN_MAX_TRY_COUNT - loginCount));
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Boolean logout(String token) {
|
public Boolean logout(String token) {
|
||||||
Integer staffId = TokenUtils.getStaffId(token);
|
Integer staffId = TokenUtils.getStaffId(token);
|
||||||
|
|
|
@ -286,10 +286,14 @@ public class TaskServiceImpl extends ServiceImpl<TaskMapper, Task> implements IT
|
||||||
task.setTaskStatus(Task.STATUS_WAITING);
|
task.setTaskStatus(Task.STATUS_WAITING);
|
||||||
task.setChildrenCount(0);
|
task.setChildrenCount(0);
|
||||||
task.setTaskClosedTime(null);
|
task.setTaskClosedTime(null);
|
||||||
if (baseMapper.insert(task) == 0) {
|
if (baseMapper.insert(task) == 0 ||
|
||||||
|
baseMapper.update(null,
|
||||||
|
Wrappers.<Task>lambdaUpdate()
|
||||||
|
.eq(Task::getTaskId, task.getTaskFatherId())
|
||||||
|
.setSql("children_count = children_count + 1")) != 1
|
||||||
|
) {
|
||||||
throw new BadRequestException(BadRequestException.OPERATE_FAILED);
|
throw new BadRequestException(BadRequestException.OPERATE_FAILED);
|
||||||
}
|
}
|
||||||
baseMapper.update(null, Wrappers.<Task>lambdaUpdate().setSql("children_count = children_count + 1"));
|
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
log.error(e.getMessage(), e);
|
log.error(e.getMessage(), e);
|
||||||
throw new BadRequestException(BadRequestException.OPERATE_FAILED);
|
throw new BadRequestException(BadRequestException.OPERATE_FAILED);
|
||||||
|
|
|
@ -84,6 +84,9 @@ public class BeanUtils {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 检查object是否在set中
|
||||||
|
*/
|
||||||
public static boolean checkInSet(Object object, Object... set) {
|
public static boolean checkInSet(Object object, Object... set) {
|
||||||
return Arrays.asList(set).contains(object);
|
return Arrays.asList(set).contains(object);
|
||||||
}
|
}
|
||||||
|
|
|
@ -63,4 +63,22 @@ public class TimeUtils {
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 最大格式化单位为分钟,有需求再改
|
||||||
|
*/
|
||||||
|
public static String secondsFormat(long seconds) {
|
||||||
|
long minutes = 0;
|
||||||
|
if ((minutes = seconds / 60) > 0) {
|
||||||
|
seconds %= 60;
|
||||||
|
}
|
||||||
|
StringBuilder sb = new StringBuilder();
|
||||||
|
if (minutes > 0) {
|
||||||
|
sb.append(minutes).append("分");
|
||||||
|
}
|
||||||
|
if (seconds > 0) {
|
||||||
|
sb.append(seconds).append("秒");
|
||||||
|
}
|
||||||
|
return sb.toString();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,48 @@
|
||||||
|
package cn.edu.hfut.rmdjzz.projectmanagement.utils.http;
|
||||||
|
|
||||||
|
import javax.servlet.http.HttpServletRequest;
|
||||||
|
import java.net.InetAddress;
|
||||||
|
import java.net.UnknownHostException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author 佘语殊
|
||||||
|
* @since 2022/7/12 10:57
|
||||||
|
*/
|
||||||
|
public class HttpUtils {
|
||||||
|
public static String getRequestIpAddress(HttpServletRequest request) {
|
||||||
|
String ipAddress = null;
|
||||||
|
try {
|
||||||
|
ipAddress = request.getHeader("x-forwarded-for");
|
||||||
|
if (ipAddress == null || ipAddress.length() == 0 || "unknown".equalsIgnoreCase(ipAddress)) {
|
||||||
|
ipAddress = request.getHeader("Proxy-Client-IP");
|
||||||
|
}
|
||||||
|
if (ipAddress == null || ipAddress.length() == 0 || "unknown".equalsIgnoreCase(ipAddress)) {
|
||||||
|
ipAddress = request.getHeader("WL-Proxy-Client-IP");
|
||||||
|
}
|
||||||
|
if (ipAddress == null || ipAddress.length() == 0 || "unknown".equalsIgnoreCase(ipAddress)) {
|
||||||
|
ipAddress = request.getRemoteAddr();
|
||||||
|
if (ipAddress.equals("127.0.0.1")) {
|
||||||
|
// 根据网卡取本机配置的IP
|
||||||
|
InetAddress inet = null;
|
||||||
|
try {
|
||||||
|
inet = InetAddress.getLocalHost();
|
||||||
|
} catch (UnknownHostException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
ipAddress = inet.getHostAddress();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// 对于通过多个代理的情况,第一个IP为客户端真实IP,多个IP按照','分割
|
||||||
|
if (ipAddress != null && ipAddress.length() > 15) { // "***.***.***.***".length()
|
||||||
|
// = 15
|
||||||
|
if (ipAddress.indexOf(",") > 0) {
|
||||||
|
ipAddress = ipAddress.substring(0, ipAddress.indexOf(","));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
ipAddress = "";
|
||||||
|
}
|
||||||
|
// ipAddress = this.getRequest().getRemoteAddr();
|
||||||
|
return ipAddress;
|
||||||
|
}
|
||||||
|
}
|
|
@ -11,7 +11,7 @@
|
||||||
task_name,
|
task_name,
|
||||||
task_project_id,
|
task_project_id,
|
||||||
task_holder_id,
|
task_holder_id,
|
||||||
s.staff_fullname AS task_holder_name,
|
s.staff_fullname AS task_holder_name,
|
||||||
task_status,
|
task_status,
|
||||||
task_type,
|
task_type,
|
||||||
t.task_father_id,
|
t.task_father_id,
|
||||||
|
@ -22,11 +22,9 @@
|
||||||
task_priority,
|
task_priority,
|
||||||
task_description,
|
task_description,
|
||||||
attached_info,
|
attached_info,
|
||||||
judge.task_father_id IS NOT NULL AS has_children
|
children_count
|
||||||
FROM task AS t
|
FROM task AS t
|
||||||
JOIN (SELECT staff_id, staff_fullname FROM staff) AS s ON t.task_holder_id = s.staff_id
|
JOIN (SELECT staff_id, staff_fullname FROM staff) AS s ON t.task_holder_id = s.staff_id
|
||||||
LEFT JOIN (SELECT DISTINCT task_father_id FROM task WHERE is_deleted = 0) AS judge
|
|
||||||
ON t.task_id = judge.task_father_id
|
|
||||||
WHERE is_deleted = 0
|
WHERE is_deleted = 0
|
||||||
AND task_project_id = #{projectId}
|
AND task_project_id = #{projectId}
|
||||||
AND t.task_father_id = #{fatherId}
|
AND t.task_father_id = #{fatherId}
|
||||||
|
|
|
@ -18,7 +18,7 @@ public class RedisTests {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void test() {
|
void test() {
|
||||||
redisTemplate.opsForList().rightPush(123456, 89);
|
System.out.println(redisTemplate.opsForValue().get("l1"));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|
Loading…
Reference in New Issue