Spring MVC + Spring Security 使用一个休息的 web 服务登录

标签 spring rest spring-mvc spring-security

我有一个 SpringMVC Web 应用程序,它需要通过发送用户名和密码来使用 Spring Security 对 RESTful Web 服务进行身份验证。当用户登录时,需要将 cookie 设置到用户的浏览器,并在后续调用中使用 cookie 与另一个 RESTful Web 服务验证用户 session 。

我到处找,但我一直没能找到一个很好的例子来说明如何做到这一点,我所有的尝试都是徒劳的。

这是我的想法:

我可以声明两个身份验证提供程序,第一个检查 cookie,如果由于任何原因失败,它会转到第二个检查用户名和密码的身份验证提供程序(如果该请求中没有用户名和密码,也会失败) .

这两个服务每次都返回用户的权限,spring security是“无状态”的。

另一方面,我质疑自己这种方法是否正确,因为很难找到具有相同问题的示例或其他人。这种方法有错吗?

我之所以要这样做而不仅仅是 JDBC 身份验证,是因为我的整个 Web 应用程序都是无状态的,并且始终通过包装“请愿队列”的 RESTful Web 服务访问数据库,我想尊重用户身份验证和验证也是。

到目前为止我尝试了什么?我可以粘贴很长很长的 springSecurity-context.xml,但我现在只列出它们:

  • 使用带有 authenticationSuccessHandler 的自定义 authenticationFilter。显然不起作用,因为此时用户已经登录。
  • 实现入口点引用过滤器。
  • 在 BASIC_AUTH_FILTER 位置做一个自定义过滤器
  • 制作自定义身份验证提供程序(苦苦挣扎,没有运气!)。当我得到一些答案时,我正在重试。
  • 当我决定写一个问题时,我开始使用 CAS。也许将来我可以考虑在我的 web 应用程序中安装一个 CAS 服务器,但是就目前而言,这感觉像是一个巨大的矫枉过正。

  • 提前致谢!

    顺便说一句,我使用的是 Spring Security 3.1.4 和 Spring MVC 3.2.3

    编辑:由于@coder 回答,我能够做到

    以下是我所做的一些事情,我将尝试记录所有这些并将其发布在此处或不久后的博客文章中:
    <http use-expressions="true" create-session="stateless" entry-point-ref="loginUrlAuthenticationEntryPoint"
            authentication-manager-ref="customAuthenticationManager">
        <custom-filter ref="restAuthenticationFilter" position="FORM_LOGIN_FILTER" />
        <custom-filter ref="restPreAuthFilter" position="PRE_AUTH_FILTER" />
        <intercept-url pattern="/signin/**" access="permitAll" />
        <intercept-url pattern="/img/**" access="permitAll" />
        <intercept-url pattern="/css/**" access="permitAll" />
        <intercept-url pattern="/js/**" access="permitAll" />
        <intercept-url pattern="/**" access="hasRole('ROLE_USER')" />
    
    </http>
    
    <authentication-manager id="authManager" alias="authManager">
        <authentication-provider ref="preauthAuthProvider" />
    </authentication-manager>
    
    <beans:bean id="restPreAuthFilter" class="com.company.CustomPreAuthenticatedFilter">
        <beans:property name="cookieName" value="SessionCookie" />
        <beans:property name="checkForPrincipalChanges" value="true" />
        <beans:property name="authenticationManager" ref="authManager" />
    </beans:bean>
    
    <beans:bean id="preauthAuthProvider"
        class="com.company.CustomPreAuthProvider">
        <beans:property name="preAuthenticatedUserDetailsService">
            <beans:bean id="userDetailsServiceWrapper"
                class="org.springframework.security.core.userdetails.UserDetailsByNameServiceWrapper">
                <beans:property name="userDetailsService" ref="userDetailsService" />
            </beans:bean>
        </beans:property>
    </beans:bean>
    
    <beans:bean id="userDetailsService" class="com.company.CustomUserDetailsService" />
    
    <beans:bean id="loginUrlAuthenticationEntryPoint"
        class="org.springframework.security.web.authentication.LoginUrlAuthenticationEntryPoint">
        <beans:constructor-arg value="/signin" />
    </beans:bean>
    
    <beans:bean id="customAuthenticationManager"
        class="com.company.CustomAuthenticationManager" />
    
    <beans:bean id="restAuthenticationFilter"
        class="com.company.CustomFormLoginFilter">
        <beans:property name="filterProcessesUrl" value="/signin/authenticate" />
        <beans:property name="authenticationManager" ref="customAuthenticationManager" />
        <beans:property name="authenticationFailureHandler">
            <beans:bean
                class="org.springframework.security.web.authentication.SimpleUrlAuthenticationFailureHandler">
                <beans:property name="defaultFailureUrl" value="/login?login_error=t" />
            </beans:bean>
        </beans:property>
    </beans:bean>
    

    自定义实现是这样的:
    // Here, the idea is to write authenticate method and return a new UsernamePasswordAuthenticationToken
    public class CustomAuthenticationManager implements AuthenticationManager { ... }
    
    // Write attemptAuthentication method and return UsernamePasswordAuthenticationToken 
    public class CustomFormLoginFilter extends UsernamePasswordAuthenticationFilter { ... }
    
    // Write getPreAuthenticatedPrincipal and getPreAuthenticatedCredentials methods and return cookieName and cookieValue respectively
    public class CustomPreAuthenticatedFilter extends AbstractPreAuthenticatedProcessingFilter { ... }
    
    // Write authenticate method and return Authentication auth = new UsernamePasswordAuthenticationToken(name, token, grantedAuths); (or null if can't be pre-authenticated)
    public class CustomPreAuthProvider extends PreAuthenticatedAuthenticationProvider{ ... }
    
    // Write loadUserByUsername method and return a new UserDetails user = new User("hectorg87", "123456", Collections.singletonList(new GrantedAuthorityImpl("ROLE_USER")));
    public class CustomUserDetailsService implements UserDetailsService { ... }
    

    最佳答案

  • 您可以通过扩展来定义自定义预身份验证过滤器
    AbstractPreAuthenticatedProcessingFilter。
  • 在您的实现中
    getPreAuthenticatedPrincipal() 方法可以检查cookie是否存在
    如果它存在,则返回 cookie 名称是主体和 cookie 值
    证书。
  • 使用 PreAuthenticatedAuthenticationProvider 并提供您的自定义 preAuthenticatedUserDetailsS​​ervice 来检查 cookie 是否有效,如果其有效也获取授予的权限,否则会抛出 AuthenticationException 之类的 BadCredentialsException
  • 要使用用户名/密码对用户进行身份验证,请添加表单登录过滤器、基本过滤器或具有自定义身份验证提供程序(或自定义 userdetailsS​​ervice)的自定义过滤器以验证用户/密码

  • 如果 cookie 存在,pre auth 过滤器将在 springContext 中设置经过身份验证的用户,并且不会调用您的 username./password 过滤器,如果 cookie 缺失/无效,则身份验证入口点将触发使用用户名/密码的身份验证

    希望能帮助到你

    关于Spring MVC + Spring Security 使用一个休息的 web 服务登录,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18205436/

    相关文章:

    jquery - 如何使用 Jquery/WebClient/WebRequest 并以多个类对象作为参数来使用 WCF Rest

    spring - 配置文件未从 tomcat 中设置的环境变量中选取,但在 web.xml 中提及时选取

    java - Spring boot ConditionalOnBean 注解

    java - 使用 Spring Data MongoDB 在应用程序启动时加载初始数据

    java - Spring 和 hibernate : form for object containing objects

    python - 如何使用在 Apache Spark 上训练的 ML 模型开发 REST API?

    使用两个查询参数时 Java Rest 不起作用

    javascript - Ajax 调用 Spring Controller 时出现 400 Bad request 错误

    java - Spring 集成 Javascript

    java - 无法为 Spring MVC 中的变量设置值