如何在使用 LDAP 进行身份验证的项目中正确配置 Spring 安全的记住我选项?
How to correctly configure the remember me option of Spring Security in a project that use LDAP for authentication?
我是 Spring MVC 的新手,我在尝试理解如何在我的登录页面中实现 "remember me" 功能时遇到了一些问题。
所以我正在开发一个 Spring 项目,该项目使用 4.1.7.RELEASE 版本的 Spring。此 Web 应用程序使用 Spring 安全和 LDAP 来处理用户登录。
在这个项目中,我有一个名为 login.jsp 的登录页面,这个:
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<%@page session="true"%>
<%
response.setHeader("Cache-Control", "no-cache");
response.setHeader("Pragma", "no-cache");
response.setDateHeader("Expires", -1);
%>
<!DOCTYPE html>
<html>
<head>
<!-- link href="<c:url value="resources/css/style.css" />" rel="stylesheet"-->
<link href="<c:url value="resources/css/bootstrap.css" />"
rel="stylesheet">
<link href="<c:url value="resources/css/bootstrap-theme.css" />"
rel="stylesheet">
<link href="<c:url value="resources/css/login.css" />" rel="stylesheet">
<title>Login Page</title>
</head>
<body onload='document.loginForm.username.focus();'>
<!-- div id="intestazione">
<h1 align="center">WIFI e PNSD</h1>
</div-->
<div class="container">
<section id="sezioneBenvenuto">
<h1 id="benvenuto" >Benvenuto</h1>
</section>
<section id="sezioneLogo" >
<img src="resources/img/logo2.png" id="logo">
</section>
<section id="sezioneLogin">
<div id="login-box">
<c:if test="${not empty error}">
<div class="error">${error}</div>
</c:if>
<form class="form-horizontal" name='loginForm' action="<c:url value='/j_spring_security_check' />" method='POST'>
<div class="form-group" style="margin: 0px;" >
<label class="sr-only" for="exampleInputEmail3">Email address</label>
<input type='text' name='username' class="form-control" id="exampleInputEmail3" placeholder="Nome Utente">
<br>
</div>
<div class="form-group" style="margin: 0px;" >
<label class="sr-only" for="exampleInputPassword3">Password</label>
<input type='password' name='password' class="form-control" id="exampleInputPassword3" placeholder="Password">
<br>
</div>
<!-- <button type="submit" class="btn btn-default">Sign in</button> -->
<input id="ricorda" name="submit" type="submit" class="btn btn-default" value="Accedi" style="color: #0F8BB0;" />
<br>
<div style="white-space: nowrap; padding-top: 35px;">
<a id="linkGestioneUtenza" class="pull-left" href="${linkGestioneUtenza}">Gestione utenza</a>
<div class="pull-right">
<input style="vertical-align: top;" type="checkbox">
<label style="vertical-align: top; font-weight: normal; color: #0F8BB0;">Ricordami</label>
</div>
</div>
</form>
</div>
</section>
</div>
<!--jsp:include page="footer.jsp" /-->
<script type="text/javascript" src="webjars/bootstrap/3.2.0/js/bootstrap.min.js"></script>
<script type="text/javascript" src="webjars/jquery/2.1.1/jquery.min.js"></script>
</body>
</html>
因此,正如您在前面的代码片段中看到的那样,有一个复选框代表 记住我 选择:
<div class="pull-right">
<input style="vertical-align: top;" type="checkbox">
<label style="vertical-align: top; font-weight: normal; color: #0F8BB0;">Ricordami</label>
</div>
好的,使用之前的 login.jsp 页面,我可以毫无问题地使用我的凭据访问我的应用程序,但是,如果我选中记住我复选框,它无法工作(事实上,当我再次访问该应用程序时,我必须再次插入我的凭据)。
所以我阅读了官方文档,发现我必须通过向浏览器发送 cookie 来实现或配置此行为,并在未来的会话中检测到 cookie 并导致自动登录,如此处所述: http://docs.spring.io/spring-security/site/docs/4.1.x-SNAPSHOT/reference/html/remember-me.html
据我所知,有两种方法可以做到:
第一个使用哈希来保护基于 cookie 的令牌的安全性。
第二种使用数据库或者其他持久化存储机制来
存储生成的令牌
这里是第一个疑问:这些断言究竟意味着什么?这两种方法有什么区别?
在文档中我还可以阅读:
Note that both implemementations require a UserDetailsService. If
you are using an authentication provider which doesn’t use a
UserDetailsService (for example, the LDAP provider) then it won’t work unless you also have a UserDetailsService bean in your
application context.
好的,在这个项目中,用户身份验证是使用 LDAP 进行的。阅读文档,在我看来 UserDetailsService 是一个接口(因此必须由自定义具体 class 实现?),它加载特定于用户的数据。
所以现在我的疑问是:这个 UserDetailsService 究竟是做什么的?我应该在哪里声明它才能将其放入我的 应用程序上下文 ?进入Spring安全配置文件(spring-security.xml)或者在Spring配置文件(root -context.xml) ?
这些断言究竟意味着什么?
基本上记住我的功能有两件事
- 登录成功后,创建一个"rememeber-me"浏览器cookie
使用基于用户名、密码的令牌(可以计算令牌并
如果需要,可以保存在 db 中,也可以即时计算的哈希值
用户,密码)。
- 当用户尝试在没有任何会话的情况下访问受保护页面时
(session因为超时过期),然后RememberMe服务
将尝试通过反转过程来自动登录用户(获取 cookie
并检查 userDetails 哈希或检查数据库中的持久令牌
)
这两种方法有什么区别?
TokenBasedRememberMeServices -
- 它使用用户详细信息的散列来保护
基于 cookie 的令牌。
- 它包含密码的散列,这个解决方案是潜在的
如果 cookie 被捕获,则易受攻击。
PersistentTokenBasedRememberMeServices
- 它使用数据库或其他持久存储机制来存储
生成的令牌。
- 它使用用户的唯一系列标识符。这标识了
用户的初始登录并在每次用户登录时保持不变
在该持续会话期间自动登录。它也是
包含一个随机令牌,每次用户登录时都会重新生成
通过持久的记住我的功能。这种组合
随机生成的系列和令牌被持久化,使一个蛮力
强制攻击不太可能。
您的用例示例
public class LdapUserDetailsService implements UserDetailsService {
@Override
public UserDetails loadUserByUsername(final String userName) throws UsernameNotFoundException {
//Basically you need user details , username,password,roles you can fetch from your LdapService
final List<GrantedAuthority> authorities = new ArrayList<GrantedAuthority>();
final SimpleGrantedAuthority authority = new SimpleGrantedAuthority("ROLE_USER");
authorities.add(authority);
return new User(userName, "password", authorities); }
Spring 安全配置文件 (spring-security.xml)
<!-- Remember me config -->
<security:http
<security:remember-me services-ref="rememberMeServices" />
</security:http>
<bean id="customUserDetailsService" class="com..LdapUserDetailsService"/>
<bean id="rememberMeServices" class="org.springframework.security.web.authentication.rememberme.TokenBasedRememberMeServices">
<constructor-arg index="0" value="myAppKey" />
<constructor-arg index="1" ref="customUserDetailsService" />
</bean>
<bean id="rememberMeAuthenticationProvider" class="org.springframework.security.authentication.RememberMeAuthenticationProvider">
<constructor-arg index="0" value="myAppKey" />
</bean>
<security:authentication-manager alias="authenticationManager">
<security:authentication-provider ref="rememberMeAuthenticationProvider"/>
</security:authentication-manager>
UserDetailService 是一个用于加载用户特定数据(例如用户名和密码等)的接口。您将实施 UserDetailService,然后编写您的自定义用户详细信息服务以提供用户特定信息。
以下是如何使用基于 UserDetailService 的身份验证的示例:-
Custom UserDetailsService example for spring 3 security
对于记住我的选项,您最好选择 cookie。将数据库用于记住我选项不是一个好主意。只需使用 cookie。
我是 Spring MVC 的新手,我在尝试理解如何在我的登录页面中实现 "remember me" 功能时遇到了一些问题。
所以我正在开发一个 Spring 项目,该项目使用 4.1.7.RELEASE 版本的 Spring。此 Web 应用程序使用 Spring 安全和 LDAP 来处理用户登录。
在这个项目中,我有一个名为 login.jsp 的登录页面,这个:
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<%@page session="true"%>
<%
response.setHeader("Cache-Control", "no-cache");
response.setHeader("Pragma", "no-cache");
response.setDateHeader("Expires", -1);
%>
<!DOCTYPE html>
<html>
<head>
<!-- link href="<c:url value="resources/css/style.css" />" rel="stylesheet"-->
<link href="<c:url value="resources/css/bootstrap.css" />"
rel="stylesheet">
<link href="<c:url value="resources/css/bootstrap-theme.css" />"
rel="stylesheet">
<link href="<c:url value="resources/css/login.css" />" rel="stylesheet">
<title>Login Page</title>
</head>
<body onload='document.loginForm.username.focus();'>
<!-- div id="intestazione">
<h1 align="center">WIFI e PNSD</h1>
</div-->
<div class="container">
<section id="sezioneBenvenuto">
<h1 id="benvenuto" >Benvenuto</h1>
</section>
<section id="sezioneLogo" >
<img src="resources/img/logo2.png" id="logo">
</section>
<section id="sezioneLogin">
<div id="login-box">
<c:if test="${not empty error}">
<div class="error">${error}</div>
</c:if>
<form class="form-horizontal" name='loginForm' action="<c:url value='/j_spring_security_check' />" method='POST'>
<div class="form-group" style="margin: 0px;" >
<label class="sr-only" for="exampleInputEmail3">Email address</label>
<input type='text' name='username' class="form-control" id="exampleInputEmail3" placeholder="Nome Utente">
<br>
</div>
<div class="form-group" style="margin: 0px;" >
<label class="sr-only" for="exampleInputPassword3">Password</label>
<input type='password' name='password' class="form-control" id="exampleInputPassword3" placeholder="Password">
<br>
</div>
<!-- <button type="submit" class="btn btn-default">Sign in</button> -->
<input id="ricorda" name="submit" type="submit" class="btn btn-default" value="Accedi" style="color: #0F8BB0;" />
<br>
<div style="white-space: nowrap; padding-top: 35px;">
<a id="linkGestioneUtenza" class="pull-left" href="${linkGestioneUtenza}">Gestione utenza</a>
<div class="pull-right">
<input style="vertical-align: top;" type="checkbox">
<label style="vertical-align: top; font-weight: normal; color: #0F8BB0;">Ricordami</label>
</div>
</div>
</form>
</div>
</section>
</div>
<!--jsp:include page="footer.jsp" /-->
<script type="text/javascript" src="webjars/bootstrap/3.2.0/js/bootstrap.min.js"></script>
<script type="text/javascript" src="webjars/jquery/2.1.1/jquery.min.js"></script>
</body>
</html>
因此,正如您在前面的代码片段中看到的那样,有一个复选框代表 记住我 选择:
<div class="pull-right">
<input style="vertical-align: top;" type="checkbox">
<label style="vertical-align: top; font-weight: normal; color: #0F8BB0;">Ricordami</label>
</div>
好的,使用之前的 login.jsp 页面,我可以毫无问题地使用我的凭据访问我的应用程序,但是,如果我选中记住我复选框,它无法工作(事实上,当我再次访问该应用程序时,我必须再次插入我的凭据)。
所以我阅读了官方文档,发现我必须通过向浏览器发送 cookie 来实现或配置此行为,并在未来的会话中检测到 cookie 并导致自动登录,如此处所述: http://docs.spring.io/spring-security/site/docs/4.1.x-SNAPSHOT/reference/html/remember-me.html
据我所知,有两种方法可以做到:
第一个使用哈希来保护基于 cookie 的令牌的安全性。
第二种使用数据库或者其他持久化存储机制来 存储生成的令牌
这里是第一个疑问:这些断言究竟意味着什么?这两种方法有什么区别?
在文档中我还可以阅读:
Note that both implemementations require a UserDetailsService. If you are using an authentication provider which doesn’t use a UserDetailsService (for example, the LDAP provider) then it won’t work unless you also have a UserDetailsService bean in your application context.
好的,在这个项目中,用户身份验证是使用 LDAP 进行的。阅读文档,在我看来 UserDetailsService 是一个接口(因此必须由自定义具体 class 实现?),它加载特定于用户的数据。
所以现在我的疑问是:这个 UserDetailsService 究竟是做什么的?我应该在哪里声明它才能将其放入我的 应用程序上下文 ?进入Spring安全配置文件(spring-security.xml)或者在Spring配置文件(root -context.xml) ?
这些断言究竟意味着什么?
基本上记住我的功能有两件事
- 登录成功后,创建一个"rememeber-me"浏览器cookie 使用基于用户名、密码的令牌(可以计算令牌并 如果需要,可以保存在 db 中,也可以即时计算的哈希值 用户,密码)。
- 当用户尝试在没有任何会话的情况下访问受保护页面时 (session因为超时过期),然后RememberMe服务 将尝试通过反转过程来自动登录用户(获取 cookie 并检查 userDetails 哈希或检查数据库中的持久令牌 )
这两种方法有什么区别?
TokenBasedRememberMeServices -
- 它使用用户详细信息的散列来保护 基于 cookie 的令牌。
- 它包含密码的散列,这个解决方案是潜在的 如果 cookie 被捕获,则易受攻击。
PersistentTokenBasedRememberMeServices
- 它使用数据库或其他持久存储机制来存储 生成的令牌。
- 它使用用户的唯一系列标识符。这标识了 用户的初始登录并在每次用户登录时保持不变 在该持续会话期间自动登录。它也是 包含一个随机令牌,每次用户登录时都会重新生成 通过持久的记住我的功能。这种组合 随机生成的系列和令牌被持久化,使一个蛮力 强制攻击不太可能。
您的用例示例
public class LdapUserDetailsService implements UserDetailsService {
@Override
public UserDetails loadUserByUsername(final String userName) throws UsernameNotFoundException {
//Basically you need user details , username,password,roles you can fetch from your LdapService
final List<GrantedAuthority> authorities = new ArrayList<GrantedAuthority>();
final SimpleGrantedAuthority authority = new SimpleGrantedAuthority("ROLE_USER");
authorities.add(authority);
return new User(userName, "password", authorities); }
Spring 安全配置文件 (spring-security.xml)
<!-- Remember me config -->
<security:http
<security:remember-me services-ref="rememberMeServices" />
</security:http>
<bean id="customUserDetailsService" class="com..LdapUserDetailsService"/>
<bean id="rememberMeServices" class="org.springframework.security.web.authentication.rememberme.TokenBasedRememberMeServices">
<constructor-arg index="0" value="myAppKey" />
<constructor-arg index="1" ref="customUserDetailsService" />
</bean>
<bean id="rememberMeAuthenticationProvider" class="org.springframework.security.authentication.RememberMeAuthenticationProvider">
<constructor-arg index="0" value="myAppKey" />
</bean>
<security:authentication-manager alias="authenticationManager">
<security:authentication-provider ref="rememberMeAuthenticationProvider"/>
</security:authentication-manager>
UserDetailService 是一个用于加载用户特定数据(例如用户名和密码等)的接口。您将实施 UserDetailService,然后编写您的自定义用户详细信息服务以提供用户特定信息。 以下是如何使用基于 UserDetailService 的身份验证的示例:-
Custom UserDetailsService example for spring 3 security
对于记住我的选项,您最好选择 cookie。将数据库用于记住我选项不是一个好主意。只需使用 cookie。