如何使用 Spring Security / Spring MVC 处理表单登录

Posted

技术标签:

【中文标题】如何使用 Spring Security / Spring MVC 处理表单登录【英文标题】:How to process a form login using Spring Security / Spring MVC 【发布时间】:2011-05-03 08:04:21 【问题描述】:

简单的问题,我只需要一个指向正确方向的指针:

我有一个简单的 Spring MVC/Spring Security webapp。最初我设置了 Spring Security,以便正确显示默认登录页面并进行身份验证(我实现了 UserDetailsServiceDaoAuthenticationProvider 来执行此操作)。

下一步:用我的登录页面替换默认的 spring 登录页面并发布凭据。

但是我如何处理提交的登录凭据? 我假设我将表单发布到控制器,验证凭据,但我不清楚是什么正确的步骤是在那之后。例如:

我是在调用 AuthenticationManager 的方法吗? 我需要为此定义一个 bean 吗? 是否有我需要实现的接口/服务,例如 AuthenticationEntryPoint 之类的?

我已经阅读了 3 次文档,但并没有完全遵循它们。我知道这很简单,所以我只需要听听流程应该如何进行。

【问题讨论】:

你想达到什么目的?为什么不能只配置 Spring Security 以使用自己的表单而不是默认表单? 啊,是的,我能做到,这就是我要死的原因。 :) 在 Spring 中有很多方法可以做某事,而我在无数的选择中迷失了方向。最终,我只需要更清楚地了解如何使用 。我没有意识到它实际上会拦截 login-processing-url 路径上的请求并处理它们,我试图创建自己的控制器来处理登录表单请求(简单表单登录的不必要步骤)。跨度> 【参考方案1】:

我们越来越少地谈论同一个问题,this is my approach 让我们看看人们会怎么说。

【讨论】:

你在那里使用 Spring Security 吗?我在表单登录上迷路了,但是使用 Spring Security 提供的基本默认登录页面(来自 Spring 框架的单独捆绑包),您需要实现 UserDetails 服务,并且这些文档特别呼吁反对在会话中存储任何用户信息(它们应该存储在由 SecurityContextHolder 处理的 UserDetails 对象中)。您将通过 SecurityContextHolder 访问所有内容,并确定经过身份验证的用户是否具有您在 UserDetails 对象中为其定义的特定角色。 实际上,我目前没有使用任何 Spring Security 框架,但我可能是一个好主意。我没有在 HTTP 会话上存储任何内容,因为据我了解它不是线程安全的。我将它存储在会话级别。我还没有决定是否值得实施 Spring Security,想听听大师们怎么说。 Spring 安全性很好,实施起来也不难。对我来说(我和你的情况几乎完全相同)这似乎很合乎逻辑。你可能会像学习额外的框架一样大惊小怪,你只会花更多的时间在前面而不是从长远来看。在那里之后,应用各种安全选项真的很容易。我建议至少阅读文档。【参考方案2】:

Spring Security reference documentation 概述了5.4 Authentication in a Web Application 中的基本处理流程。第6点:

接下来,服务器将决定提供的凭据是否有效。如果它们有效,则将进行下一步。如果它们无效,通常会要求您的浏览器重试(因此您返回到上面的第二步)。

...

Spring Security 有不同的类负责上述大部分步骤。主要参与者(按使用顺序)是 ExceptionTranslationFilter、一个 AuthenticationEntryPoint 和一个“身份验证机制”,它负责调用我们在上一节中看到的 AuthenticationManager。

我不得不承认,这里的文档有点混乱,所以我再给你一些指点——这里提到的“身份验证机制”就是你要的东西,它负责处理浏览器发送的凭据。

由于将凭据附加到 HTTP 请求的详细信息在不同的身份验证方法(表单数据、普通标头和摘要标头)之间存在很大差异,因此没有通用的“身份验证机制” - 相反,每种方法都实现了自己的机制,在基于网络的身份验证的情况下,它通常是一个特殊过滤器,您必须在web.xml 中进行配置。

在您的情况下,您很可能对UsernamePasswordAuthenticationFilter 感兴趣 - 它用于处理基于表单的基本登录信息。您的自定义登录表单和过滤器之间的约定是 URL(表单发布的位置)+ 用户名和密码字段名称:

登录表单仅包含 j_username 和 j_password 输入字段,并发布到过滤器监控的 URL(默认为 /j_spring_security_check)。

【讨论】:

感谢您的详细解释。它帮助我最终理解了 标签的工作原理。我不明白它本质上是作为一个控制器工作的,它实际上处理发布到登录处理 url 的请求,并且我需要传递名为 j_username 和 j_password 的参数 你愿意帮我解决一个类似的话题吗?我尝试使用 java config 实现自定义登录处理方法,但我遇到了这个问题:***.com/questions/22738738/…。任何帮助都应该非常感谢。【参考方案3】:

我将为将来阅读此内容的任何人添加一个明确的答案:

当您在 Spring Security 中定义标签时,它将为您处理登录,我将详细介绍它是如何工作的(希望文档中如此详细):

<security:http auto-config="true">
    <security:form-login login-page="/login"
         login-processing-url="/postlogin"
         default-target-url="/myaccount"
         authentication-failure-url="/login?loginError=true" />
    <security:logout logout-url="/logout" />
</security:http>

login-page 是登录页面的 url。你应该有一个服务于这个页面的控制器(或静态 html 页面),这是你漂亮的登录表单。

login-processing-url 是表单登录组件处理的 URL。就好像表单登录组件为此页面实现了自己的控制器。您应该将表单发布到此页面。您还需要知道将您的用户名/密码参数命名为“j_username”和“j_login”

除此之外,以及上面其他相当明显的选项,您应该已经实现了一个UserDetailsService - 也就是说,创建一个类并实现接口UserDetailsService,该接口获取并返回一个UserDetails 对象(给定用户名的用户名/密码) - 并为该 UserDetails 对象提供其余的安全配置:

<security:authentication-manager>
        <security:authentication-provider ref="daoAuthenticationProvider" />
</security:authentication-manager>

<bean id="daoAuthenticationProvider"
    class="org.springframework.security.authentication.dao.DaoAuthenticationProvider" >
    <property name="userDetailsService" ref="myAuthorizationService" />
</bean>

【讨论】:

如果不指定 login-processing-url,默认使用 login-page 值,所以登录表单必须在那里发布。 (Spring Security 3.2.4) 请注意,在 Spring Security 4+ 中,用户名/密码参数现在默认为“用户名”和“密码” default-target-url属性有什么用? @DaveRlz 可以将用户名附加到 authentication-failure-url 吗?例如authentication-failure-url="/login?loginError=true&amp;username=getUser()【参考方案4】:

查看limc 回复Ritesh 的回复Configuring Spring Security 3.x to have multiple entry points 的帖子查看标题为:

2011 年 1 月 29 日更新 - @Ritesh 的技术 更新 - @Ritesh 技术的解决方案

这是一个简洁、高级的好例子,说明如何在 Spring Security 中自定义登录过程

【讨论】:

【参考方案5】:

如果您使用的是 JDBC 可访问数据库,那么您可以使用以下身份验证提供程序并避免创建自定义提供程序。它将所需的代码减少到 9 行 XML:

<authentication-provider>
    <jdbc-user-service data-source-ref="dataSource" users-by-username-query="select username,password from users where username=?" authorities-by-username-query="select u.username, r.authority from users u, roles r where u.userid = r.userid and u.username =?" />
</authentication-provider>

然后您可以按如下方式设置数据源

<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
    <property name="driverClassName" value="com.mysql.jdbc.Driver" />
    <property name="url" value="jdbc:mysql://localhost:3306/DB_NAME" />
    <property name="username" value="root" />
    <property name="password" value="password" />
</bean>

看看这个帖子:http://codehustler.org/blog/spring-security-tutorial-form-login/ 它涵盖了您需要了解的有关自定义 Spring Security 表单登录的所有信息。

【讨论】:

【参考方案6】:
<security:http auto-config="true">
  <security:form-login login-page="/login"
   login-processing-url="/postlogin"
    default-target-url="/myaccount"
     authentication-failure-url="/login?loginError=true" />
  <security:logout logout-url="/logout" />
</security:http>

login-page 是登录表单的 URL login-processing-url 是提交登录表单的 url。 Spring 将在 security.xml 文件中对您映射的身份验证管理器进行自我调用。

过程

    你需要写一个类来实现org.springframework.security.authentication.AuthenticationProvider,重写方法Authentication authenticate(Authentication authentication) 第二个类扩展 org.springframework.security.core.userdetails.UserDetailsS​​ervice 并重写方法 loadUserByUsername(String username) 第二类表单,您可以在其中调用 DAO 并使用数据库获取用户名和密码来验证用户。 在 Authentication authenticate(Authentication authentication) 中,您将比较密码并返回成功失败。

【讨论】:

以上是关于如何使用 Spring Security / Spring MVC 处理表单登录的主要内容,如果未能解决你的问题,请参考以下文章

使用 Spring Security Saml 和 SP 应用程序的无状态会话

Spring security Saml - SP 和 IDP 的时间差

在期待多个应用程序时,我应该使用 Spring Security SAML 还是 Shiboleth SP?

生成 SP 元数据时出现意外的堆栈跟踪表单 Spring-Security-SAML?

如何使用 Spring MVC & Security、Jasig CAS 和 JSP 视图在 Spring Boot 2 中配置 UTF-8?

如何导入 Spring Security OAuth 授权服务器?