Remember-Me

Remember-me 或者 persistent-login 身份验证是指网站能够在会话之间记住主体的身份。这通常是通过向浏览器发送 cookie 来实现的,在以后的会话中检测到 cookie 并完成自动登录。Spring Security 提供了执行这些操作所需的挂钩,并有两个具体的 remember-me 实现。一种使用散列来保持基于 cookie 的令牌的安全性,另一种使用数据库或其他持久存储机制来存储生成的令牌。

注意,这两个实现都需要 UserDetailsService。如果您使用的身份验证提供程序不使用 UserDetailsService (例如,LDAP 提供程序) ,那么除非在应用程序上下文中还有一个 UserDetailsService bean,否则它将无法工作。

一种简单的基于散列的令牌方法(Simple Hash-Based Token Approach)

这种方法使用散列来实现一个有用的 remember-me 策略。实际上,成功的交互式身份验证后,cookie 被发送到浏览器,其组成如下:

base64(username + ":" + expirationTime + ":" +
md5Hex(username + ":" + expirationTime + ":" password + ":" + key))

username:          作为 UserDetailsService 的标识
password:          与检索到的 UserDetails 中的一个匹配
expirationTime:   Remember-me 令牌失效的日期和时间,以毫秒表示
key:               一个用于防止修改 remember-me 令牌的私钥

因此,remember-me 令牌仅在指定的时间段内有效,并且用户名、密码和密钥不变。值得注意的是,这有一个潜在的安全问题,因为捕获的 remember-me 令牌将可以从任何用户代理使用,直到令牌过期为止。这与摘要式身份验证的问题相同。如果一个主体知道一个令牌已经被捕获,他们可以很容易地更改他们的密码并立即使所有记住我的令牌失效。如果需要更重要的安全性,应该使用下一节中描述的方法。或者,remember-me 服务根本不应该被使用。

如果您熟悉名称空间配置一章中讨论的主题,您可以通过添加 < remember-me > 元素来启用 remember-me 身份验证:

...
<remember-me key="myAppKey"/>
</http>

UserDetailsService 通常会被自动选择。如果应用程序上下文中有多个属性,则需要指定应该将哪个属性与 user-service-ref 属性一起使用,其中的值是 UserDetailsService bean 的名称。

持久令牌方法(Persistent Token Approach)

这种方法是基于 http://jaspan.com/improved_persistent_login_cookie_best_practice 的文章,只是做了一些小的修改(从本质上讲,用户名并不包含在 cookie 中,以防止无意中暴露一个有效的登录名)。为了在名称空间配置中使用这种方法,你需要提供一个数据源引用:

<http>
...
<remember-me data-source-ref="someDataSource"/>
</http>

数据库应该包含一个 persistent _ logins 表,该表使用以下 SQL (或等效)创建:

create table persistent_logins (username varchar(64) not null,
								series varchar(64) primary key,
								token varchar(64) not null,
								last_used timestamp not null)

Remember-Me 接口和实现

Remember-me 与 UsernamePasswordAuthenticationFilter 一起使用,并通过 AbstractAuthenticationProcessingFilter 超类中的钩子实现。它也在 BasicAuthenticationFilter 中使用。钩子会在适当的时候调用一个具体的记忆服务。接口是这样的:

Authentication autoLogin(HttpServletRequest request, HttpServletResponse response);

void loginFail(HttpServletRequest request, HttpServletResponse response);

void loginSuccess(HttpServletRequest request, HttpServletResponse response,
	Authentication successfulAuthentication);

请参考 Javadoc 以获得关于这些方法做什么的更全面的讨论,尽管在这个阶段要注意 AbstractAuthenticationProcessingFilter 只调用 loginFail ()和 loginSuccess ()方法。只要 SecurityContextHolder 不包含身份验证,RememberMeAuthenticationFilter 就会调用 autoLogin ()方法。因此,该接口为基础 remember-me 实现提供了与认证相关事件的充分通知,并在候选 web 请求可能包含 cookie 并希望被记住时委托实现。这种设计允许任何数量的记住我的实现策略。我们已经在上面看到 Spring Security 提供了两个实现。我们将依次看看这些。

TokenBasedRememberMeServices

