[英]Spring Security form-login for REST applications
我在使用Spring Security 4.0时遇到了小麻烦。
我正在使用Spring Security保护Web应用程序和一些REST资源的安全,这些资源将通过使用Ajax调用被移动应用程序使用。 我的Web应用程序开箱即用,但是我的REST服务不太好。 这个想法是使用http中的表单登录名登录我的应用程序,但是成功登录后,我将无法访问受保护的资源
要进入代码,这是我的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);
}
});
但是,当我想访问添加了基本授权标头的受保护资源时,它会从服务器返回未授权状态。 我还注意到Spring正在响应中创建JSESSION cookie。
我的UserDetailsSerivce工作正常,但是,真正的问题是:
我是否缺少标题? 或服务器端项目中的任何其他设置?
请,任何帮助将不胜感激
[更新]这是使用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
但是,在II尝试访问受保护的资源后,我得到了以下信息:
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>
完成这些更改后,我的应用程序安全性立即可用!
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.