如何使用 Spring Security 登录页面传递附加参数
Posted
技术标签:
【中文标题】如何使用 Spring Security 登录页面传递附加参数【英文标题】:How to pass an additional parameter with spring security login page 【发布时间】:2012-04-21 21:22:59 【问题描述】:我正在尝试将数据库名称设置为来自 Spring Security 登录页面的请求输入参数。目前我只获得使用 spring security SecurityContextHolder.getContext().getAuthentication()
检索到的用户名。
如何访问登录页面上设置的附加字段?
【问题讨论】:
是登录前传这个参数还是登录后从DB获取参数? 我想在连接到数据库之前获取请求参数值,我想根据登录屏幕上提供的选择值来决定用户需要连接哪个数据库。 我不认为,Spring 有能力做到这一点。无论如何,您可以创建我们自己的身份验证过滤器,并从HttpRequest
对象中获取此参数。
看看UsernamePasswordAuthenticationFilter
。默认情况下在任何登录页面上使用它。
是的,我正在努力解决这个问题。但是我错过了那里的一些部分并遇到了错误。如果您有一些想法或工作示例(配置),请告诉我。
【参考方案1】:
详细阐述@Vacuum 的评论
这是一个简单的方法(未经测试,但我相信这会奏效)
-
创建一个新类
ExUsernamePasswordAuthenticationFilter
,它将扩展默认过滤器并获取附加参数并将其存储在会话中。它看起来像这样:
public class ExUsernamePasswordAuthenticationFilter extends UsernamePasswordAuthenticationFilter
@Override
public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException
final String dbValue = request.getParameter("dbParam");
request.getSession().setAttribute("dbValue", dbValue);
return super.attemptAuthentication(request, response);
-
在您的
UserDetailsService
实现中,修改您的实现:
UserDetails loadUserByUsername(String username) throws UsernameNotFoundException, DataAccessException;
获取步骤 1) 中的过滤器提供的会话变量。
-
在您的
<http />
安全设置中,使用您的自定义过滤器覆盖默认过滤器
<custom-filter ref="beanForYourCustomFilterFromStep1" position="FORM_LOGIN_FILTER"/>
有关自定义过滤器的更多信息,请参阅文档的这一部分:http://static.springsource.org/spring-security/site/docs/3.1.x/reference/springsecurity-single.html#ns-custom-filters
【讨论】:
非常感谢您的信息。我实现了,效果很好。 这样做的侵入性较小,而且不会违反UserDetailsService
的合同。我同意@sourcedelica。也可以将我的answer 转至类似问题以获取更详细的示例。
@Bhas,你是如何修改 UserDetailsService 来获取会话变量的?【参考方案2】:
有很多方法可以做到这一点,但官方的方法是使用自定义 AuthenticationDetails
和 AuthenticationDetailsSource
,分别继承 Spring 的 WebAuthenticationDetails
和 WebAuthenticationDetailsSource
。将额外字段添加到自定义 WebAuthenticationDetails
并让自定义 WebAuthenticationDetailsSource
从请求中获取数据以填充该字段。
在 Spring Security 3.1 中,使用 <form-login>
元素的 authentication-details-source-ref
属性很容易配置。
在 3.0 中,您必须使用 BeanPostProcessor
。 using a BeanPostProcessor to configure a custom WebAuthenticationDetailsSource 上的 Spring Security FAQ 中有一个示例。
完成此操作后,您可以调用 SecurityContextHolder.getContext().getAuthentication().getDetails() 来访问您的额外字段。
【讨论】:
感谢 Ericacm,他们已经实施了 Taylor Mingos 提供的解决方案,对我来说效果很好。 感谢自定义 AuthenticationDetails 的想法。这很有趣。你说它是官方的,但我找不到任何关于该技术的官方文档。有吗? 没有太多文档 - 你必须从UsernamePasswordAuthenticationFilter
的工作原理中推断出来 - 它使用 WebAuthenticationDetailsSource
并将 WebAuthenticationDetails
添加到 UsernamePasswordAuthenticationToken
。【参考方案3】:
sourcedelica 使用AuthenticationDetailsSource
和自定义AuthenticationDetails
提及。
这是一个例子。
将authentication-details-source-ref
属性与bean id customWebAuthenticationDetailsSource
添加到form-login
:
<security:http>
<security:intercept-url pattern="/**" access="..." />
<security:form-login authentication-details-source-ref="customWebAuthenticationDetailsSource" login-page="..." />
<security:logout logout-success-url="..." />
</security:http>
创建一个新类CustomWebAuthenticationDetailsSource
:
package security;
import org.springframework.security.authentication.AuthenticationDetailsSource;
import org.springframework.security.web.authentication.WebAuthenticationDetails;
import javax.servlet.http.HttpServletRequest;
public class CustomWebAuthenticationDetailsSource implements AuthenticationDetailsSource<HttpServletRequest, WebAuthenticationDetails>
@Override
public WebAuthenticationDetails buildDetails(HttpServletRequest context)
return new CustomWebAuthenticationDetails(context);
以及相关的CustomWebAuthenticationDetails
:
package security;
import org.springframework.security.web.authentication.WebAuthenticationDetails;
import javax.servlet.http.HttpServletRequest;
public class CustomWebAuthenticationDetails extends WebAuthenticationDetails
private final String yourParameter;
public CustomWebAuthenticationDetails(HttpServletRequest request)
super(request);
yourParameter = request.getParameter("yourParameter");
public String getyourParameter()
return yourParameter;
//TODO override hashCode, equals and toString to include yourParameter
@Override
public int hashCode() /* collapsed */
@Override
public boolean equals(Object obj) /* collapsed */
@Override
public String toString() /* collapsed */
【讨论】:
那么我该如何使用 CustomWebAuthenticationDetails ? 见@sourcedelica 回答:SecurityContextHolder.getContext().getAuthentication().getDetails()
对我不起作用。 AuthenticationDetailsSource 在登录后调用 buildDetails 并且我的 GET 参数不再存在。使用 Spring 3.1.6
@raupach 您的安全配置一定有问题。如果您愿意,可以从Github 获取我的示例进行调试。
@diegosahagun 在调用JdbcDaoImpl.loadUsersByUsername
时,SecurityContext
没有填充当前的Authentication
,因此null
引用。在您的情况下,您需要一个自定义的AuthenticationProvider
,它能够处理您的额外参数。在这种情况下,您不能UserDetailsService
。也许您可以在单独的问题中详细说明您的问题并获得多个答案。【参考方案4】:
@user1322340 没有提供在 loadUserByUsername 函数中获取会话属性的实现细节:
第 1 步:按照@user1322340 提供的所有步骤进行操作
第 2 步: 您需要像这样在 web.xml 中添加一项配置:
<listener>
<listener-class>
org.springframework.web.context.request.RequestContextListener
</listener-class>
</listener>
第 3 步: 使用此类代码获取属性:
RequestContextHolder.getRequestAttributes().getAttribute("yourAttributeName", RequestAttributes.SCOPE_SESSION);
第 4 步:在 spring 安全配置中注册您的过滤器。 如果您收到错误“authenticationManager must be specified”。在配置中注册过滤器后。您需要为扩展过滤器设置一个 authenticationManagerBean 并以这种方式进行配置:
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter
@Bean
public ExUsernamePasswordAuthenticationFilter exUsernamePasswordAuthenticationFilter()
throws Exception
ExUsernamePasswordAuthenticationFilter exUsernamePasswordAuthenticationFilter = new ExUsernamePasswordAuthenticationFilter();
exUsernamePasswordAuthenticationFilter
.setAuthenticationManager(authenticationManagerBean());
return exUsernamePasswordAuthenticationFilter;
@Bean
@Override
public AuthenticationManager authenticationManagerBean() throws Exception
return super.authenticationManagerBean();
@Override
protected void configure(HttpSecurity http) throws Exception
RequestMatcher requestMatcher = new RequestMatcher()
@Override
public boolean matches(HttpServletRequest httpServletRequest)
if (httpServletRequest.getRequestURI().indexOf("/api", 0) >= 0)
return true;
return false;
;
http
.addFilterBefore(exUsernamePasswordAuthenticationFilter(), UsernamePasswordAuthenticationFilter.class)
...
【讨论】:
【参考方案5】:对于使用java配置的spring security 3.0或以上版本,以下简单步骤即可。
在 配置中 HttpSecurity 对象中的 UserNameandPasswordAuthenticationFilter。
http.addFilterBefore(new YourFilter(), UsernamePasswordAuthenticationFilter.class);
让过滤器有这样一行来获取您的所需字段 请求会话。
if(requestPath != null &&requestPath.equals("/login") )
session.setAttribute("yourParam",req.getParameter("yourParam"));
稍后您可以从任何类的会话中获取参数值:
String yourParam =(String)request.getSession().getAttribute("yourParam");
【讨论】:
【参考方案6】:如果您使用自定义AuthenticationProvider
,则有一种更简单的方法。您可以注入 HttpServletRequest
并检索您的额外参数:
@Component
public class CustomAuthenticationProvider implements AuthenticationProvider
@Autowired(required = false)
private HttpServletRequest request;
@Autowired
private MyAccountService myAccountService;
@Override
public Authentication authenticate(Authentication authentication)
System.out.println("request testing= " + request.getParameter("testing"));
.....
@Override
public boolean supports(Class<?> authentication)
return authentication.equals(UsernamePasswordAuthenticationToken.class);
【讨论】:
【参考方案7】:简单的方法:
1) 注册RequestContextListener
@Bean
public RequestContextListener requestContextListener()
return new RequestContextListener();
2) 到主类:
HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.
currentRequestAttributes()).
getRequest();
3) 之后我们可以在自定义标题中获取参数:
request.getHeader("OrganizationId")
【讨论】:
【参考方案8】:最简单的方法,只需两步:
第 1 步。
在 web.xml 中添加如下监听器:
<listener>
<listener-class>
org.springframework.web.context.request.RequestContextListener
</listener-class>
</listener>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value></param-value>
</context-param>
第 2 步。
在你想要获取额外参数的类方法中添加以下内容:
RequestAttributes attribs = RequestContextHolder.getRequestAttributes();
if (RequestContextHolder.getRequestAttributes() != null)
HttpServletRequest request = ((ServletRequestAttributes) attribs).getRequest();
现在您可以通过以下方式获取您的附加参数,假设附加参数名为“loginType”:
request.getParameter("loginType")
【讨论】:
以上是关于如何使用 Spring Security 登录页面传递附加参数的主要内容,如果未能解决你的问题,请参考以下文章
如何使用自定义登录页面纠正 Spring Security 异常?
如何使初始登陆页面不是spring security的登录表单?
如何使用 Spring Security 实现登录页面以使其与 Spring Web 流一起使用?
如何使用 Spring Security 在 login.jsp 页面显示登录错误消息?