此实现支持简单的基于散列的令牌方法中描述的更简单的方法。TokenBasedRememberMeServices生成一个RememberMeAuthenticationToken,该令牌RememberMeAuthenticationProvider处理。此身份验证提供程序和TokenBasedRememberMeServices之间共享密钥。此外,TokenBasedRememberMeServices需要UserDetailsService,它可以从该服务检索用户名和密码以进行签名比较,并生成RememberMeAuthenticationToken以包含正确的rantedAuthoritys。
应用程序应该提供某种注销命令,如果用户请求注销命令,该命令将使cookie无效。TokenBasedRememberMeServices还实现了Spring Security的LogoutHandler接口,因此可以与LogoutFilter一起使用,以自动清除cookie。应用程序上下文中启用Remory-Me服务所需的Bean如下所示:

<bean id="rememberMeFilter" class=
"org.springframework.security.web.authentication.rememberme.RememberMeAuthenticationFilter">
<property name="rememberMeServices" ref="rememberMeServices"/>
<property name="authenticationManager" ref="theAuthenticationManager" />
</bean>

<bean id="rememberMeServices" class=
"org.springframework.security.web.authentication.rememberme.TokenBasedRememberMeServices">
<property name="userDetailsService" ref="myUserDetailsService"/>
<property name="key" value="springRocks"/>
</bean>

<bean id="rememberMeAuthenticationProvider" class=
"org.springframework.security.authentication.RememberMeAuthenticationProvider">
<property name="key" value="springRocks"/>
</bean>

不要忘记将你的 RememberMeServices 实现添加到你的 UsernamePasswordAuthenticationFilter.setRememberMeServices ()属性中,将 RememberMeAuthenticationProvider 包含在你的 AuthenticationManager.setProviders ()列表中,并将 RememberMeAuthenticationFilter 添加到你的 FilterChainProxy 中(通常在你的 UsernamePasswordAuthenticationFilter 之后)。

PersistentTokenBasedRememberMeServices

这个类可以像 TokenBasedRememberMeServices 一样使用,但是它还需要配置一个 PersistentTokenRepository 来存储这些令牌。有两种标准实现。

  • InMemoryTokenRepositoryImpl 基于内存的 Token Repository,只用于测试
  • JdbcTokenRepositoryImpl 基于数据库的 Token Repository
    上面在 持久令牌方法 中描述了数据库模式

参考 SpringSecurity 官方文档

Spring Security提供了Remember-me功能来让用户在下次访问时无需重新登录。要启用Remember-me功能,可以按照以下步骤进行配置: 1. 在Spring Security配置文件中启用Remember-me功能,例如: ``` http .rememberMe() .key("remember-me-key") .rememberMeParameter("remember-me") .tokenValiditySeconds(86400) .userDetailsService(userDetailsService); ``` 其中,key是用来加密Remember-me cookie的密钥,rememberMeParameter是用来接收Remember-me cookie的请求参数,tokenValiditySeconds是Remember-me cookie的有效期,userDetailsService是用来根据用户名获取用户信息的服务。 2. 在登录页面中添加Remember-me的复选框,例如: ``` <input type="checkbox" name="remember-me" value="true" /> Remember me ``` 3. 在登录成功后生成Remember-me cookie,例如: ``` @RequestMapping(value = "/login", method = RequestMethod.POST) public String login(@RequestParam("username") String username, @RequestParam("password") String password, @RequestParam(value = "remember-me", required = false) boolean rememberMe, HttpServletResponse response) { // 验证用户名和密码 // ... // 生成Remember-me cookie if (rememberMe) { TokenBasedRememberMeServices rememberMeServices = new TokenBasedRememberMeServices("remember-me-key", userDetailsService); rememberMeServices.setTokenValiditySeconds(86400); rememberMeServices.setAlwaysRemember(true); rememberMeServices.loginSuccess(request, response, authentication); } // ... } ``` 其中,如果用户勾选了Remember-me复选框,则调用TokenBasedRememberMeServices的loginSuccess方法生成Remember-me cookie。 4. 在下次访问时验证Remember-me cookie,例如: ``` http .csrf().disable() .authorizeRequests() .antMatchers("/admin/**").hasRole("ADMIN") .antMatchers("/user/**").hasAnyRole("USER", "ADMIN") .anyRequest().authenticated() .and() .formLogin() .loginPage("/login") .permitAll() .and() .rememberMe() .key("remember-me-key") .rememberMeParameter("remember-me") .tokenValiditySeconds(86400) .userDetailsService(userDetailsService); ``` 其中,Remember-me cookie会在每次请求时被自动验证,如果验证通过,则用户会被认为已经登录。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值