繁体   English   中英

REST应用程序的Spring Security表单登录

[英]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。

我的UserDetailsS​​erivce工作正常,但是,真正的问题是:

我是否缺少标题? 或服务器端项目中的任何其他设置?

请,任何帮助将不胜感激

[更新]这是使用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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM