如何使用 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,以便正确显示默认登录页面并进行身份验证(我实现了 UserDetailsService
和 DaoAuthenticationProvider
来执行此操作)。
下一步:用我的登录页面替换默认的 spring 登录页面并发布凭据。
但是我如何处理提交的登录凭据? 我假设我将表单发布到控制器,验证凭据,但我不清楚是什么正确的步骤是在那之后。例如:
我是在调用 AuthenticationManager 的方法吗? 我需要为此定义一个 bean 吗? 是否有我需要实现的接口/服务,例如 AuthenticationEntryPoint 之类的?我已经阅读了 3 次文档,但并没有完全遵循它们。我知道这很简单,所以我只需要听听流程应该如何进行。
【问题讨论】:
你想达到什么目的?为什么不能只配置 Spring Security 以使用自己的表单而不是默认表单? 啊,是的,我能做到,这就是我要死的原因。 :) 在 Spring 中有很多方法可以做某事,而我在无数的选择中迷失了方向。最终,我只需要更清楚地了解如何使用我们越来越少地谈论同一个问题,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)。
【讨论】:
感谢您的详细解释。它帮助我最终理解了我将为将来阅读此内容的任何人添加一个明确的答案:
当您在 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&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.UserDetailsService 并重写方法 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?