JavaWeb-SpringSecurity记住我功能
系列博文
项目已上传至guthub 传送门
JavaWeb-SpringSecurity初认识 传送门
JavaWeb-SpringSecurity在数据库中查询登陆用户 传送门
JavaWeb-SpringSecurity自定义登陆页面 传送门
JavaWeb-SpringSecurity实现需求-判断请求是否以html结尾 传送门
JavaWeb-SpringSecurity自定义登陆配置 传送门
JavaWeb-SpringSecurity图片验证ImageCode 传送门
JavaWeb-SpringSecurity记住我功能 传送门
JavaWeb-SpringSecurity使用短信验证码登陆 传送门
在login.html中添加一个复选框,表示"记住我"功能【注意:<input>标签的name一定是remember-me】
<form action="/loginPage" method="post"> 用户名:
<input type="text" name="username">
<br> 密码:
<input type="password" name="password">
<br> 图片验证码:
<input type="text" name="imageCode">
<img src="/code/image">
<br> <input name="remember-me" type="checkbox" value="true">
记住我 <input type="submit"> </form>
在config层SecurityConfig.java中添加persistentTokenRepository()方法,用来在server层操作数据库
@Autowired
private DataSource dataSource; //负责操作数据库
public PersistentTokenRepository persistentTokenRepository()
{
JdbcTokenRepositoryImpl tokenRepository = new JdbcTokenRepositoryImpl();
tokenRepository.setDataSource(dataSource);
return tokenRepository;
}
JdbcTokenRepositoryImpl要操作数据库,得在数据库中存在操作存储用户信息token数据库表,使用JdbcTokenRepositoryImpl接口中提供创建数据库语句
/** Default SQL for creating the database table to store the tokens */
public static final String CREATE_TABLE_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)";
/** The default SQL used by the <tt>getTokenBySeries</tt> query */
public static final String DEF_TOKEN_BY_SERIES_SQL = "select username,series,token,last_used from persistent_logins where series = ?";
/** The default SQL used by <tt>createNewToken</tt> */
public static final String DEF_INSERT_TOKEN_SQL = "insert into persistent_logins (username, series, token, last_used) values(?,?,?,?)";
/** The default SQL used by <tt>updateToken</tt> */
public static final String DEF_UPDATE_TOKEN_SQL = "update persistent_logins set token = ?, last_used = ? where series = ?";
/** The default SQL used by <tt>removeUserTokens</tt> */
public static final String DEF_REMOVE_USER_TOKENS_SQL = "delete from persistent_logins where username = ?";
create table persistent_logins (username varchar(64) not null, series varchar(64) primary key, token varchar(64) not null, last_used timestamp not null)
gary.sql
在SecurityConfig.java实现"记住我"功能
@Autowired
private DataSource dataSource; //负责操作数据库
public PersistentTokenRepository persistentTokenRepository()
{
JdbcTokenRepositoryImpl tokenRepository = new JdbcTokenRepositoryImpl();
tokenRepository.setDataSource(dataSource);
return tokenRepository;
} @Autowired
public UserDetailsService userDetailService; protected void configure(HttpSecurity http) throws Exception{ //声明我们自己写的过滤器
ValidateCodeFilter validateCodeFilter = new ValidateCodeFilter();
//给过滤器赋值
validateCodeFilter.setAuthenticationFailureHandler(loginFailureHandler);
validateCodeFilter.setGarySecurityProperties(garySecurityProperties);
validateCodeFilter.afterPropertiesSet(); //表单验证(身份认证)
http.addFilterBefore(validateCodeFilter, UsernamePasswordAuthenticationFilter.class)
.formLogin()
//自定义登陆页面
.loginPage("/require")
//如果URL为loginPage,则用SpringSecurity中自带的过滤器去处理该请求
.loginProcessingUrl("/loginPage")
//配置登陆成功调用loginSuccessHandler
.successHandler(loginSuccessHandler)
//配置登陆失败调用loginFailureHandler
.failureHandler(loginFailureHandler)
//记住我功能
.and()
.rememberMe()
//配置persistentTokenRepository
.tokenRepository(persistentTokenRepository())
//配置userDetailsService
.userDetailsService(userDetailService)
.and()
//请求授权
.authorizeRequests()
//在访问我们的URL时,我们是不需要省份认证,可以立即访问
.antMatchers("/login.html","/require","/code/image").permitAll()
//所有请求都被拦截,跳转到(/login请求中)
.anyRequest()
//都需要我们身份认证
.authenticated()
//SpringSecurity保护机制
.and().csrf().disable();
}
package com.Gary.GaryRESTful.config; import javax.sql.DataSource; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.security.web.authentication.rememberme.JdbcTokenRepositoryImpl;
import org.springframework.security.web.authentication.rememberme.PersistentTokenRepository; import com.Gary.GaryRESTful.filter.ValidateCodeFilter;
import com.Gary.GaryRESTful.handler.LoginFailureHandler;
import com.Gary.GaryRESTful.handler.LoginSuccessHandler;
import com.Gary.GaryRESTful.properties.GarySecurityProperties; //Web应用安全适配器
@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter{ //告诉SpringSecurity密码用什么加密的
@Bean
public PasswordEncoder passwordEncoder()
{
return new BCryptPasswordEncoder();
} @Autowired
private LoginSuccessHandler loginSuccessHandler; @Autowired
private LoginFailureHandler loginFailureHandler; @Autowired
private GarySecurityProperties garySecurityProperties; @Autowired
private DataSource dataSource; //负责操作数据库
public PersistentTokenRepository persistentTokenRepository()
{
JdbcTokenRepositoryImpl tokenRepository = new JdbcTokenRepositoryImpl();
tokenRepository.setDataSource(dataSource);
return tokenRepository;
} @Autowired
public UserDetailsService userDetailService; protected void configure(HttpSecurity http) throws Exception{ //声明我们自己写的过滤器
ValidateCodeFilter validateCodeFilter = new ValidateCodeFilter();
//给过滤器赋值
validateCodeFilter.setAuthenticationFailureHandler(loginFailureHandler);
validateCodeFilter.setGarySecurityProperties(garySecurityProperties);
validateCodeFilter.afterPropertiesSet(); //表单验证(身份认证)
http.addFilterBefore(validateCodeFilter, UsernamePasswordAuthenticationFilter.class)
.formLogin()
//自定义登陆页面
.loginPage("/require")
//如果URL为loginPage,则用SpringSecurity中自带的过滤器去处理该请求
.loginProcessingUrl("/loginPage")
//配置登陆成功调用loginSuccessHandler
.successHandler(loginSuccessHandler)
//配置登陆失败调用loginFailureHandler
.failureHandler(loginFailureHandler)
//记住我功能
.and()
.rememberMe()
//配置persistentTokenRepository
.tokenRepository(persistentTokenRepository())
//配置userDetailsService
.userDetailsService(userDetailService)
.and()
//请求授权
.authorizeRequests()
//在访问我们的URL时,我们是不需要省份认证,可以立即访问
.antMatchers("/login.html","/require","/code/image").permitAll()
//所有请求都被拦截,跳转到(/login请求中)
.anyRequest()
//都需要我们身份认证
.authenticated()
//SpringSecurity保护机制
.and().csrf().disable();
} }
SecurityConfig.java
为防止一直记住用户,在GaryRESTful.properties中的GarySecurityProperties()方法下,配置token过期时间
//LoginType登陆的方式,默认为JSON(restful设计风格)
private LoginType loginType = LoginType.JSON; private ValidateCodeProperties code = new ValidateCodeProperties(); private int rememberMeSeconds = 60*60; //getter()、setter()
在application.properties中配置Token过期时间
#Token过期时间
gary.security.rememberMeSeconds = 3600
在SecurityConfig.java下的configure()方法中配置过期秒数
protected void configure(HttpSecurity http) throws Exception{ //声明我们自己写的过滤器
ValidateCodeFilter validateCodeFilter = new ValidateCodeFilter();
//给过滤器赋值
validateCodeFilter.setAuthenticationFailureHandler(loginFailureHandler);
validateCodeFilter.setGarySecurityProperties(garySecurityProperties);
validateCodeFilter.afterPropertiesSet(); //表单验证(身份认证)
http.addFilterBefore(validateCodeFilter, UsernamePasswordAuthenticationFilter.class)
.formLogin()
//自定义登陆页面
.loginPage("/require")
//如果URL为loginPage,则用SpringSecurity中自带的过滤器去处理该请求
.loginProcessingUrl("/loginPage")
//配置登陆成功调用loginSuccessHandler
.successHandler(loginSuccessHandler)
//配置登陆失败调用loginFailureHandler
.failureHandler(loginFailureHandler)
//记住我功能
.and()
.rememberMe()
//配置persistentTokenRepository
.tokenRepository(persistentTokenRepository())
//配置过期秒数
.tokenValiditySeconds(garySecurityProperties.getRememberMeSeconds())
//配置userDetailsService
.userDetailsService(userDetailService)
.and()
//请求授权
.authorizeRequests()
//在访问我们的URL时,我们是不需要省份认证,可以立即访问
.antMatchers("/login.html","/require","/code/image").permitAll()
//所有请求都被拦截,跳转到(/login请求中)
.anyRequest()
//都需要我们身份认证
.authenticated()
//SpringSecurity保护机制
.and().csrf().disable();
}
package com.Gary.GaryRESTful.config; import javax.sql.DataSource; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.security.web.authentication.rememberme.JdbcTokenRepositoryImpl;
import org.springframework.security.web.authentication.rememberme.PersistentTokenRepository; import com.Gary.GaryRESTful.filter.ValidateCodeFilter;
import com.Gary.GaryRESTful.handler.LoginFailureHandler;
import com.Gary.GaryRESTful.handler.LoginSuccessHandler;
import com.Gary.GaryRESTful.properties.GarySecurityProperties; //Web应用安全适配器
@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter{ //告诉SpringSecurity密码用什么加密的
@Bean
public PasswordEncoder passwordEncoder()
{
return new BCryptPasswordEncoder();
} @Autowired
private LoginSuccessHandler loginSuccessHandler; @Autowired
private LoginFailureHandler loginFailureHandler; @Autowired
private GarySecurityProperties garySecurityProperties; @Autowired
private DataSource dataSource; //负责操作数据库
public PersistentTokenRepository persistentTokenRepository()
{
JdbcTokenRepositoryImpl tokenRepository = new JdbcTokenRepositoryImpl();
tokenRepository.setDataSource(dataSource);
return tokenRepository;
} @Autowired
public UserDetailsService userDetailService; protected void configure(HttpSecurity http) throws Exception{ //声明我们自己写的过滤器
ValidateCodeFilter validateCodeFilter = new ValidateCodeFilter();
//给过滤器赋值
validateCodeFilter.setAuthenticationFailureHandler(loginFailureHandler);
validateCodeFilter.setGarySecurityProperties(garySecurityProperties);
validateCodeFilter.afterPropertiesSet(); //表单验证(身份认证)
http.addFilterBefore(validateCodeFilter, UsernamePasswordAuthenticationFilter.class)
.formLogin()
//自定义登陆页面
.loginPage("/require")
//如果URL为loginPage,则用SpringSecurity中自带的过滤器去处理该请求
.loginProcessingUrl("/loginPage")
//配置登陆成功调用loginSuccessHandler
.successHandler(loginSuccessHandler)
//配置登陆失败调用loginFailureHandler
.failureHandler(loginFailureHandler)
//记住我功能
.and()
.rememberMe()
//配置persistentTokenRepository
.tokenRepository(persistentTokenRepository())
//配置过期秒数
.tokenValiditySeconds(garySecurityProperties.getRememberMeSeconds())
//配置userDetailsService
.userDetailsService(userDetailService)
.and()
//请求授权
.authorizeRequests()
//在访问我们的URL时,我们是不需要省份认证,可以立即访问
.antMatchers("/login.html","/require","/code/image").permitAll()
//所有请求都被拦截,跳转到(/login请求中)
.anyRequest()
//都需要我们身份认证
.authenticated()
//SpringSecurity保护机制
.and().csrf().disable();
} }
SecurityConfig.java
测试:每次用户勾选了了记住我,在persistent_logins表中就会多处一条token记录【如果用户不勾选记住我,persistent_logins表中不会多处token记录】
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body> <h1>Gary登陆页面</h1>
<form action="/loginPage" method="post"> 用户名:
<input type="text" name="username">
<br> 密码:
<input type="password" name="password">
<br> 图片验证码:
<input type="text" name="imageCode">
<img src="/code/image">
<br> <input name="remember-me" type="checkbox" value="true">
记住我 <input type="submit"> </form> </body>
</html>
login.html
#datasource
spring.datasource.url=jdbc:mysql:///springsecurity?serverTimezone=UTC&characterEncoding=utf-8
spring.datasource.username=root
spring.datasource.password=123456
spring.datasource.dricer-class-name=com.mysql.jdbc.Driver #jpa
#打印出数据库语句
spring.jpa.show-sql=true
#更新数据库表
spring.jpa.hibernate.ddl-auto=update #配置登陆方式
gary.security.loginType = JSON server.port=8081 #验证码长度
gary.security.code.image.length = 6
#验证码图片的长
gary.security.code.image.width = 100 #配置哪些需要我们验证码的Filter
gary.security.code.image.url = /user,/user/* #Token过期时间
gary.security.rememberMeSeconds = 3600
application.properties
package com.Gary.GaryRESTful.properties; import org.springframework.boot.context.properties.ConfigurationProperties; @ConfigurationProperties(prefix = "gary.security")
public class GarySecurityProperties { //LoginType登陆的方式,默认为JSON(restful设计风格)
private LoginType loginType = LoginType.JSON; private ValidateCodeProperties code = new ValidateCodeProperties(); private int rememberMeSeconds = 60*60; public int getRememberMeSeconds() {
return rememberMeSeconds;
} public void setRememberMeSeconds(int rememberMeSeconds) {
this.rememberMeSeconds = rememberMeSeconds;
} public ValidateCodeProperties getCode() {
return code;
} public void setCode(ValidateCodeProperties code) {
this.code = code;
} public LoginType getLoginType() {
return loginType;
} public void setLoginType(LoginType loginType) {
this.loginType = loginType;
} }
GarySecurityProperties.java
package com.Gary.GaryRESTful.config; import javax.sql.DataSource; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.security.web.authentication.rememberme.JdbcTokenRepositoryImpl;
import org.springframework.security.web.authentication.rememberme.PersistentTokenRepository; import com.Gary.GaryRESTful.filter.ValidateCodeFilter;
import com.Gary.GaryRESTful.handler.LoginFailureHandler;
import com.Gary.GaryRESTful.handler.LoginSuccessHandler;
import com.Gary.GaryRESTful.properties.GarySecurityProperties; //Web应用安全适配器
@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter{ //告诉SpringSecurity密码用什么加密的
@Bean
public PasswordEncoder passwordEncoder()
{
return new BCryptPasswordEncoder();
} @Autowired
private LoginSuccessHandler loginSuccessHandler; @Autowired
private LoginFailureHandler loginFailureHandler; @Autowired
private GarySecurityProperties garySecurityProperties; @Autowired
private DataSource dataSource; //负责操作数据库
public PersistentTokenRepository persistentTokenRepository()
{
JdbcTokenRepositoryImpl tokenRepository = new JdbcTokenRepositoryImpl();
tokenRepository.setDataSource(dataSource);
return tokenRepository;
} @Autowired
public UserDetailsService userDetailService; protected void configure(HttpSecurity http) throws Exception{ //声明我们自己写的过滤器
ValidateCodeFilter validateCodeFilter = new ValidateCodeFilter();
//给过滤器赋值
validateCodeFilter.setAuthenticationFailureHandler(loginFailureHandler);
validateCodeFilter.setGarySecurityProperties(garySecurityProperties);
validateCodeFilter.afterPropertiesSet(); //表单验证(身份认证)
http.addFilterBefore(validateCodeFilter, UsernamePasswordAuthenticationFilter.class)
.formLogin()
//自定义登陆页面
.loginPage("/require")
//如果URL为loginPage,则用SpringSecurity中自带的过滤器去处理该请求
.loginProcessingUrl("/loginPage")
//配置登陆成功调用loginSuccessHandler
.successHandler(loginSuccessHandler)
//配置登陆失败调用loginFailureHandler
.failureHandler(loginFailureHandler)
//记住我功能
.and()
.rememberMe()
//配置persistentTokenRepository
.tokenRepository(persistentTokenRepository())
//配置过期秒数
.tokenValiditySeconds(garySecurityProperties.getRememberMeSeconds())
//配置userDetailsService
.userDetailsService(userDetailService)
.and()
//请求授权
.authorizeRequests()
//在访问我们的URL时,我们是不需要省份认证,可以立即访问
.antMatchers("/login.html","/require","/code/image").permitAll()
//所有请求都被拦截,跳转到(/login请求中)
.anyRequest()
//都需要我们身份认证
.authenticated()
//SpringSecurity保护机制
.and().csrf().disable();
} }
SecurityConfig.java
JavaWeb-SpringSecurity记住我功能的更多相关文章
- SpringSecurity(2)---记住我功能实现
SpringSecurity(2)---记住我功能实现 上一篇博客实现了认证+授权的基本功能,这里在这个基础上,添加一个 记住我的功能. 上一篇博客地址:SpringSecurity(1)---认证+ ...
- SpringBoot + Spring Security 学习笔记(四)记住我功能实现
记住我功能的基本原理 当用户登录发起认证请求时,会通过UsernamePasswordAuthenticationFilter进行用户认证,认证成功之后,SpringSecurity 调用前期配置好的 ...
- java实现记住密码功能(利用cookie)
<br> <input type="text" id="userName" name="userName" value=& ...
- 通过sharedpreferences实现记住密码功能
通过sharedpreferences实现记住密码功能
- jquery.cookie.js 操作cookie实现记住密码功能的实现代码
jquery.cookie.js操作cookie实现记住密码功能,很简单很强大,喜欢的朋友可以参考下. 复制代码代码如下: //初始化页面时验证是否记住了密码 $(document).ready( ...
- cookie记住密码功能
很多门户网站都提供了记住密码功能,虽然现在的浏览器都已经提供了相应的记住密码功能 效果就是你每次进入登录页面后就不需要再进行用户名和密码的输入: 记住密码功能基本都是使用cookie来进行实现的,因此 ...
- 【原创】js中利用cookie实现记住密码功能
在登录界面添加记住密码功能,我首先想到的是在java后台中调用cookie存放账号密码,大致如下: HttpServletRequest request HttpServletResponse res ...
- android: SharedPreferences实现记住密码功能
既然是实现记住密码的功能,那么我们就不需要从头去写了,因为在上一章中的最佳实 践部分已经编写过一个登录界面了,有可以重用的代码为什么不用呢?那就首先打开 BroadcastBestPractice 项 ...
- asp.net记住我功能
登录页面的记住我功能 不能用session的原因:sessionID是以cookie的形式存在浏览器端的内存中 如果用户把浏览器关闭 则sessionID就消失 但是服务器端的sessi ...
随机推荐
- pidof---找寻PID
pidof---找寻pid 1.根据守护进程找到pid [root@localhost ~]# pidof sshd 2542 1622 [root@localhost ~]# ps -ef | gr ...
- java 异常捕捉 ( try catch finally ) 你真的掌握了吗?
掌握下面几条原则就可以完全解决“当try.catch.finally遭遇return”的问题. 原则:1.finally语句块中的代码是一定会执行的,而catch块中的代码只有发生异常时才会执行. 2 ...
- spring注解定时器
上一篇文章写了一个在配置文件中设置时间的定时器,现在来写一个注解方式的定时器: 1.工程结构如下: 2.需要执行的代码块: package com.Task; import org.springfra ...
- 上述代码在JavaScript事件处理中
上述代码在JavaScript事件处理中很常见,主要设置为与旧版本的Internet Explorer(主要在IE9之前)兼容,因为旧版本的IE不支持标准的W3C事件处理规范. 此代码中的e表示事件对 ...
- python中进制转换
使用Python内置函数:bin().oct().int().hex()可实现进制转换. 先看Python官方文档中对这几个内置函数的描述: bin(x)Convert an integer numb ...
- postgres 表和库等信息大小统计
一 .数据库大小的统计 1.单个库查询 select pg_database_size('zybdb'); 2.查询所有的库 方法一: select pg_database.datname, pg_s ...
- Maxwell平滑升级流程
1. 同步配置文件 copy之前的配置文件 2 关掉监控程序 如果有的话 3 kill掉之前的maxwell程序 4 查询已经读取到的position位置,然后重启服务 ...
- 第一章·MySQL介绍及安装
一.DBA工作内容及课程体系 二.MySQL课程体系介绍 三.DBA的职业素养 四.MySQL简介及安装 4.1 什么是数据? 数据(data)是事实或观察的结果,是对客观事物的逻辑归纳,是用于表示客 ...
- angular流程引擎集成
工作流在oa和erp中十分常见,现有成熟的工作流通常是在客户端实现的,web实现工作流的案例十分稀少.要实现web工作流必须要有强大的流程设计器,这里为大家介绍一款基于angular的流程控件,其功能 ...
- 【安徽集训】fiend
考试的时候只会 \(O(Tn^3)\) 的做法,其它题还都不会,想到一整场就打这么点是人都能写的暴力没啥意思,就懒得写了.. Description 双人博弈.每一轮 A 和 B 同时选择一个 \(1 ...