当前位置: 首页 > 知识库问答 >
问题:

使用rest web服务的Spring MVC+Spring Security登录

桓修能
2023-03-14

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

我四处寻找,但一直未能找到如何完成这一点的好例子,所有的尝试都是徒劳的。

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

另一方面,我怀疑自己这种方法是否正确,因为很难找到一个有同样问题的例子或其他人。这种做法是错误的吗?

我之所以要这样做,而不是仅仅进行JDBC身份验证,是因为我的整个web应用程序是无状态的,并且数据库总是通过封装“请求队列”的RESTful web服务访问的,我也希望尊重这一点来进行用户身份验证和验证。

  1. 使用带有AuthenticationSuccessHandler的自定义authenticationFilter。显然不起作用,因为用户已在此点登录。
  2. 实现entry-point-ref筛选器。
  3. 在basic_auth_filter位置执行自定义筛选
  4. 创建一个自定义身份验证提供程序(苦苦挣扎,没有运气!)。我正在重试此操作,同时得到一些答案。
  5. 当我开始使用CAS时,我决定改写一个问题。也许将来我可以考虑在我的webapp中安装一个CAS服务器,但目前看来,这似乎是一个巨大的矫枉过正。

提前道谢!

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

<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 { ... }

共有1个答案

沈琛
2023-03-14
  1. 您可以通过扩展AbstractPreAuthenticatedProcessingFilter来定义自定义预身份验证筛选器。
  2. 在getPreAuthenticatedPrincipal()方法的实现中,您可以检查cookie是否存在,如果它存在,则返回cookie名称为主体和凭据中的cookie值。
  3. 使用PreAuthenticatedAuthenticationProvider并提供自定义的preAuthenticatedUserDetailsService来检查cookie是否有效,如果其有效还提取授予的权限,则抛出AttenticationException(如BadCredentialsException)
  4. 要使用用户名/密码对用户进行身份验证,请添加表单登录筛选器、基本筛选器或带有自定义身份验证提供程序(或自定义userdetailsService)的自定义筛选器,以验证用户/密码

如果cookie存在,预身份验证过滤器将在springContext中设置已验证的用户和您的用户名。/password过滤器将不会被调用,如果cookie不存在/无效,身份验证入口点将触发使用用户名/密码的身份验证

希望有帮助

 类似资料:
  • 我正在学习springsecurity(基于java的配置),我无法使注销正常工作。当我点击注销时,我看到URL更改为http://localhost:8080/logout并获取“HTTP 404-/logout”。登录功能工作正常(即使使用自定义登录表单),但问题是注销,我怀疑重定向的url“localhost:8080/logout”应该类似于“localhost:8808/springte

  • 我有一个现有的Spring应用程序,它有自己的上下文,从Spring xml文件的douzens中引导。Grizzly web服务器开始发布Soap服务。 现在我也想满足同一只灰熊的Rest请求。我使用的是jersey-spring3,但它从所需的applicationContext.xml中启动自己的、独立的应用程序上下文。 这是创建注册Rest和Soap Web服务的Grizzly HttpS

  • 创建restful应用程序,但它不会以XML格式返回响应。即使在点击URL时控制台上也没有日志“http://localhost:8080/message/webapi/messages". 我返回一个列表,并使用@products(MediaType.APPLICATION\uxml)以XML形式返回响应。 消息资源。Java语言 Message.java 如果我不使用@XMLRootEleme

  • 错误日志: 浏览器出错 org.springframework.web.util.NestedServletException:请求处理失败;嵌套异常为java.lang.IllegalArgumentException:无效的处理程序方法返回值:false org.springframework.web.servlet.frameworkServlet.processRequest(framew

  • 目前,我正在使用以下内容将用户登录到我的应用程序中。然而,我想使用一个角函数来实际执行登录。为此,我想创建一个Rest网络服务来进行身份验证,但是我在SO上看到的所有示例都使用我认为被贬低的用户。我还希望该服务返回有关用户的信息。 我要问的是如何将MyUserDetailsService更改为用作登录的restful服务,或者如何创建一个可用于登录的服务,该服务将在登录后返回用户对象。 这是我的a

  • 正在使用Spring MVC创建Restful Web服务... 下面是我的pom.xml: WEB-INF/web.xml: web-inf/mvc-dispatcher-servlet.xml: src/main/resources/database_db.xml: @Repository public class UserDAO{ } SRC/Test/Java: 这就像在print()语句