使用Spring 3在REST中登录/注销

FKh*_*han 21 rest spring spring-security spring-webflow spring-3

我们正在使用Spring 3开发RESTful Web服务,我们需要具有登录/注销功能,类似于/webservices/login/<username>/<password>//webservices/logout.会话应存储在上下文中,直到会话超时或注销以允许使用其他Web服务.任何访问没有会话信息的Web服务的请求都应该被拒绝.寻找这种情况的最先进的解决方案.

我实际上复活了Spring Security 3以编程方式登录的问题,这仍然没有得到妥善解答.请指定web.xml中所需的更改.

roo*_*kit 50

我建议完全手动定义Spring Security过滤器.这并不困难,您可以完全控制您的登录/注销行为.

首先,您需要标准的web.xml blurb来将过滤器链处理委托给Spring(如果您不在Servlet API第3版中,则删除异步支持):

<filter>
    <filter-name>springSecurityFilterChain</filter-name>
    <async-supported>true</async-supported>
    <filter-class>
        org.springframework.web.filter.DelegatingFilterProxy
    </filter-class>
</filter>



<filter-mapping>
    <filter-name>springSecurityFilterChain</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>
Run Code Online (Sandbox Code Playgroud)

现在,在安全上下文中,您将为每个路径单独定义过滤器.过滤器可以对用户进行身份验证,注销用户,检查安全凭据等.

<bean id="springSecurityFilterChain" class="org.springframework.security.web.FilterChainProxy">
    <sec:filter-chain-map path-type="ant">
        <sec:filter-chain pattern="/login" filters="sif,wsFilter"/>
        <sec:filter-chain pattern="/logout" filters="sif,logoutFilter" />
        <sec:filter-chain pattern="/rest/**" filters="sif,fsi"/>
    </sec:filter-chain-map>
</bean>
Run Code Online (Sandbox Code Playgroud)

上面的XML告诉Spring通过过滤器链将请求传递给特定的上下文相关URL.任何过滤器链中的第一件事就是建立安全上下文 - 'sif'bean负责这一点.

<bean id="sif" class="org.springframework.security.web.context.SecurityContextPersistenceFilter"/>
Run Code Online (Sandbox Code Playgroud)

链中的下一个过滤器现在可以将数据添加到安全上下文(读取:登录/注销用户),或者是否允许基于所述安全上下文进行访问.

对于您的登录URL,您需要一个过滤器,该过滤器从请求中读取身份验证数据,对其进行验证,然后将其存储在安全上下文中(存储在会话中):

<bean id="wsFilter" class="my.own.security.AuthenticationFilter">
  <property name="authenticationManager" ref="authenticationManager"/>
  <property name="authenticationSuccessHandler" ref="myAuthSuccessHandler"/>
  <property name="passwordParameter" value="pass"></property>
  <property name="usernameParameter" value="user"></property>
  <property name="postOnly" value="false"></property>
Run Code Online (Sandbox Code Playgroud)

您可以使用Spring泛型,UsernamePasswordAuthenticationFilter但我使用自己的实现的原因是继续过滤器链处理(默认实现假定用户将在成功的auth上重定向并终止过滤器链),并且每次传递用户名和密码时都能够处理身份验证它:

public class MyAuthenticationFilter extends UsernamePasswordAuthenticationFilter {

@Override
protected boolean requiresAuthentication(HttpServletRequest request, HttpServletResponse response) {
    return ( StringUtils.hasText(obtainUsername(request)) && StringUtils.hasText(obtainPassword(request)) );
}

@Override
protected void successfulAuthentication(HttpServletRequest request, HttpServletResponse response, FilterChain chain,
        Authentication authResult) throws IOException, ServletException{
    super.successfulAuthentication(request, response, chain, authResult);
    chain.doFilter(request, response);
}
Run Code Online (Sandbox Code Playgroud)

您可以为/ login路径添加任意数量的自己的过滤器实现,例如使用HTTP基本身份验证标头,摘要标头进行身份验证,甚至从请求正文中提取用户名/密码.Spring为此提供了一堆过滤器.

我有自己的auth成功处理程序,它会覆盖默认的重定向策略:

public class AuthenticationSuccessHandler extends SimpleUrlAuthenticationSuccessHandler {

   @PostConstruct
   public void afterPropertiesSet() {
       setRedirectStrategy(new NoRedirectStrategy());
   }

    protected class NoRedirectStrategy implements RedirectStrategy {

        @Override
        public void sendRedirect(HttpServletRequest request,
                HttpServletResponse response, String url) throws IOException {
            // no redirect

        }

    }

}
Run Code Online (Sandbox Code Playgroud)

如果您在成功登录后可以重定向用户,那么您不必拥有自定义身份验证成功处理程序(也可能是自定义身份验证过滤器)(可以自定义重定向URL,检查文档)

定义将负责检索用户详细信息的身份验证管理器:

<sec:authentication-manager alias="authenticationManager">
    <sec:authentication-provider ref="myAuthAuthProvider"/>
</sec:authentication-manager>

 <bean id="myAuthAuthProvider" class="org.springframework.security.web.authentication.preauth.PreAuthenticatedAuthenticationProvider">
    <property name="preAuthenticatedUserDetailsService">
        <bean id="userDetailsServiceWrapper" class="org.springframework.security.core.userdetails.UserDetailsByNameServiceWrapper">
            <property name="userDetailsService" ref="myUserDetailsImpl"/>
        </bean>
    </property>
</bean>
Run Code Online (Sandbox Code Playgroud)

您必须在此处提供自己的用户详细信息bean实现.

注销过滤器:负责清除安全上下文

<bean id="logoutFilter" class="org.springframework.security.web.authentication.logout.LogoutFilter">
    <constructor-arg>
        <list>
            <bean class="org.springframework.security.web.authentication.logout.SecurityContextLogoutHandler"/>
        </list>
    </constructor-arg>
</bean>
Run Code Online (Sandbox Code Playgroud)

通用认证内容:

<bean id="httpRequestAccessDecisionManager" class="org.springframework.security.access.vote.AffirmativeBased">
    <property name="allowIfAllAbstainDecisions" value="false"/>
    <property name="decisionVoters">
        <list>
            <ref bean="roleVoter"/>
        </list>
    </property>
</bean>

<bean id="roleVoter" class="org.springframework.security.access.vote.RoleVoter"/>

<bean id="securityContextHolderAwareRequestFilter" class="org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter"/>
Run Code Online (Sandbox Code Playgroud)

访问控制过滤器(应该是不言自明的):

<bean id="fsi" class="org.springframework.security.web.access.intercept.FilterSecurityInterceptor">
    <property name="authenticationManager" ref="myAuthenticationManager"/>
    <property name="accessDecisionManager" ref="httpRequestAccessDecisionManager"/>
    <property name="securityMetadataSource">
        <sec:filter-invocation-definition-source>
            <sec:intercept-url pattern="/rest/**" access="ROLE_REST"/>
        </sec:filter-invocation-definition-source>
    </property>
</bean>
Run Code Online (Sandbox Code Playgroud)

您还应该能够使用@Secured方法注释来保护REST服务.

上面的上下文是从现有的REST服务webapp中提取的 - 对于任何可能的错别字都很抱歉.

通过使用库存secSpring标签,至少可以做到这里实现的大部分内容,但我更喜欢自定义方法,因为这给了我最大的控制权.

希望这至少可以让你开始.