新增CSRF防护功能

This commit is contained in:
RuoYi
2025-04-15 16:24:42 +08:00
parent 407f9f46d8
commit ea9976575a
11 changed files with 175 additions and 9 deletions

View File

@@ -33,6 +33,7 @@ import com.ruoyi.framework.shiro.session.OnlineSessionFactory;
import com.ruoyi.framework.shiro.web.CustomShiroFilterFactoryBean;
import com.ruoyi.framework.shiro.web.filter.LogoutFilter;
import com.ruoyi.framework.shiro.web.filter.captcha.CaptchaValidateFilter;
import com.ruoyi.framework.shiro.web.filter.csrf.CsrfValidateFilter;
import com.ruoyi.framework.shiro.web.filter.kickout.KickoutSessionFilter;
import com.ruoyi.framework.shiro.web.filter.online.OnlineSessionFilter;
import com.ruoyi.framework.shiro.web.filter.sync.SyncOnlineSessionFilter;
@@ -132,6 +133,18 @@ public class ShiroConfig
@Value("${shiro.rememberMe.enabled: false}")
private boolean rememberMe;
/**
* 是否开启csrf
*/
@Value("${csrf.enabled: false}")
private boolean csrfEnabled;
/**
* csrf白名单链接
*/
@Value("${csrf.whites: ''}")
private String csrfWhites;
/**
* 缓存管理器 使用Ehcache实现
*/
@@ -263,6 +276,17 @@ public class ShiroConfig
return logoutFilter;
}
/**
* csrf过滤器
*/
public CsrfValidateFilter csrfValidateFilter()
{
CsrfValidateFilter csrfValidateFilter = new CsrfValidateFilter();
csrfValidateFilter.setEnabled(csrfEnabled);
csrfValidateFilter.setCsrfWhites(StringUtils.str2List(csrfWhites, ","));
return csrfValidateFilter;
}
/**
* Shiro过滤器配置
*/
@@ -309,13 +333,14 @@ public class ShiroConfig
filters.put("onlineSession", onlineSessionFilter());
filters.put("syncOnlineSession", syncOnlineSessionFilter());
filters.put("captchaValidate", captchaValidateFilter());
filters.put("csrfValidateFilter", csrfValidateFilter());
filters.put("kickout", kickoutSessionFilter());
// 注销成功,则跳转到指定页面
filters.put("logout", logoutFilter());
shiroFilterFactoryBean.setFilters(filters);
// 所有请求需要认证
filterChainDefinitionMap.put("/**", "user,kickout,onlineSession,syncOnlineSession");
filterChainDefinitionMap.put("/**", "user,kickout,onlineSession,syncOnlineSession,csrfValidateFilter");
shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap);
return shiroFilterFactoryBean;

View File

@@ -0,0 +1,76 @@
package com.ruoyi.framework.shiro.web.filter.csrf;
import java.util.List;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.shiro.web.filter.AccessControlFilter;
import com.ruoyi.common.constant.ShiroConstants;
import com.ruoyi.common.core.text.Convert;
import com.ruoyi.common.utils.ServletUtils;
import com.ruoyi.common.utils.ShiroUtils;
import com.ruoyi.common.utils.StringUtils;
/**
* csrf过滤器
*
* @author ruoyi
*/
public class CsrfValidateFilter extends AccessControlFilter
{
/**
* 白名单链接
*/
private List<String> csrfWhites;
@Override
protected boolean isAccessAllowed(ServletRequest request, ServletResponse response, Object mappedValue)
throws Exception
{
HttpServletRequest httpServletRequest = (HttpServletRequest) request;
if (!isAllowMethod(httpServletRequest))
{
return true;
}
if (StringUtils.matches(httpServletRequest.getServletPath(), csrfWhites))
{
return true;
}
return validateResponse(httpServletRequest, httpServletRequest.getHeader(ShiroConstants.CSRF_TOKEN));
}
public boolean validateResponse(HttpServletRequest request, String requestToken)
{
Object obj = ShiroUtils.getSession().getAttribute(ShiroConstants.CSRF_TOKEN);
String sessionToken = Convert.toStr(obj, "");
if (StringUtils.isEmpty(requestToken) || !requestToken.equalsIgnoreCase(sessionToken))
{
return false;
}
return true;
}
@Override
protected boolean onAccessDenied(ServletRequest request, ServletResponse response) throws Exception
{
ServletUtils.renderString((HttpServletResponse) response, "{\"code\":\"1\",\"msg\":\"当前请求的安全验证未通过,请刷新页面后重试。\"}");
return false;
}
private boolean isAllowMethod(HttpServletRequest request)
{
String method = request.getMethod();
return "POST".equalsIgnoreCase(method);
}
public List<String> getCsrfWhites()
{
return csrfWhites;
}
public void setCsrfWhites(List<String> csrfWhites)
{
this.csrfWhites = csrfWhites;
}
}