我在使用 Spring Security 4.0 时遇到了一些小麻烦。
我正在使用 Spring Security 来保护 Web 应用程序和移动应用程序将通过 Ajax 调用消耗的一些 REST 资源。 我的 Web 应用程序开箱即用,但我的 REST 服务不太好。这个想法是使用 http 中的表单登录来登录我的应用程序,但成功登录后,我无法访问我的 protected 资源
要进入代码,这是我的web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
version="3.0">
<display-name>ShakePoint CMS</display-name>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>
/WEB-INF/datasource.xml
/WEB-INF/repositories.xml
/WEB-INF/facades.xml
/WEB-INF/spring-mvc-servlet.xml
/WEB-INF/spring-security.xml
</param-value>
</context-param>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<servlet>
<servlet-name>spring-mvc</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<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>/*</url-pattern>
</filter-mapping>
<servlet-mapping>
<servlet-name>spring-mvc</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
<welcome-file-list>
<welcome-file>index.jsp</welcome-file>
</welcome-file-list>
另外,我的spring-security.xml
<?xml version="1.0" encoding="UTF-8"?>
<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:security="http://www.springframework.org/schema/security"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
http://www.springframework.org/schema/security
http://www.springframework.org/schema/security/spring-security-4.0.xsd">
<beans:bean id="restAuthenticationEntryPoint" class="com.shakepoint.web.controller.rest.auth.RESTAuthenticationEntryPoint"/>
<beans:bean id="restAuthenticationDeniedHandler" class="com.shakepoint.web.controller.rest.auth.RESTAccessDeniedHandler"/>
<beans:bean id="restAuthenticationFailedHandler" class="com.shakepoint.web.controller.rest.auth.RESTAuthenticationFailedHandler"/>
<beans:bean id="restAuthenticationSuccessHandler" class="com.shakepoint.web.controller.rest.auth.RESTAuthenticationSuccessHandler"/>
<beans:bean id="successAuthenticationHandler" class="com.shakepoint.web.auth.SuccessAuthenticationHandler"/>
<security:http create-session="stateless"
pattern="/rest/**"
use-expressions="true"
entry-point-ref="restAuthenticationEntryPoint"
authentication-manager-ref="authenticationManager" >
<!--<security:intercept-url pattern="/account/signin" access="permitAll()"/>-->
<security:intercept-url pattern="/rest/account/signup" access="permitAll()"/>
<security:intercept-url pattern="/rest/shop/**" access="hasRole('ROLE_MEMBER')"/>
<!--<security:http-basic />-->
<security:form-login login-processing-url="/rest/account/signin"
authentication-failure-handler-ref="restAuthenticationFailedHandler"
authentication-success-handler-ref="restAuthenticationSuccessHandler"
password-parameter="shakepoint_password"
username-parameter="shakepoint_username"
/>
<!--<security:access-denied-handler ref="restAuthenticationDeniedHandler"/>-->
<security:csrf disabled="true"/>
</security:http>
<security:http use-expressions="true" >
<security:intercept-url pattern="/tech/**" access="hasAnyRole('ROLE_TECHNICIAN')"/>
<security:intercept-url pattern="/admin/**" access="hasAnyRole('ROLE_ADMIN','ROLE_SUPER_ADMIN')"/>
<security:form-login
login-page="/signin"
login-processing-url="/login_to_checkpoint"
authentication-failure-url="/signin?error"
authentication-success-handler-ref="successAuthenticationHandler"
password-parameter="j_password"
username-parameter="j_email"/>
<security:logout logout-success-url="/" logout-url="/j_spring_security_logout"/>
<security:csrf/>
</security:http>
<security:global-method-security secured-annotations="enabled"/>
在我的 AuthenticationSuccessHandler 和 AuthenticationFailedHandler 上,我仅发送 application/json 内容类型和包含基本授权值(如果成功)的对象,如果失败则发送错误消息。
我已使用以下 ajax 请求成功登录我的应用程序
$.support.corps = true;
$.ajax({
url: 'http://192.168.0.7:8080/rest/account/signin',
type: "POST",
data: JSON.stringify(signinData),
contentType: "application/json; charset=utf-8",
dataType: "json",
success: function (response) {
if(response.success == true){
...
}
},
error: function(error){
alert(error);
}
});
但是当我想访问添加基本授权 header 的 protected 资源时,它会从服务器返回未经授权的状态。 我还注意到 spring 正在响应上创建一个 JSESSION cookie。
我的 UserDetailsSerivce 工作正常,但是,真正的问题是:
Am I missing any header? or any extra setup from my server side project?
请提供任何帮助,我们将不胜感激
[更新] 这是使用 Spring Security 成功登录的 Tomcat-7 日志
2015-10-07 12:16:18 DEBUG AntPathRequestMatcher:151 - Checking match of request : '/rest/account/signin'; against '/rest/**'
2015-10-07 12:16:18 DEBUG FilterChainProxy:324 - /rest/account/signin? shakepoint_password=tech2&shakepoint_username=tech2@gmail.com at position 1 of 9 in additional filter chain; firing Filter: 'SecurityContextPersistenceFilter'
2015-10-07 12:16:18 DEBUG FilterChainProxy:324 - /rest/account/signin?shakepoint_password=tech2&shakepoint_username=tech2@gmail.com at position 2 of 9 in additional filter chain; firing Filter: 'WebAsyncManagerIntegrationFilter'
2015-10-07 12:16:18 DEBUG FilterChainProxy:324 - /rest/account/signin?shakepoint_password=tech2&shakepoint_username=tech2@gmail.com at position 3 of 9 in additional filter chain; firing Filter: 'HeaderWriterFilter'
2015-10-07 12:16:18 DEBUG HstsHeaderWriter:128 - Not injecting HSTS header since it did not match the requestMatcher org.springframework.security.web.header.writers.HstsHeaderWriter$SecureRequestMatcher@7cb9682a
2015-10-07 12:16:18 DEBUG FilterChainProxy:324 - /rest/account/signin?shakepoint_password=tech2&shakepoint_username=tech2@gmail.com at position 4 of 9 in additional filter chain; firing Filter: 'UsernamePasswordAuthenticationFilter'
2015-10-07 12:16:18 DEBUG AntPathRequestMatcher:151 - Checking match of request : '/rest/account/signin'; against '/rest/account/signin'
2015-10-07 12:16:18 DEBUG UsernamePasswordAuthenticationFilter:211 - Request is to process authentication
2015-10-07 12:16:18 DEBUG ProviderManager:162 - Authentication attempt using org.springframework.security.authentication.dao.DaoAuthenticationProvider
2015-10-07 12:16:18 DEBUG JdbcTemplate:634 - Executing prepared SQL query
2015-10-07 12:16:18 DEBUG JdbcTemplate:569 - Executing prepared SQL statement [select email, password, role from user where email = ?]
2015-10-07 12:16:18 DEBUG DataSourceUtils:110 - Fetching JDBC Connection from DataSource
2015-10-07 12:16:18 DEBUG DriverManagerDataSource:162 - Creating new JDBC DriverManager Connection to [jdbc:mysql://localhost:3306/shakepoint]
2015-10-07 12:16:19 DEBUG DataSourceUtils:332 - Returning JDBC Connection to DataSource
2015-10-07 12:16:19 DEBUG UsernamePasswordAuthenticationFilter:317 - Authentication success. Updating SecurityContextHolder to contain: org.springframework.security.authentication.UsernamePasswordAuthenticationToken@511e4d66: Principal: org.springframework.security.core.userdetails.User@fea4fb4d: Username: tech2@gmail.com; Password: [PROTECTED]; Enabled: true; AccountNonExpired: true; credentialsNonExpired: true; AccountNonLocked: true; Granted Authorities: ROLE_TECHNICIAN; Credentials: [PROTECTED]; Authenticated: true; Details: org.springframework.security.web.authentication.WebAuthenticationDetails@957e: RemoteIpAddress: 127.0.0.1; SessionId: null; Granted Authorities: ROLE_TECHNICIAN
2015-10-07 12:16:19 DEBUG SecurityContextPersistenceFilter:105 - SecurityContextHolder now cleared, as request processing completed
但是,在我尝试访问我的 protected 资源后,我得到了这个:
2015-10-07 12:22:09 DEBUG AntPathRequestMatcher:151 - Checking match of request : '/rest/shop/secured_ping'; against '/rest/**'
2015-10-07 12:22:09 DEBUG FilterChainProxy:324 - /rest/shop/secured_ping at position 1 of 9 in additional filter chain; firing Filter: 'SecurityContextPersistenceFilter'
2015-10-07 12:22:09 DEBUG FilterChainProxy:324 - /rest/shop/secured_ping at position 2 of 9 in additional filter chain; firing Filter: 'WebAsyncManagerIntegrationFilter'
2015-10-07 12:22:09 DEBUG FilterChainProxy:324 - /rest/shop/secured_ping at position 3 of 9 in additional filter chain; firing Filter: 'HeaderWriterFilter'
2015-10-07 12:22:09 DEBUG HstsHeaderWriter:128 - Not injecting HSTS header since it did not match the requestMatcher org.springframework.security.web.header.writers.HstsHeaderWriter$SecureRequestMatcher@7cb9682a
2015-10-07 12:22:09 DEBUG FilterChainProxy:324 - /rest/shop/secured_ping at position 4 of 9 in additional filter chain; firing Filter: 'UsernamePasswordAuthenticationFilter'
2015-10-07 12:22:09 DEBUG AntPathRequestMatcher:131 - Request 'GET /rest/shop/secured_ping' doesn't match 'POST /rest/account/signin
2015-10-07 12:22:09 DEBUG FilterChainProxy:324 - /rest/shop/secured_ping at position 5 of 9 in additional filter chain; firing Filter: 'DefaultLoginPageGeneratingFilter'
2015-10-07 12:22:09 DEBUG FilterChainProxy:324 - /rest/shop/secured_ping at position 6 of 9 in additional filter chain; firing Filter: 'SecurityContextHolderAwareRequestFilter'
2015-10-07 12:22:09 DEBUG FilterChainProxy:324 - /rest/shop/secured_ping at position 7 of 9 in additional filter chain; firing Filter: 'AnonymousAuthenticationFilter'
2015-10-07 12:22:09 DEBUG AnonymousAuthenticationFilter:100 - Populated SecurityContextHolder with anonymous token: 'org.springframework.security.authentication.AnonymousAuthenticationToken@9055e4a6: Principal: anonymousUser; Credentials: [PROTECTED]; Authenticated: true; Details: org.springframework.security.web.authentication.WebAuthenticationDetails@957e: RemoteIpAddress: 127.0.0.1; SessionId: null; Granted Authorities: ROLE_ANONYMOUS'
2015-10-07 12:22:09 DEBUG FilterChainProxy:324 - /rest/shop/secured_ping at position 8 of 9 in additional filter chain; firing Filter: 'ExceptionTranslationFilter'
2015-10-07 12:22:09 DEBUG FilterChainProxy:324 - /rest/shop/secured_ping at position 9 of 9 in additional filter chain; firing Filter: 'FilterSecurityInterceptor'
2015-10-07 12:22:09 DEBUG AntPathRequestMatcher:151 - Checking match of request : '/rest/shop/secured_ping'; against '/rest/account/signup'
2015-10-07 12:22:09 DEBUG AntPathRequestMatcher:151 - Checking match of request : '/rest/shop/secured_ping'; against '/rest/shop/**'
2015-10-07 12:22:09 DEBUG FilterSecurityInterceptor:218 - Secure object: FilterInvocation: URL: /rest/shop/secured_ping; Attributes: [hasRole('ROLE_MEMBER')]
2015-10-07 12:22:09 DEBUG FilterSecurityInterceptor:347 - Previously Authenticated: org.springframework.security.authentication.AnonymousAuthenticationToken@9055e4a6: Principal: anonymousUser; Credentials: [PROTECTED]; Authenticated: true; Details: org.springframework.security.web.authentication.WebAuthenticationDetails@957e: RemoteIpAddress: 127.0.0.1; SessionId: null; Granted Authorities: ROLE_ANONYMOUS
2015-10-07 12:22:09 DEBUG AffirmativeBased:65 - Voter: org.springframework.security.web.access.expression.WebExpressionVoter@629d991f, returned: -1
2015-10-07 12:22:09 DEBUG ExceptionTranslationFilter:173 - Access is denied (user is anonymous); redirecting to authentication entry point
org.springframework.security.access.AccessDeniedException: Access is denied
at org.springframework.security.access.vote.AffirmativeBased.decide(AffirmativeBased.java:83)
at org.springframework.security.access.intercept.AbstractSecurityInterceptor.beforeInvocation(AbstractSecurityInterceptor.java:232)
at org.springframework.security.web.access.intercept.FilterSecurityInterceptor.invoke(FilterSecurityInterceptor.java:123)
at org.springframework.security.web.access.intercept.FilterSecurityInterceptor.doFilter(FilterSecurityInterceptor.java:90)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330)
at org.springframework.security.web.access.ExceptionTranslationFilter.doFilter(ExceptionTranslationFilter.java:114)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330)
at org.springframework.security.web.authentication.AnonymousAuthenticationFilter.doFilter(AnonymousAuthenticationFilter.java:111)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330)
at org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter.doFilter(SecurityContextHolderAwareRequestFilter.java:169)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330)
at org.springframework.security.web.authentication.ui.DefaultLoginPageGeneratingFilter.doFilter(DefaultLoginPageGeneratingFilter.java:162)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330)
at org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter.doFilter(AbstractAuthenticationProcessingFilter.java:205)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330)
at org.springframework.security.web.header.HeaderWriterFilter.doFilterInternal(HeaderWriterFilter.java:64)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:108)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330)
at org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter.doFilterInternal(WebAsyncManagerIntegrationFilter.java:53)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:108)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330)
at org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter(SecurityContextPersistenceFilter.java:91)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330)
at org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:213)
at org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:176)
at org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:344)
at org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:261)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:241)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:208)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:220)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:122)
at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:505)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:170)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:103)
at org.apache.catalina.valves.AccessLogValve.invoke(AccessLogValve.java:956)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:116)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:423)
at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1079)
at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:625)
at org.apache.tomcat.util.net.AprEndpoint$SocketProcessor.doRun(AprEndpoint.java:2522)
at org.apache.tomcat.util.net.AprEndpoint$SocketProcessor.run(AprEndpoint.java:2511)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)
at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
at java.lang.Thread.run(Thread.java:745)
2015-10-07 12:22:09 DEBUG ExceptionTranslationFilter:202 - Calling Authentication entry point.
2015-10-07 12:22:09 DEBUG SecurityContextPersistenceFilter:105 - SecurityContextHolder now cleared, as request processing completed
最佳答案
好吧,这次我找到了自己的答案,在深入了解 Spring 文档后,我发现 Spring Security 需要一个 BasicAuthorizationProcessingFilter在应用程序上设置 SecurityContext
我唯一做的就是:
添加身份验证过滤器
<beans:bean id="basicAuthenticationFilter" class="org.springframework.security.web.authentication.www.BasicAuthenticationFilter">
<beans:constructor-arg index="0" ref="authenticationManager"/>
<beans:constructor-arg index="1" ref="restAuthenticationEntryPoint"/>
</beans:bean>
更改了我的 http 元素,添加了自定义过滤器子元素
<security:http create-session="stateless"
pattern="/rest/**"
use-expressions="true"
entry-point-ref="restAuthenticationEntryPoint"
authentication-manager-ref="authenticationManager" >
<!--<security:intercept-url pattern="/account/signin" access="permitAll()"/>-->
<security:intercept-url pattern="/rest/account/signup" access="permitAll()"/>
<security:intercept-url pattern="/rest/shop/**" access="hasAnyRole('ROLE_MEMBER', 'ROLE_SUPER_ADMIN', 'ROLE_ADMIN', 'ROLE_TECHNICIAN')"/>
<security:custom-filter ref="basicAuthenticationFilter" position="BASIC_AUTH_FILTER"/>
<security:form-login login-processing-url="/rest/account/signin"
authentication-failure-handler-ref="restAuthenticationFailedHandler"
authentication-success-handler-ref="restAuthenticationSuccessHandler"
password-parameter="shakepoint_password"
username-parameter="shakepoint_username"
/>
<!--<security:access-denied-handler ref="restAuthenticationDeniedHandler"/>-->
<security:csrf disabled="true"/>
</security:http>
进行这些更改后,我的应用程序安全性开箱即用!
关于java - REST 应用程序的 Spring Security 表单登录,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32984810/