我正在使用AngularJS前端和Spring后端构建应用程序。我在前端和后端都有CSRF的所有设置,并且在我做出改变之前它工作正常。
当我登录我的应用程序时一切顺利,我登录/rest/user
处的端点。当我注销403错误时,它就会被抛出。我在调试模式下将Spring Security打印到日志文件,我发现它在尝试验证CSRF令牌时失败了。我会继续解释我做了什么导致这种情况发生。
我作为Spring调度程序servlet的静态内容提供AngularJS应用程序,我不希望Spring Security保护该静态内容。我认为它在服务器上的负载更大。因此,我已将Spring Security Filter Chain入口点设置为我的其他服务映射到的位置,而不是应用程序的根目录。
这是我的web.xml的部分显示:
<servlet>
<servlet-name>gravytrack</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>gravytrack</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>gravytrack</servlet-name>
<url-pattern>*.*</url-pattern>
</servlet-mapping>
<!-- Security entry point -->
<filter>
<filter-name>springSecurityFilterChain</filter-name>
<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
</filter>
<filter-mapping>
<filter-name>springSecurityFilterChain</filter-name>
<url-pattern>/rest/*</url-pattern>
</filter-mapping>
由于此更改,我必须将我的退出网址映射到/rest/logout
,而不是默认情况下Spring安全性将其映射到的普通/logout
。这是我的安全配置显示:
<beans:beans xmlns="http://www.springframework.org/schema/security"
xmlns:beans="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:util="http://www.springframework.org/schema/util"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/util
http://www.springframework.org/schema/util/spring-util.xsd
http://www.springframework.org/schema/security
http://www.springframework.org/schema/security/spring-security.xsd">
<global-method-security pre-post-annotations="enabled"
secured-annotations="enabled"/>
<http auto-config="true" use-expressions="true">
<intercept-url pattern="/rest/**" requires-channel="https"/>
<access-denied-handler error-page="/"/>
<http-basic entry-point-ref="gtBasicAuthenticationEntryPoint"/>
<!-- CRSF FILTER CONFIG -->
<custom-filter ref="csrfHeaderFilter" after="CSRF_FILTER"/>
<csrf token-repository-ref="csrfTokenRepository" />
<!-- LOGOUT CONFIG -->
<logout logout-url="/rest/logout" invalidate-session="true" delete-cookies="JSESSIONID"/>
<!--<session-management invalid-session-url="/">-->
<!--<concurrency-control max-sessions="10" error-if-maximum-exceeded="true" />-->
<!--</session-management>-->
</http>
<!--<beans:bean id="gtBasicAuthenticationEntryPoint" class="com.gbsolutions.gravytrack.security.GtBasicAuthenticationEntryPoint">-->
<!--<beans:property name="realmName" value="gravytrack" />-->
<!--</beans:bean>-->
<beans:bean id="csrfTokenRepository" class="org.springframework.security.web.csrf.HttpSessionCsrfTokenRepository">
<beans:property name="headerName" value="X-XSRF-TOKEN" />
</beans:bean>
<!--<beans:bean class="org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder" id="passwordEncoder" />-->
<authentication-manager alias="authenticationManager">
<authentication-provider>
<!--<password-encoder ref="passwordEncoder"/>-->
<!--<jdbc-user-service data-source-ref="dataSource"-->
<!--users-by-username-query="SELECT email as username, password, enabled FROM user_account-->
<!--WHERE email = ?" />-->
<user-service>
<user name="admin@admin.com" password="admin" authorities="ROLE_USER"/>
</user-service>
</authentication-provider>
</authentication-manager>
</beans:beans>
我有一个自定义过滤器,你可以在安全配置的这一行看到:
<custom-filter ref="csrfHeaderFilter" after="CSRF_FILTER"/>
这是我修改返回的cookie以获取为Angular定制的CSRF令牌的地方。这是csrfHeaderFilter
类:
@Service("csrfHeaderFilter")
public class CsrfHeaderFilter extends OncePerRequestFilter {
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
throws ServletException, IOException {
CsrfToken csrf = (CsrfToken) request.getAttribute(CsrfToken.class.getName());
if (csrf != null) {
Cookie cookie = WebUtils.getCookie(request, "XSRF-TOKEN");
String token = csrf.getToken();
if (cookie==null || token!=null && !token.equals(cookie.getValue())) {
cookie = new Cookie("XSRF-TOKEN", token);
cookie.setPath("/");
response.addCookie(cookie);
}
}
filterChain.doFilter(request, response);
}
}
我认为问题与这一行有关:
cookie.setPath("/");
之前我遇到过类似的问题,我通过改变应用路径的路径修复了它。但是现在我的应用程序的路径是tomcat的根目录,因为我已经设置了tomcat。因此,https://localhost:8443/gravytrack
只是https://localhost:8443/
而不是/rest
。
我也尝试将路径更改为{{1}}(我的Spring Security的入口点),但这并没有帮助。可能导致403错误的原因是什么?