mirror of
https://github.com/201206030/novel-plus.git
synced 2025-07-19 07:36:39 +00:00
fix: 修复sort和order参数的SQL注入漏洞
This commit is contained in:
@ -0,0 +1,13 @@
|
|||||||
|
package com.java2nb.common.annotation;
|
||||||
|
|
||||||
|
import java.lang.annotation.*;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author xiongxiaoyang
|
||||||
|
* @date 2025/7/17
|
||||||
|
*/
|
||||||
|
@Target(ElementType.PARAMETER)
|
||||||
|
@Retention(RetentionPolicy.RUNTIME)
|
||||||
|
@Documented
|
||||||
|
public @interface ValidateSortOrder {
|
||||||
|
}
|
@ -0,0 +1,90 @@
|
|||||||
|
package com.java2nb.common.aspect;
|
||||||
|
|
||||||
|
import com.java2nb.common.annotation.ValidateSortOrder;
|
||||||
|
import com.java2nb.common.utils.SortWhitelistUtil;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import lombok.SneakyThrows;
|
||||||
|
import org.aspectj.lang.ProceedingJoinPoint;
|
||||||
|
import org.aspectj.lang.annotation.Around;
|
||||||
|
import org.aspectj.lang.annotation.Aspect;
|
||||||
|
import org.aspectj.lang.reflect.MethodSignature;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
import java.lang.annotation.Annotation;
|
||||||
|
import java.lang.reflect.Field;
|
||||||
|
import java.lang.reflect.Method;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author xiongxiaoyang
|
||||||
|
* @date 2025/7/17
|
||||||
|
*/
|
||||||
|
@Aspect
|
||||||
|
@Component
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
public class SortOrderValidationAspect {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 拦截所有的mapper方法
|
||||||
|
*/
|
||||||
|
@SneakyThrows
|
||||||
|
@Around("execution(* com.java2nb.*.dao.*Dao.*(..))")
|
||||||
|
public Object validateSortAndOrder(ProceedingJoinPoint joinPoint) {
|
||||||
|
Object[] args = joinPoint.getArgs();
|
||||||
|
MethodSignature signature = (MethodSignature) joinPoint.getSignature();
|
||||||
|
Method method = signature.getMethod();
|
||||||
|
|
||||||
|
Annotation[][] parameterAnnotations = method.getParameterAnnotations();
|
||||||
|
|
||||||
|
for (int i = 0; i < parameterAnnotations.length; i++) {
|
||||||
|
boolean hasAnnotation = Arrays.stream(parameterAnnotations[i])
|
||||||
|
.anyMatch(a -> a.annotationType().equals(ValidateSortOrder.class));
|
||||||
|
|
||||||
|
if (hasAnnotation && args[i] != null) {
|
||||||
|
processArgument(args[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return joinPoint.proceed(args);
|
||||||
|
}
|
||||||
|
|
||||||
|
@SneakyThrows
|
||||||
|
private void processArgument(Object obj) {
|
||||||
|
if (obj instanceof Map<?,?> map) {
|
||||||
|
processMap(map);
|
||||||
|
} else {
|
||||||
|
traverseAndSanitize(obj);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@SneakyThrows
|
||||||
|
private void traverseAndSanitize(Object obj) {
|
||||||
|
for (Field field : obj.getClass().getDeclaredFields()) {
|
||||||
|
switch (field.getName()) {
|
||||||
|
case "sort", "order" -> {
|
||||||
|
field.setAccessible(true);
|
||||||
|
Object value = field.get(obj);
|
||||||
|
if (value instanceof String strValue) {
|
||||||
|
String sanitized = "sort".equals(field.getName())
|
||||||
|
? SortWhitelistUtil.sanitizeColumn(strValue)
|
||||||
|
: SortWhitelistUtil.sanitizeOrder(strValue);
|
||||||
|
field.set(obj, sanitized);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
default -> {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void processMap(Map map) {
|
||||||
|
if (map.get("sort") instanceof String sortStr) {
|
||||||
|
map.put("sort", SortWhitelistUtil.sanitizeColumn(sortStr));
|
||||||
|
}
|
||||||
|
if (map.get("order") instanceof String orderStr) {
|
||||||
|
map.put("order", SortWhitelistUtil.sanitizeOrder(orderStr));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -1,5 +1,6 @@
|
|||||||
package com.java2nb.common.dao;
|
package com.java2nb.common.dao;
|
||||||
|
|
||||||
|
import com.java2nb.common.annotation.ValidateSortOrder;
|
||||||
import com.java2nb.common.domain.DictDO;
|
import com.java2nb.common.domain.DictDO;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@ -19,7 +20,7 @@ public interface DictDao {
|
|||||||
|
|
||||||
DictDO get(Long id);
|
DictDO get(Long id);
|
||||||
|
|
||||||
List<DictDO> list(Map<String, Object> map);
|
List<DictDO> list(@ValidateSortOrder Map<String, Object> map);
|
||||||
|
|
||||||
int count(Map<String, Object> map);
|
int count(Map<String, Object> map);
|
||||||
|
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
package com.java2nb.common.dao;
|
package com.java2nb.common.dao;
|
||||||
|
|
||||||
|
import com.java2nb.common.annotation.ValidateSortOrder;
|
||||||
import com.java2nb.common.domain.FileDO;
|
import com.java2nb.common.domain.FileDO;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@ -18,7 +19,7 @@ public interface FileDao {
|
|||||||
|
|
||||||
FileDO get(Long id);
|
FileDO get(Long id);
|
||||||
|
|
||||||
List<FileDO> list(Map<String,Object> map);
|
List<FileDO> list(@ValidateSortOrder Map<String,Object> map);
|
||||||
|
|
||||||
int count(Map<String,Object> map);
|
int count(Map<String,Object> map);
|
||||||
|
|
||||||
|
@ -3,6 +3,7 @@ package com.java2nb.common.dao;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
|
import com.java2nb.common.annotation.ValidateSortOrder;
|
||||||
import com.java2nb.common.domain.GenColumnsDO;
|
import com.java2nb.common.domain.GenColumnsDO;
|
||||||
import org.apache.ibatis.annotations.Mapper;
|
import org.apache.ibatis.annotations.Mapper;
|
||||||
import org.apache.ibatis.annotations.Param;
|
import org.apache.ibatis.annotations.Param;
|
||||||
@ -19,7 +20,7 @@ public interface GenColumnsDao {
|
|||||||
|
|
||||||
GenColumnsDO get(Long id);
|
GenColumnsDO get(Long id);
|
||||||
|
|
||||||
List<GenColumnsDO> list(Map<String,Object> map);
|
List<GenColumnsDO> list(@ValidateSortOrder Map<String,Object> map);
|
||||||
|
|
||||||
int count(Map<String,Object> map);
|
int count(Map<String,Object> map);
|
||||||
|
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
package com.java2nb.common.dao;
|
package com.java2nb.common.dao;
|
||||||
|
|
||||||
|
import com.java2nb.common.annotation.ValidateSortOrder;
|
||||||
import com.java2nb.common.domain.LogDO;
|
import com.java2nb.common.domain.LogDO;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@ -18,7 +19,7 @@ public interface LogDao {
|
|||||||
|
|
||||||
LogDO get(Long id);
|
LogDO get(Long id);
|
||||||
|
|
||||||
List<LogDO> list(Map<String,Object> map);
|
List<LogDO> list(@ValidateSortOrder Map<String,Object> map);
|
||||||
|
|
||||||
int count(Map<String,Object> map);
|
int count(Map<String,Object> map);
|
||||||
|
|
||||||
|
@ -0,0 +1,28 @@
|
|||||||
|
package com.java2nb.common.utils;
|
||||||
|
|
||||||
|
import lombok.experimental.UtilityClass;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author xiongxiaoyang
|
||||||
|
* @date 2025/7/17
|
||||||
|
*/
|
||||||
|
@UtilityClass
|
||||||
|
public class SortWhitelistUtil {
|
||||||
|
|
||||||
|
private final Set<String> allowedColumns = new HashSet<>(
|
||||||
|
Arrays.asList("id", "name", "create_time", "update_time", "order_num", "last_index_update_time", "word_count",
|
||||||
|
"visit_count"));
|
||||||
|
private final Set<String> allowedOrders = new HashSet<>(Arrays.asList("asc", "desc"));
|
||||||
|
|
||||||
|
public String sanitizeColumn(String input) {
|
||||||
|
return allowedColumns.contains(input.toLowerCase()) ? input.toLowerCase() : "id";
|
||||||
|
}
|
||||||
|
|
||||||
|
public String sanitizeOrder(String input) {
|
||||||
|
return allowedOrders.contains(input.toLowerCase()) ? input.toLowerCase() : "asc";
|
||||||
|
}
|
||||||
|
}
|
@ -1,5 +1,7 @@
|
|||||||
package com.java2nb.novel.dao;
|
package com.java2nb.novel.dao;
|
||||||
|
|
||||||
|
import com.java2nb.common.annotation.ValidateSortOrder;
|
||||||
|
|
||||||
import com.java2nb.novel.domain.AuthorCodeDO;
|
import com.java2nb.novel.domain.AuthorCodeDO;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@ -18,7 +20,7 @@ public interface AuthorCodeDao {
|
|||||||
|
|
||||||
AuthorCodeDO get(Long id);
|
AuthorCodeDO get(Long id);
|
||||||
|
|
||||||
List<AuthorCodeDO> list(Map<String,Object> map);
|
List<AuthorCodeDO> list(@ValidateSortOrder Map<String,Object> map);
|
||||||
|
|
||||||
int count(Map<String,Object> map);
|
int count(Map<String,Object> map);
|
||||||
|
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
package com.java2nb.novel.dao;
|
package com.java2nb.novel.dao;
|
||||||
|
|
||||||
|
import com.java2nb.common.annotation.ValidateSortOrder;
|
||||||
import com.java2nb.novel.domain.AuthorDO;
|
import com.java2nb.novel.domain.AuthorDO;
|
||||||
|
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
@ -19,7 +20,7 @@ public interface AuthorDao {
|
|||||||
|
|
||||||
AuthorDO get(Long id);
|
AuthorDO get(Long id);
|
||||||
|
|
||||||
List<AuthorDO> list(Map<String,Object> map);
|
List<AuthorDO> list(@ValidateSortOrder Map<String,Object> map);
|
||||||
|
|
||||||
int count(Map<String,Object> map);
|
int count(Map<String,Object> map);
|
||||||
|
|
||||||
|
@ -1,5 +1,7 @@
|
|||||||
package com.java2nb.novel.dao;
|
package com.java2nb.novel.dao;
|
||||||
|
|
||||||
|
import com.java2nb.common.annotation.ValidateSortOrder;
|
||||||
|
|
||||||
import com.java2nb.novel.domain.BookCommentDO;
|
import com.java2nb.novel.domain.BookCommentDO;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@ -18,7 +20,7 @@ public interface BookCommentDao {
|
|||||||
|
|
||||||
BookCommentDO get(Long id);
|
BookCommentDO get(Long id);
|
||||||
|
|
||||||
List<BookCommentDO> list(Map<String,Object> map);
|
List<BookCommentDO> list(@ValidateSortOrder Map<String,Object> map);
|
||||||
|
|
||||||
int count(Map<String,Object> map);
|
int count(Map<String,Object> map);
|
||||||
|
|
||||||
|
@ -1,5 +1,7 @@
|
|||||||
package com.java2nb.novel.dao;
|
package com.java2nb.novel.dao;
|
||||||
|
|
||||||
|
import com.java2nb.common.annotation.ValidateSortOrder;
|
||||||
|
|
||||||
import com.java2nb.novel.domain.BookContentDO;
|
import com.java2nb.novel.domain.BookContentDO;
|
||||||
import org.apache.ibatis.annotations.Mapper;
|
import org.apache.ibatis.annotations.Mapper;
|
||||||
|
|
||||||
@ -18,7 +20,7 @@ public interface BookContentDao {
|
|||||||
|
|
||||||
BookContentDO get(Long id);
|
BookContentDO get(Long id);
|
||||||
|
|
||||||
List<BookContentDO> list(Map<String, Object> map);
|
List<BookContentDO> list(@ValidateSortOrder Map<String, Object> map);
|
||||||
|
|
||||||
int count(Map<String, Object> map);
|
int count(Map<String, Object> map);
|
||||||
|
|
||||||
|
@ -1,5 +1,7 @@
|
|||||||
package com.java2nb.novel.dao;
|
package com.java2nb.novel.dao;
|
||||||
|
|
||||||
|
import com.java2nb.common.annotation.ValidateSortOrder;
|
||||||
|
|
||||||
import com.java2nb.novel.domain.BookDO;
|
import com.java2nb.novel.domain.BookDO;
|
||||||
import org.apache.ibatis.annotations.Mapper;
|
import org.apache.ibatis.annotations.Mapper;
|
||||||
|
|
||||||
@ -19,7 +21,7 @@ public interface BookDao {
|
|||||||
|
|
||||||
BookDO get(Long id);
|
BookDO get(Long id);
|
||||||
|
|
||||||
List<BookDO> list(Map<String, Object> map);
|
List<BookDO> list(@ValidateSortOrder Map<String, Object> map);
|
||||||
|
|
||||||
int count(Map<String, Object> map);
|
int count(Map<String, Object> map);
|
||||||
|
|
||||||
|
@ -1,5 +1,7 @@
|
|||||||
package com.java2nb.novel.dao;
|
package com.java2nb.novel.dao;
|
||||||
|
|
||||||
|
import com.java2nb.common.annotation.ValidateSortOrder;
|
||||||
|
|
||||||
import com.java2nb.novel.domain.BookIndexDO;
|
import com.java2nb.novel.domain.BookIndexDO;
|
||||||
import org.apache.ibatis.annotations.Mapper;
|
import org.apache.ibatis.annotations.Mapper;
|
||||||
|
|
||||||
@ -18,7 +20,7 @@ public interface BookIndexDao {
|
|||||||
|
|
||||||
BookIndexDO get(Long id);
|
BookIndexDO get(Long id);
|
||||||
|
|
||||||
List<BookIndexDO> list(Map<String, Object> map);
|
List<BookIndexDO> list(@ValidateSortOrder Map<String, Object> map);
|
||||||
|
|
||||||
int count(Map<String, Object> map);
|
int count(Map<String, Object> map);
|
||||||
|
|
||||||
|
@ -1,5 +1,7 @@
|
|||||||
package com.java2nb.novel.dao;
|
package com.java2nb.novel.dao;
|
||||||
|
|
||||||
|
import com.java2nb.common.annotation.ValidateSortOrder;
|
||||||
|
|
||||||
import com.java2nb.novel.domain.BookSettingDO;
|
import com.java2nb.novel.domain.BookSettingDO;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@ -18,7 +20,7 @@ public interface BookSettingDao {
|
|||||||
|
|
||||||
BookSettingDO get(Long id);
|
BookSettingDO get(Long id);
|
||||||
|
|
||||||
List<BookSettingDO> list(Map<String,Object> map);
|
List<BookSettingDO> list(@ValidateSortOrder Map<String,Object> map);
|
||||||
|
|
||||||
int count(Map<String,Object> map);
|
int count(Map<String,Object> map);
|
||||||
|
|
||||||
|
@ -1,5 +1,7 @@
|
|||||||
package com.java2nb.novel.dao;
|
package com.java2nb.novel.dao;
|
||||||
|
|
||||||
|
import com.java2nb.common.annotation.ValidateSortOrder;
|
||||||
|
|
||||||
import com.java2nb.novel.domain.CategoryDO;
|
import com.java2nb.novel.domain.CategoryDO;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@ -18,7 +20,7 @@ public interface CategoryDao {
|
|||||||
|
|
||||||
CategoryDO get(Integer id);
|
CategoryDO get(Integer id);
|
||||||
|
|
||||||
List<CategoryDO> list(Map<String,Object> map);
|
List<CategoryDO> list(@ValidateSortOrder Map<String,Object> map);
|
||||||
|
|
||||||
int count(Map<String,Object> map);
|
int count(Map<String,Object> map);
|
||||||
|
|
||||||
|
@ -1,5 +1,7 @@
|
|||||||
package com.java2nb.novel.dao;
|
package com.java2nb.novel.dao;
|
||||||
|
|
||||||
|
import com.java2nb.common.annotation.ValidateSortOrder;
|
||||||
|
|
||||||
import com.java2nb.novel.domain.FriendLinkDO;
|
import com.java2nb.novel.domain.FriendLinkDO;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@ -18,7 +20,7 @@ public interface FriendLinkDao {
|
|||||||
|
|
||||||
FriendLinkDO get(Integer id);
|
FriendLinkDO get(Integer id);
|
||||||
|
|
||||||
List<FriendLinkDO> list(Map<String,Object> map);
|
List<FriendLinkDO> list(@ValidateSortOrder Map<String,Object> map);
|
||||||
|
|
||||||
int count(Map<String,Object> map);
|
int count(Map<String,Object> map);
|
||||||
|
|
||||||
|
@ -1,5 +1,7 @@
|
|||||||
package com.java2nb.novel.dao;
|
package com.java2nb.novel.dao;
|
||||||
|
|
||||||
|
import com.java2nb.common.annotation.ValidateSortOrder;
|
||||||
|
|
||||||
import com.java2nb.novel.domain.NewsDO;
|
import com.java2nb.novel.domain.NewsDO;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@ -18,7 +20,7 @@ public interface NewsDao {
|
|||||||
|
|
||||||
NewsDO get(Long id);
|
NewsDO get(Long id);
|
||||||
|
|
||||||
List<NewsDO> list(Map<String,Object> map);
|
List<NewsDO> list(@ValidateSortOrder Map<String,Object> map);
|
||||||
|
|
||||||
int count(Map<String,Object> map);
|
int count(Map<String,Object> map);
|
||||||
|
|
||||||
|
@ -1,5 +1,7 @@
|
|||||||
package com.java2nb.novel.dao;
|
package com.java2nb.novel.dao;
|
||||||
|
|
||||||
|
import com.java2nb.common.annotation.ValidateSortOrder;
|
||||||
|
|
||||||
import com.java2nb.novel.domain.PayDO;
|
import com.java2nb.novel.domain.PayDO;
|
||||||
|
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
@ -19,7 +21,7 @@ public interface PayDao {
|
|||||||
|
|
||||||
PayDO get(Long id);
|
PayDO get(Long id);
|
||||||
|
|
||||||
List<PayDO> list(Map<String,Object> map);
|
List<PayDO> list(@ValidateSortOrder Map<String,Object> map);
|
||||||
|
|
||||||
int count(Map<String,Object> map);
|
int count(Map<String,Object> map);
|
||||||
|
|
||||||
|
@ -1,5 +1,7 @@
|
|||||||
package com.java2nb.novel.dao;
|
package com.java2nb.novel.dao;
|
||||||
|
|
||||||
|
import com.java2nb.common.annotation.ValidateSortOrder;
|
||||||
|
|
||||||
import com.java2nb.novel.domain.UserDO;
|
import com.java2nb.novel.domain.UserDO;
|
||||||
import org.apache.ibatis.annotations.Mapper;
|
import org.apache.ibatis.annotations.Mapper;
|
||||||
|
|
||||||
@ -17,7 +19,7 @@ public interface UserDao {
|
|||||||
|
|
||||||
UserDO get(Long id);
|
UserDO get(Long id);
|
||||||
|
|
||||||
List<UserDO> list(Map<String, Object> map);
|
List<UserDO> list(@ValidateSortOrder Map<String, Object> map);
|
||||||
|
|
||||||
int count(Map<String, Object> map);
|
int count(Map<String, Object> map);
|
||||||
|
|
||||||
|
@ -1,5 +1,7 @@
|
|||||||
package com.java2nb.novel.dao;
|
package com.java2nb.novel.dao;
|
||||||
|
|
||||||
|
import com.java2nb.common.annotation.ValidateSortOrder;
|
||||||
|
|
||||||
import com.java2nb.novel.domain.UserFeedbackDO;
|
import com.java2nb.novel.domain.UserFeedbackDO;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@ -18,7 +20,7 @@ public interface UserFeedbackDao {
|
|||||||
|
|
||||||
UserFeedbackDO get(Long id);
|
UserFeedbackDO get(Long id);
|
||||||
|
|
||||||
List<UserFeedbackDO> list(Map<String,Object> map);
|
List<UserFeedbackDO> list(@ValidateSortOrder Map<String,Object> map);
|
||||||
|
|
||||||
int count(Map<String,Object> map);
|
int count(Map<String,Object> map);
|
||||||
|
|
||||||
|
@ -1,5 +1,7 @@
|
|||||||
package com.java2nb.novel.dao;
|
package com.java2nb.novel.dao;
|
||||||
|
|
||||||
|
import com.java2nb.common.annotation.ValidateSortOrder;
|
||||||
|
|
||||||
import com.java2nb.novel.domain.WebsiteInfoDO;
|
import com.java2nb.novel.domain.WebsiteInfoDO;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@ -18,7 +20,7 @@ public interface WebsiteInfoDao {
|
|||||||
|
|
||||||
WebsiteInfoDO get(Long id);
|
WebsiteInfoDO get(Long id);
|
||||||
|
|
||||||
List<WebsiteInfoDO> list(Map<String,Object> map);
|
List<WebsiteInfoDO> list(@ValidateSortOrder Map<String,Object> map);
|
||||||
|
|
||||||
int count(Map<String,Object> map);
|
int count(Map<String,Object> map);
|
||||||
|
|
||||||
|
@ -1,5 +1,7 @@
|
|||||||
package com.java2nb.system.dao;
|
package com.java2nb.system.dao;
|
||||||
|
|
||||||
|
import com.java2nb.common.annotation.ValidateSortOrder;
|
||||||
|
|
||||||
import com.java2nb.system.domain.DataPermDO;
|
import com.java2nb.system.domain.DataPermDO;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@ -19,7 +21,7 @@ public interface DataPermDao {
|
|||||||
|
|
||||||
DataPermDO get(Long id);
|
DataPermDO get(Long id);
|
||||||
|
|
||||||
List<DataPermDO> list(Map<String,Object> map);
|
List<DataPermDO> list(@ValidateSortOrder Map<String,Object> map);
|
||||||
|
|
||||||
int count(Map<String,Object> map);
|
int count(Map<String,Object> map);
|
||||||
|
|
||||||
|
@ -1,5 +1,7 @@
|
|||||||
package com.java2nb.system.dao;
|
package com.java2nb.system.dao;
|
||||||
|
|
||||||
|
import com.java2nb.common.annotation.ValidateSortOrder;
|
||||||
|
|
||||||
import com.java2nb.system.domain.DeptDO;
|
import com.java2nb.system.domain.DeptDO;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@ -19,7 +21,7 @@ public interface DeptDao {
|
|||||||
|
|
||||||
DeptDO get(Long deptId);
|
DeptDO get(Long deptId);
|
||||||
|
|
||||||
List<DeptDO> list(Map<String,Object> map);
|
List<DeptDO> list(@ValidateSortOrder Map<String,Object> map);
|
||||||
|
|
||||||
int count(Map<String,Object> map);
|
int count(Map<String,Object> map);
|
||||||
|
|
||||||
|
@ -1,5 +1,7 @@
|
|||||||
package com.java2nb.system.dao;
|
package com.java2nb.system.dao;
|
||||||
|
|
||||||
|
import com.java2nb.common.annotation.ValidateSortOrder;
|
||||||
|
|
||||||
import com.java2nb.system.domain.MenuDO;
|
import com.java2nb.system.domain.MenuDO;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@ -18,7 +20,7 @@ public interface MenuDao {
|
|||||||
|
|
||||||
MenuDO get(Long menuId);
|
MenuDO get(Long menuId);
|
||||||
|
|
||||||
List<MenuDO> list(Map<String,Object> map);
|
List<MenuDO> list(@ValidateSortOrder Map<String,Object> map);
|
||||||
|
|
||||||
int count(Map<String,Object> map);
|
int count(Map<String,Object> map);
|
||||||
|
|
||||||
|
@ -1,5 +1,7 @@
|
|||||||
package com.java2nb.system.dao;
|
package com.java2nb.system.dao;
|
||||||
|
|
||||||
|
import com.java2nb.common.annotation.ValidateSortOrder;
|
||||||
|
|
||||||
import com.java2nb.system.domain.RoleDO;
|
import com.java2nb.system.domain.RoleDO;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@ -18,7 +20,7 @@ public interface RoleDao {
|
|||||||
|
|
||||||
RoleDO get(Long roleId);
|
RoleDO get(Long roleId);
|
||||||
|
|
||||||
List<RoleDO> list(Map<String,Object> map);
|
List<RoleDO> list(@ValidateSortOrder Map<String,Object> map);
|
||||||
|
|
||||||
int count(Map<String,Object> map);
|
int count(Map<String,Object> map);
|
||||||
|
|
||||||
|
@ -1,5 +1,7 @@
|
|||||||
package com.java2nb.system.dao;
|
package com.java2nb.system.dao;
|
||||||
|
|
||||||
|
import com.java2nb.common.annotation.ValidateSortOrder;
|
||||||
|
|
||||||
import com.java2nb.system.domain.RoleDataPermDO;
|
import com.java2nb.system.domain.RoleDataPermDO;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@ -18,7 +20,7 @@ public interface RoleDataPermDao {
|
|||||||
|
|
||||||
RoleDataPermDO get(Long id);
|
RoleDataPermDO get(Long id);
|
||||||
|
|
||||||
List<RoleDataPermDO> list(Map<String,Object> map);
|
List<RoleDataPermDO> list(@ValidateSortOrder Map<String,Object> map);
|
||||||
|
|
||||||
int count(Map<String,Object> map);
|
int count(Map<String,Object> map);
|
||||||
|
|
||||||
|
@ -1,5 +1,7 @@
|
|||||||
package com.java2nb.system.dao;
|
package com.java2nb.system.dao;
|
||||||
|
|
||||||
|
import com.java2nb.common.annotation.ValidateSortOrder;
|
||||||
|
|
||||||
import com.java2nb.system.domain.RoleMenuDO;
|
import com.java2nb.system.domain.RoleMenuDO;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@ -18,7 +20,7 @@ public interface RoleMenuDao {
|
|||||||
|
|
||||||
RoleMenuDO get(Long id);
|
RoleMenuDO get(Long id);
|
||||||
|
|
||||||
List<RoleMenuDO> list(Map<String,Object> map);
|
List<RoleMenuDO> list(@ValidateSortOrder Map<String,Object> map);
|
||||||
|
|
||||||
int count(Map<String,Object> map);
|
int count(Map<String,Object> map);
|
||||||
|
|
||||||
|
@ -1,5 +1,7 @@
|
|||||||
package com.java2nb.system.dao;
|
package com.java2nb.system.dao;
|
||||||
|
|
||||||
|
import com.java2nb.common.annotation.ValidateSortOrder;
|
||||||
|
|
||||||
import com.java2nb.system.domain.UserDO;
|
import com.java2nb.system.domain.UserDO;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@ -19,7 +21,7 @@ public interface SysUserDao {
|
|||||||
|
|
||||||
UserDO get(Long userId);
|
UserDO get(Long userId);
|
||||||
|
|
||||||
List<UserDO> list(Map<String,Object> map);
|
List<UserDO> list(@ValidateSortOrder Map<String,Object> map);
|
||||||
|
|
||||||
int count(Map<String,Object> map);
|
int count(Map<String,Object> map);
|
||||||
|
|
||||||
|
@ -1,5 +1,7 @@
|
|||||||
package com.java2nb.system.dao;
|
package com.java2nb.system.dao;
|
||||||
|
|
||||||
|
import com.java2nb.common.annotation.ValidateSortOrder;
|
||||||
|
|
||||||
import com.java2nb.system.domain.UserRoleDO;
|
import com.java2nb.system.domain.UserRoleDO;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@ -19,7 +21,7 @@ public interface UserRoleDao {
|
|||||||
|
|
||||||
UserRoleDO get(Long id);
|
UserRoleDO get(Long id);
|
||||||
|
|
||||||
List<UserRoleDO> list(Map<String, Object> map);
|
List<UserRoleDO> list(@ValidateSortOrder Map<String, Object> map);
|
||||||
|
|
||||||
int count(Map<String, Object> map);
|
int count(Map<String, Object> map);
|
||||||
|
|
||||||
|
@ -18,7 +18,7 @@ public interface ${className}Dao {
|
|||||||
|
|
||||||
${className}DO get(${pk.javaType} ${pk.attrname});
|
${className}DO get(${pk.javaType} ${pk.attrname});
|
||||||
|
|
||||||
List<${className}DO> list(Map<String,Object> map);
|
List<${className}DO> list(@ValidateSortOrder Map<String,Object> map);
|
||||||
|
|
||||||
int count(Map<String,Object> map);
|
int count(Map<String,Object> map);
|
||||||
|
|
||||||
|
@ -44,7 +44,7 @@ public interface ${className}Mapper {
|
|||||||
"limit #{offset}, #{limit}" +
|
"limit #{offset}, #{limit}" +
|
||||||
"</if>"+
|
"</if>"+
|
||||||
"</script>")
|
"</script>")
|
||||||
List<${className}DO> list(Map<String,Object> map);
|
List<${className}DO> list(@ValidateSortOrder Map<String,Object> map);
|
||||||
|
|
||||||
@Select("<script>" +
|
@Select("<script>" +
|
||||||
"select count(*) from ${tableName} " +
|
"select count(*) from ${tableName} " +
|
||||||
|
@ -22,6 +22,12 @@
|
|||||||
<artifactId>spring-boot-starter-web</artifactId>
|
<artifactId>spring-boot-starter-web</artifactId>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
|
<!-- Aop 相关 -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-starter-aop</artifactId>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.springframework.boot</groupId>
|
<groupId>org.springframework.boot</groupId>
|
||||||
<artifactId>spring-boot-starter-thymeleaf</artifactId>
|
<artifactId>spring-boot-starter-thymeleaf</artifactId>
|
||||||
|
@ -0,0 +1,13 @@
|
|||||||
|
package com.java2nb.novel.core.annotation;
|
||||||
|
|
||||||
|
import java.lang.annotation.*;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author xiongxiaoyang
|
||||||
|
* @date 2025/7/17
|
||||||
|
*/
|
||||||
|
@Target(ElementType.PARAMETER)
|
||||||
|
@Retention(RetentionPolicy.RUNTIME)
|
||||||
|
@Documented
|
||||||
|
public @interface ValidateSortOrder {
|
||||||
|
}
|
@ -0,0 +1,89 @@
|
|||||||
|
package com.java2nb.novel.core.aspect;
|
||||||
|
|
||||||
|
import com.java2nb.novel.core.annotation.ValidateSortOrder;
|
||||||
|
import com.java2nb.novel.core.utils.SortWhitelistUtil;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import lombok.SneakyThrows;
|
||||||
|
import org.aspectj.lang.ProceedingJoinPoint;
|
||||||
|
import org.aspectj.lang.annotation.Around;
|
||||||
|
import org.aspectj.lang.annotation.Aspect;
|
||||||
|
import org.aspectj.lang.reflect.MethodSignature;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
import java.lang.annotation.Annotation;
|
||||||
|
import java.lang.reflect.Field;
|
||||||
|
import java.lang.reflect.Method;
|
||||||
|
import java.util.*;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author xiongxiaoyang
|
||||||
|
* @date 2025/7/17
|
||||||
|
*/
|
||||||
|
@Aspect
|
||||||
|
@Component
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
public class SortOrderValidationAspect {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 拦截所有的mapper方法
|
||||||
|
*/
|
||||||
|
@SneakyThrows
|
||||||
|
@Around("execution(* com.java2nb.novel.mapper.*Mapper.*(..))")
|
||||||
|
public Object validateSortAndOrder(ProceedingJoinPoint joinPoint) {
|
||||||
|
Object[] args = joinPoint.getArgs();
|
||||||
|
MethodSignature signature = (MethodSignature) joinPoint.getSignature();
|
||||||
|
Method method = signature.getMethod();
|
||||||
|
|
||||||
|
Annotation[][] parameterAnnotations = method.getParameterAnnotations();
|
||||||
|
|
||||||
|
for (int i = 0; i < parameterAnnotations.length; i++) {
|
||||||
|
boolean hasAnnotation = Arrays.stream(parameterAnnotations[i])
|
||||||
|
.anyMatch(a -> a.annotationType().equals(ValidateSortOrder.class));
|
||||||
|
|
||||||
|
if (hasAnnotation && args[i] != null) {
|
||||||
|
processArgument(args[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return joinPoint.proceed(args);
|
||||||
|
}
|
||||||
|
|
||||||
|
@SneakyThrows
|
||||||
|
private void processArgument(Object obj) {
|
||||||
|
if (obj instanceof Map<?,?> map) {
|
||||||
|
processMap(map);
|
||||||
|
} else {
|
||||||
|
traverseAndSanitize(obj);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@SneakyThrows
|
||||||
|
private void traverseAndSanitize(Object obj) {
|
||||||
|
for (Field field : obj.getClass().getDeclaredFields()) {
|
||||||
|
switch (field.getName()) {
|
||||||
|
case "sort", "order" -> {
|
||||||
|
field.setAccessible(true);
|
||||||
|
Object value = field.get(obj);
|
||||||
|
if (value instanceof String strValue) {
|
||||||
|
String sanitized = "sort".equals(field.getName())
|
||||||
|
? SortWhitelistUtil.sanitizeColumn(strValue)
|
||||||
|
: SortWhitelistUtil.sanitizeOrder(strValue);
|
||||||
|
field.set(obj, sanitized);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
default -> {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void processMap(Map map) {
|
||||||
|
if (map.get("sort") instanceof String sortStr) {
|
||||||
|
map.put("sort", SortWhitelistUtil.sanitizeColumn(sortStr));
|
||||||
|
}
|
||||||
|
if (map.get("order") instanceof String orderStr) {
|
||||||
|
map.put("order", SortWhitelistUtil.sanitizeOrder(orderStr));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,28 @@
|
|||||||
|
package com.java2nb.novel.core.utils;
|
||||||
|
|
||||||
|
import lombok.experimental.UtilityClass;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author xiongxiaoyang
|
||||||
|
* @date 2025/7/17
|
||||||
|
*/
|
||||||
|
@UtilityClass
|
||||||
|
public class SortWhitelistUtil {
|
||||||
|
|
||||||
|
private final Set<String> allowedColumns = new HashSet<>(
|
||||||
|
Arrays.asList("id", "name", "create_time", "update_time", "last_index_update_time", "word_count",
|
||||||
|
"visit_count"));
|
||||||
|
private final Set<String> allowedOrders = new HashSet<>(Arrays.asList("asc", "desc"));
|
||||||
|
|
||||||
|
public String sanitizeColumn(String input) {
|
||||||
|
return allowedColumns.contains(input.toLowerCase()) ? input.toLowerCase() : "id";
|
||||||
|
}
|
||||||
|
|
||||||
|
public String sanitizeOrder(String input) {
|
||||||
|
return allowedOrders.contains(input.toLowerCase()) ? input.toLowerCase() : "asc";
|
||||||
|
}
|
||||||
|
}
|
@ -1,5 +1,6 @@
|
|||||||
package com.java2nb.novel.mapper;
|
package com.java2nb.novel.mapper;
|
||||||
|
|
||||||
|
import com.java2nb.novel.core.annotation.ValidateSortOrder;
|
||||||
import com.java2nb.novel.entity.Book;
|
import com.java2nb.novel.entity.Book;
|
||||||
import com.java2nb.novel.vo.BookSpVO;
|
import com.java2nb.novel.vo.BookSpVO;
|
||||||
import com.java2nb.novel.vo.BookVO;
|
import com.java2nb.novel.vo.BookVO;
|
||||||
@ -13,7 +14,7 @@ import java.util.List;
|
|||||||
public interface FrontBookMapper extends BookMapper {
|
public interface FrontBookMapper extends BookMapper {
|
||||||
|
|
||||||
|
|
||||||
List<BookVO> searchByPage(BookSpVO params);
|
List<BookVO> searchByPage(@ValidateSortOrder BookSpVO params);
|
||||||
|
|
||||||
void addVisitCount(@Param("bookId") Long bookId, @Param("visitCount") Integer visitCount);
|
void addVisitCount(@Param("bookId") Long bookId, @Param("visitCount") Integer visitCount);
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user