Spring Security4实例(Java config 版) —— Remember-Me
本文源码请看这里
相关文章:
Spring Security4实例(Java config版)——ajax登录,自定义验证
Spring Security提供了两种remember-me的实现,一种是简单的使用加密来保证基于cookie的token的安全,另一种是通过数据库或其它持久化存储机制来保存生成的token。
一、简单Hash-Based Token方式
首先在登录页login.html上添加一个CheckBox控件:
<tr> <td>rememberMe:</td> <td><input type="checkbox" name='remember-me' id='rememberMe' /></td> </tr>配置WebSecurityConfig类中的configure(HttpSecurity http)方法,开启remember me功能:
```
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests().antMatchers("/", "/login/**").permitAll()
// user权限可以访问的请求
.antMatchers("/security/user").hasRole("user")
// admin权限可以访问的请求
.antMatchers("/security/admin").hasRole("admin")
//SpEL表达式:需要拥有user权限,且进行了完全认证
.antMatchers("/user/account").access("hasRole('user') and isFullyAuthenticated()")
// 其他地址的访问均需验证权限(需要登录)
.anyRequest().authenticated().and()
// 添加验证码验证
.addFilterAt(myUsernamePasswordAuthenticationFilter(), UsernamePasswordAuthenticationFilter.class).exceptionHandling()
.authenticationEntryPoint(new LoginUrlAuthenticationEntryPoint("/login_page")).and()
// 指定登录页面的请求路径
.formLogin().loginPage("/login_page")
// 登陆处理路径
.loginProcessingUrl("/login").permitAll().and()
//退出请求的默认路径为logout,下面改为signout, 成功退出登录后的url可以用logoutSuccessUrl设置
.logout().logoutUrl("/signout").logoutSuccessUrl("/login_page").permitAll().and()
// 开启rememberMe,设置一个私钥专供testall项目使用,注意与下面TokenBasedRememberMeServices的key保持一致
.rememberMe().key("testallKey").and()
// 关闭csrf
.csrf().disable();
}
倒数第二行代码就是啦,还可以用tokenValiditySeconds设置一个cookie的过期时间,单位为秒;
如果没有扩展UsernamePasswordAuthenticationFilter类,定制自己的Filte(比如为了加个验证码),上面的配置应该就可以了。否则还得继续配置:
---
3. 设置TokenBasedRememberMeServices Bean,可以在里面进行一些remember me的配置:
@Bean
public TokenBasedRememberMeServices tokenBasedRememberMeServices() {
TokenBasedRememberMeServices tbrms = new TokenBasedRememberMeServices("testallKey", userDetailsServiceImpl());
// 设置cookie过期时间为2天
tbrms.setTokenValiditySeconds(60 * 60 * 24 * 2);
// 设置checkbox的参数名为rememberMe(默认为remember-me),注意如果是ajax请求,参数名不是checkbox的name而是在ajax的data里
tbrms.setParameter("rememberMe");
return tbrms;
}
注意:这时候在步骤2里设置过期时间等配置均无效,但是key("testallKey")还是要设置的。
4. 在MyUsernamePasswordAuthenticationFilter Bean中设置RememberMeServices为上面的service,还是倒数第二行
@Bean
public MyUsernamePasswordAuthenticationFilter myUsernamePasswordAuthenticationFilter() throws Exception {
MyUsernamePasswordAuthenticationFilter myFilter = new MyUsernamePasswordAuthenticationFilter();
myFilter.setAuthenticationManager(authenticationManagerBean());
myFilter.setAuthenticationSuccessHandler(authenticationSuccessHandler());
myFilter.setAuthenticationFailureHandler(authenticationFailureHandler());
myFilter.setRememberMeServices(tokenBasedRememberMeServices());
return myFilter;
}
这样就可以了,下面是部分说明
---
- 当用户选择了记住我成功登录后,Spring Security将会生成一个cookie发送给客户端浏览器。cookie值由如下方式组成:
base64(username+":"+expirationTime+":"+md5Hex(username+":"+expirationTime+":"+password+":"+key))
Øusername:登录的用户名。
Øpassword:登录的密码。
ØexpirationTime:token失效的日期和时间,以毫秒表示。
Økey:用来防止修改token的一个key。
这样用来实现Remember-Me功能的token只能在指定的时间内有效,且必须保证token中所包含的username、password和key没有被改变才行。需要注意的是,这样做其实是存在安全隐患的,那就是在用户获取到实现记住我功能的token后,任何用户都可以在该token过期之前通过该token进行自动登录。如果用户发现自己的token被盗用了,那么他可以通过改变自己的登录密码来立即使其所有的记住我token失效。如果希望我们的应用能够更安全一点,可以使用接下来要介绍的持久化token方式,或者不使用Remember-Me功能,因为Remember-Me功能总是有点不安全的。
- 下面的图表阐述了校验remember me cookie过程中涉及到的不同组件:

- [TokenBasedRememberMeServices](http://docs.spring.io/spring-security/site/docs/4.2.3.RELEASE/reference/htmlsingle/#tokenbasedremembermeservices)官方文档的说明
> This implementation supports the simpler approach described in Section 17.2, “Simple Hash-Based Token Approach”. TokenBasedRememberMeServices generates a RememberMeAuthenticationToken, which is processed by RememberMeAuthenticationProvider. A key is shared between this authentication provider and the TokenBasedRememberMeServices. In addition, TokenBasedRememberMeServices requires A UserDetailsService from which it can retrieve the username and password for signature comparison purposes...
The beans required in an application context to enable remember-me services are as follows:
> Don’t forget to add your RememberMeServices implementation to your UsernamePasswordAuthenticationFilter.setRememberMeServices() property, include the RememberMeAuthenticationProvider in your AuthenticationManager.setProviders() list, and add RememberMeAuthenticationFilter into your FilterChainProxy (typically immediately after your UsernamePasswordAuthenticationFilter).
大致翻译如下:
这个实现类就对应于17.2章节描述的那个“Simple Hash-Based Token Approach”(就是上面的简单Hash-Based Token方式)。TokenBasedRememberMeServices(以下用“它”代替) 生成了一个RememberMeAuthenticationToken(它的抽象父类AbstractRememberMeServices中的方法createSuccessfulAuthentication实现的),以供RememberMeAuthenticationProvider处理。一个key被这个AuthenticationProvider和它共享使用。此外,它还需要一个UserDetailsService 用来获取用户名和密码进行签名对比...
这个bean需要进行如下配置:
见上xml
最后别忘了,需要配置UsernamePasswordAuthenticationFilter的rememberMeServices为我们定义好的TokenBasedRememberMeServices,把RememberMeAuthenticationProvider加入AuthenticationManager的providers列表,并添加RememberMeAuthenticationFilter和UsernamePasswordAuthenticationFilter到FilterChainProxy。(通常紧接着放在UsernamePasswordAuthenticationFilter后面)。
所以上面的配置好像跟这里描述的不太一样(不过效果倒是一样),接下来按照官方文档描述的修改一下配置(上面第1步不变,从第二步开启remember me配置开始修改):
---
2. 注释掉rememberMe(),在myUsernamePasswordAuthenticationFilter后添加rememberMeAuthenticationFilter
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests().antMatchers("/", "/login/**").permitAll()
// user权限可以访问的请求
.antMatchers("/security/user").hasRole("user")
// admin权限可以访问的请求
.antMatchers("/security/admin").hasRole("admin")
// SpEL表达式:需要拥有user权限,且进行了完全认证
.antMatchers("/user/account").access("hasRole('user') and isFullyAuthenticated()")
// 其他地址的访问均需验证权限(需要登录)
.anyRequest().authenticated().and()
// 添加验证码验证
.addFilterAt(myUsernamePasswordAuthenticationFilter(), UsernamePasswordAuthenticationFilter.class).exceptionHandling()
.authenticationEntryPoint(new LoginUrlAuthenticationEntryPoint("/login_page")).and()
.addFilterAt(rememberMeAuthenticationFilter(),RememberMeAuthenticationFilter.class)
// 指定登录页面的请求路径
.formLogin().loginPage("/login_page")
// 登陆处理路径
.loginProcessingUrl("/login").permitAll().and()
// 退出请求的默认路径为logout,下面改为signout,
// 成功退出登录后的url可以用logoutSuccessUrl设置
.logout().logoutUrl("/signout").logoutSuccessUrl("/login_page").permitAll().and()
// 开启rememberMe,设置一个私钥专供testall项目使用,注意与下面TokenBasedRememberMeServices的key保持一致
//.rememberMe().key("testallKey").and()
// 关闭csrf
.csrf().disable();
}
3. 上面的3、4步还是需要的,此外还要加上之前没有配置的rememberMeAuthenticationProvider和rememberMeAuthenticationFilter,下面就直接把相关代码都贴上了
@Bean
public MyUsernamePasswordAuthenticationFilter myUsernamePasswordAuthenticationFilter() throws Exception {
MyUsernamePasswordAuthenticationFilter myFilter = new MyUsernamePasswordAuthenticationFilter();
myFilter.setAuthenticationManager(authenticationManagerBean());
myFilter.setAuthenticationSuccessHandler(authenticationSuccessHandler());
myFilter.setAuthenticationFailureHandler(authenticationFailureHandler());
myFilter.setRememberMeServices(tokenBasedRememberMeServices());
return myFilter;
}
@Bean
public TokenBasedRememberMeServices tokenBasedRememberMeServices() {
TokenBasedRememberMeServices tbrms = new TokenBasedRememberMeServices("testallKey", userDetailsServiceImpl());
// 设置cookie过期时间为2天
tbrms.setTokenValiditySeconds(60 * 60 * 24 * 2);
// 设置checkbox的参数名为rememberMe(默认为remember-me),注意如果是ajax请求,参数名不是checkbox的name而是在ajax的data里
tbrms.setParameter("rememberMe");
return tbrms;
}
@Bean
public RememberMeAuthenticationProvider rememberMeAuthenticationProvider() {
RememberMeAuthenticationProvider rmap = new RememberMeAuthenticationProvider("testallKey");
return rmap;
}
@Bean
public RememberMeAuthenticationFilter rememberMeAuthenticationFilter() throws Exception {
RememberMeAuthenticationFilter myFilter = new RememberMeAuthenticationFilter(authenticationManagerBean(), tokenBasedRememberMeServices());
return myFilter;
}
```
然后尴尬来了,remember是好使了,但是退出不清除cookie了,最后只找到TokenBasedRememberMeServices的logoutHandler没有被加到logoutFilter里(参考),至于为什么(或者哪里配置的不对)还不清楚,有知道的可以告知下,暂时还是使用之前的那种配置方式吧。
二、持久化 Token方式
待更新
Spring Security4实例(Java config 版) —— Remember-Me的更多相关文章
- Spring Security4实例(Java config版)——ajax登录,自定义验证
本文源码请看这里 相关文章: Spring Security4实例(Java config 版) -- Remember-Me 首先添加起步依赖(如果不是springboot项目,自行切换为Sprin ...
- Spring MVC 的 Java Config ( 非 XML ) 配置方式
索引: 开源Spring解决方案--lm.solution 参看代码 GitHub: solution/pom.xml web/pom.xml web.xml WebInitializer.java ...
- spring+mybati java config配置引起的bean相互引用日志报警告问题
摘要: Error creating bean with name 'XXX': Requested bean is currently in creation: Is there an unreso ...
- 纯java config配置Spring MVC实例
1.首先创建一个Maven工程,项目结构如下: pom.xml添加Spring和servlet依赖,配置如下 <project xmlns="http://maven.apache.o ...
- Spring MVC4 + Spring Security4 + Hibernate实例
http://www.yiibai.com/spring-security/spring-mvc-4-and-spring-security-4-integration-example.html 在这 ...
- spring、springmvc和mybatis整合(java config方式)
之前项目中使用ssm框架大多是基于xml的方式,spring3.0以后就提供java config的模式来构建项目,并且也推荐使用这种方式,自从接触过springboot后,深深感受到这种纯java配 ...
- spring java config 初探
Java Config 注解 spring java config作为同xml配置形式的另一种表达形式,使用的场景越来越多,在新版本的spring boot中 大量使用,今天我们来看下用到的主要注解有 ...
- Spring 4 and MyBatis Java Config
TL;DR With the Java Config enhancements in Spring 4, you no longer need xml to configure MyBatis for ...
- Spring知识点回顾(01)Java Config
Spring知识点回顾(01) 一.Java Config 1.服务和服务注入 2.Java 注解 :功能更强一些 3.测试验证 二.注解注入 1.服务和服务注入 2.配置加载 3.测试验证 三.总结 ...
随机推荐
- Include promo/activity effect into the prediction (extended ARIMA model with R)
I want to consider an approach of forecasting I really like and frequently use. It allows to include ...
- iOS 原生模块 给 Javascript(ReactNative) 发送事件 (通知监听)
官方中文文档是这样描述的: 就给我们这几句话 就打发我们了. 按照上面的写法,根本不知道 - (void)calendarEventReminderReceived:(NSNotificatio ...
- 使用React改版网站后的一些感想
文章转载:http://www.jianshu.com/p/8f74cfb146f7 网站是毕业设计的作品,开发这个网站的目的主要用于记录一些笔记,以及聚合一些资讯信息,也算自己在网络世界中的一块静地 ...
- cpp(第八章)
1. #include <iostream> inline int add(int &n) { n= n+; ; } int main() { using namespace st ...
- solr5Ik分词2
<!--IK分词器--><fieldType name="text_ik" class="solr.TextField"><ana ...
- solr学习笔记section2-solr单机(节点)简单的core操作
在上一节中我们已经成功部署和运行了一个solr应用,那么我们就可以通过这个正在运行的solr来创建一些文档,并进行搜索. 首先介绍一下core这个概念,core在solr中类似与关系型数据库中一张表的 ...
- DOM事件类型总结大全
unload:事件在用户退出页面时发生 window.onload = function(){ return "页面关闭!"; }; onblur:失去焦点发生变化 window. ...
- 波浪号和Hyphen扩展
Bash将波浪号作为路径扩展符 $echo ~ //扩展为当前用户主目录的全路径名/home/user $echo ~user //扩展为用户user的主目录/home/user $echo ~+ / ...
- 一个比较完善的httpWebRequest 封装,适合网络爬取及暴力破解
大家在模拟http请求的时候,对保持长连接及cookies,http头部信息等了解的不是那么深入.在各种网络请求过程中,发送N种问题. 可能问题如下: 1)登录成功后session保持 2)保证所有c ...
- 用netsh wlan命令行解决“Win10下WLAN不自动登陆”问题
系统崩溃了,找了一个版本Windows 10重装后,发现进入系统后不会自动连接自己家的Wifi,每次都要手动点"登录",烦不胜烦. 于是百度.Google一起上,找解决方案,然后所 ...