@@ -48,37 +48,63 @@ public class BaseInterceptor implements HandlerInterceptor {
48
48
public boolean preHandle (HttpServletRequest request , HttpServletResponse response , Object o ) throws Exception {
49
49
String uri = request .getRequestURI ();
50
50
51
+ // 规范化路径,防止路径遍历
52
+ uri = uri .replaceAll ("/+" , "/" );
53
+
51
54
LOGGE .info ("UserAgent: {}" , request .getHeader (USER_AGENT ));
52
55
LOGGE .info ("用户访问地址: {}, 来路地址: {}" , uri , IPKit .getIpAddrByRequest (request ));
53
56
54
-
55
- //请求拦截处理
57
+ // 请求拦截处理
56
58
UserDomain user = TaleUtils .getLoginUser (request );
57
59
if (null == user ) {
58
60
Integer uid = TaleUtils .getCookieUid (request );
59
61
if (null != uid ) {
60
- //这里还是有安全隐患,cookie是可以伪造的
62
+ // 这里还是有安全隐患, cookie 是可以伪造的
61
63
user = userService .getUserInfoById (uid );
62
64
request .getSession ().setAttribute (WebConst .LOGIN_SESSION_KEY , user );
63
65
}
64
66
}
65
- if (uri .startsWith ("/admin" ) && !uri .startsWith ("/admin/login" ) && null == user
66
- && !uri .startsWith ("/admin/css" ) && !uri .startsWith ("/admin/images" )
67
- && !uri .startsWith ("/admin/js" ) && !uri .startsWith ("/admin/plugins" )
68
- && !uri .startsWith ("/admin/editormd" )) {
67
+
68
+ // 如果是以 /admin 开头并且不是特定的静态资源文件,则要求认证
69
+ if (uri .startsWith ("/admin" )
70
+ && !uri .startsWith ("/admin/login" )
71
+ && null == user
72
+ && !isStaticResource (uri )) {
73
+
69
74
response .sendRedirect (request .getContextPath () + "/admin/login" );
70
75
return false ;
71
76
}
72
- //设置get请求的token
73
- if (request .getMethod ().equals ("GET" )) {
74
- String csrf_token = UUID .UU64 ();
77
+
78
+ // 设置 CSRF token 并要求对敏感操作进行校验
79
+ if ("GET" .equalsIgnoreCase (request .getMethod ())) {
80
+ String csrfToken = UUID .UU64 ();
75
81
// 默认存储30分钟
76
- cache .hset (Types .CSRF_TOKEN .getType (), csrf_token , uri , 30 * 60 );
77
- request .setAttribute ("_csrf_token" , csrf_token );
82
+ cache .hset (Types .CSRF_TOKEN .getType (), csrfToken , uri , 30 * 60 );
83
+ request .setAttribute ("_csrf_token" , csrfToken );
84
+ } else if ("POST" .equalsIgnoreCase (request .getMethod ())) {
85
+ // 检查 POST 请求的 CSRF token
86
+ String csrfToken = request .getParameter ("_csrf_token" );
87
+ String expectedUri = cache .hget (Types .CSRF_TOKEN .getType (), csrfToken );
88
+ if (expectedUri == null || !expectedUri .equals (uri )) {
89
+ response .sendError (HttpServletResponse .SC_FORBIDDEN , "CSRF token invalid or expired." );
90
+ return false ;
91
+ }
92
+ cache .hdel (Types .CSRF_TOKEN .getType (), csrfToken ); // Token 仅使用一次
78
93
}
94
+
79
95
return true ;
80
96
}
81
97
98
+ /**
99
+ * 检查是否为静态资源文件,避免对静态资源文件进行认证
100
+ */
101
+ private boolean isStaticResource (String uri ) {
102
+ return uri .startsWith ("/admin/css" ) || uri .startsWith ("/admin/images" )
103
+ || uri .startsWith ("/admin/js" ) || uri .startsWith ("/admin/plugins" )
104
+ || uri .startsWith ("/admin/editormd" );
105
+ }
106
+
107
+
82
108
@ Override
83
109
public void postHandle (HttpServletRequest httpServletRequest , HttpServletResponse httpServletResponse , Object o , ModelAndView modelAndView ) throws Exception {
84
110
OptionsDomain ov = optionService .getOptionByName ("site_record" );
0 commit comments