Spring请求参数UTF-8支持:如何在CsrfFilter前配置编码过滤器
遇到过类似的问题,Spring Security的CsrfFilter确实会在很多自定义过滤器之前读取请求参数,导致后续的编码设置失效。这里有两个可靠的解决方案,帮你彻底解决UTF-8编码问题:
方案1:在web.xml中配置编码过滤器(推荐)
这是最直接的解决方式,因为web.xml中定义的过滤器会优先于Spring Security的整个过滤器链执行,完全避开CsrfFilter先读取参数的问题。
你不需要自定义过滤器,直接用Spring提供的CharacterEncodingFilter即可,配置如下:
<filter> <filter-name>encodingFilter</filter-name> <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class> <init-param> <param-name>encoding</param-name> <param-value>UTF-8</param-value> </init-param> <init-param> <param-name>forceEncoding</param-name> <param-value>true</param-value> </init-param> </filter> <filter-mapping> <filter-name>encodingFilter</filter-name> <url-pattern>/*</url-pattern> <dispatcher>REQUEST</dispatcher> <dispatcher>FORWARD</dispatcher> </filter-mapping>
forceEncoding=true会强制为request和response都设置UTF-8编码,确保后续所有读取参数的操作(包括CsrfFilter)都会使用正确的编码。
方案2:在Spring Security链中正确插入自定义编码过滤器
如果你一定要在Spring Security的过滤器链中处理编码,关键是要准确指定过滤器在CsrfFilter之前执行,同时确保Spring Security的配置完整,避免AuthenticationEntryPoint的异常。
第一步:修正Spring Security配置
不要单独创建新的<http>块,而是把自定义过滤器放在你原来的http配置里,用before="CSRF_FILTER"明确指定位置:
<http auto-config="true" use-expressions="true"> <intercept-url pattern="/**" access="permitAll" /> <!-- 用permitAll更适合匿名访问场景 --> <access-denied-handler ref="myAccessDeniedHandler"/> <!-- 关键:在CsrfFilter之前插入编码过滤器 --> <custom-filter before="CSRF_FILTER" ref="utf8Filter" /> </http> <beans:bean id="utf8Filter" class="my.SetRequestEncodingFilter"> <beans:property name="encoding" value="UTF-8"/> <beans:property name="forceEncoding" value="true"/> </beans:bean>
这里把hasRole('ROLE_ANONYMOUS')改成permitAll更合理,因为它直接表示允许所有用户(包括匿名)访问,避免了角色检查的潜在问题。
第二步:完善自定义过滤器
你的SetRequestEncodingFilter最好继承Spring的CharacterEncodingFilter或者OncePerRequestFilter,确保编码设置只执行一次:
public class SetRequestEncodingFilter extends CharacterEncodingFilter { public SetRequestEncodingFilter() { super.setEncoding("UTF-8"); super.setForceEncoding(true); } }
或者自己实现逻辑:
public class SetRequestEncodingFilter extends OncePerRequestFilter { @Override protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException { // 仅在首次调用前设置编码 if (request.getCharacterEncoding() == null) { request.setCharacterEncoding("UTF-8"); } response.setCharacterEncoding("UTF-8"); filterChain.doFilter(request, response); } }
为什么之前的配置报错?
你之前单独创建<http>块添加自定义过滤器,覆盖了原来的完整配置,导致Spring Security无法自动初始化AuthenticationEntryPoint。必须把自定义过滤器放在包含auto-config、intercept-url等完整配置的同一个<http>块里,这样Spring才能正确构建安全链。
内容的提问来源于stack exchange,提问作者user2177118

