记住我 java_JavaWeb-SpringSecurity记住我功能

本文档详细介绍了如何在JavaWeb项目中利用SpringSecurity实现'记住我'功能,包括在login.html中添加复选框,配置持久化令牌仓库,数据库表创建,以及在SecurityConfig.java中设置相关配置,确保用户选择'记住我'后能在一定时间内自动登录。
摘要由CSDN通过智能技术生成

系列博文

项目已上传至guthub  传送门

JavaWeb-SpringSecurity初认识  传送门

JavaWeb-SpringSecurity在数据库中查询登陆用户  传送门

JavaWeb-SpringSecurity自定义登陆页面  传送门

JavaWeb-SpringSecurity实现需求-判断请求是否以html结尾  传送门

JavaWeb-SpringSecurity自定义登陆配置  传送门

JavaWeb-SpringSecurity图片验证ImageCode  传送门

JavaWeb-SpringSecurity记住我功能  传送门

JavaWeb-SpringSecurity使用短信验证码登陆  传送门

在login.html中添加一个复选框,表示"记住我"功能【注意:标签的name一定是remember-me】

用户名:


密码:


图片验证码:

记住我

64453462002329f90b23db3aaa3585f0.png

在config层SecurityConfig.java中添加persistentTokenRepository()方法,用来在server层操作数据库

@AutowiredprivateDataSource dataSource;//负责操作数据库

publicPersistentTokenRepository persistentTokenRepository()

{

JdbcTokenRepositoryImpl tokenRepository= newJdbcTokenRepositoryImpl();

tokenRepository.setDataSource(dataSource);returntokenRepository;

}

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 getTokenBySeries 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 createNewToken*/

public static final String DEF_INSERT_TOKEN_SQL = "insert into persistent_logins (username, series, token, last_used) values(?,?,?,?)";/**The default SQL used by updateToken*/

public static final String DEF_UPDATE_TOKEN_SQL = "update persistent_logins set token = ?, last_used = ? where series = ?";/**The default SQL used by removeUserTokens*/

public static final String DEF_REMOVE_USER_TOKENS_SQL = "delete from persistent_logins where username = ?";

992803b97a7477289c02360b0299efdf.png

8f900a89c6347c561fdf2122f13be562.png

961ddebeb323a10fe0623af514929fc1.png

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实现"记住我"功能

@AutowiredprivateDataSource dataSource;//负责操作数据库

publicPersistentTokenRepository persistentTokenRepository()

{

JdbcTokenRepositoryImpl tokenRepository= newJdbcTokenRepositoryImpl();

tokenRepository.setDataSource(dataSource);returntokenRepository;

}

@AutowiredpublicUserDetailsService userDetailService;protected void configure(HttpSecurity http) throwsException{//声明我们自己写的过滤器

ValidateCodeFilter validateCodeFilter = newValidateCodeFilter();//给过滤器赋值

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();

}

8f900a89c6347c561fdf2122f13be562.png

961ddebeb323a10fe0623af514929fc1.png

packagecom.Gary.GaryRESTful.config;importjavax.sql.DataSource;importorg.springframework.beans.factory.annotation.Autowired;importorg.springframework.context.annotation.Bean;importorg.springframework.context.annotation.Configuration;importorg.springframework.security.config.annotation.web.builders.HttpSecurity;importorg.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;importorg.springframework.security.core.userdetails.UserDetailsService;importorg.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;importorg.springframework.security.crypto.password.PasswordEncoder;importorg.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;importorg.springframework.security.web.authentication.rememberme.JdbcTokenRepositoryImpl;importorg.springframework.security.web.authentication.rememberme.PersistentTokenRepository;importcom.Gary.GaryRESTful.filter.ValidateCodeFilter;importcom.Gary.GaryRESTful.handler.LoginFailureHandler;importcom.Gary.GaryRESTful.handler.LoginSuccessHandler;importcom.Gary.GaryRESTful.properties.GarySecurityProperties;//Web应用安全适配器

@Configurationpublic class SecurityConfig extendsWebSecurityConfigurerAdapter{//告诉SpringSecurity密码用什么加密的

@BeanpublicPasswordEncoder passwordEncoder()

{return newBCryptPasswordEncoder();

}

@AutowiredprivateLoginSuccessHandler loginSuccessHandler;

@AutowiredprivateLoginFailureHandler loginFailureHandler;

@AutowiredprivateGarySecurityProperties garySecurityProperties;

@AutowiredprivateDataSource dataSource;//负责操作数据库

publicPersistentTokenRepository persistentTokenRepository()

{

JdbcTokenRepositoryImpl tokenRepository= newJdbcTokenRepositoryImpl();

tokenRepository.setDataSource(dataSource);returntokenRepository;

}

@AutowiredpublicUserDetailsService userDetailService;protected void configure(HttpSecurity http) throwsException{//声明我们自己写的过滤器

ValidateCodeFilter validateCodeFilter = newValidateCodeFilter();//给过滤器赋值

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 = newValidateCodeProperties();private int rememberMeSeconds = 60*60;//getter()、setter()

在application.properties中配置Token过期时间

#Token过期时间

gary.security.rememberMeSeconds = 3600

在SecurityConfig.java下的configure()方法中配置过期秒数

protected void configure(HttpSecurity http) throwsException{//声明我们自己写的过滤器

ValidateCodeFilter validateCodeFilter = newValidateCodeFilter();//给过滤器赋值

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();

}

8f900a89c6347c561fdf2122f13be562.png

961ddebeb323a10fe0623af514929fc1.png

packagecom.Gary.GaryRESTful.config;importjavax.sql.DataSource;importorg.springframework.beans.factory.annotation.Autowired;importorg.springframework.context.annotation.Bean;importorg.springframework.context.annotation.Configuration;importorg.springframework.security.config.annotation.web.builders.HttpSecurity;importorg.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;importorg.springframework.security.core.userdetails.UserDetailsService;importorg.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;importorg.springframework.security.crypto.password.PasswordEncoder;importorg.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;importorg.springframework.security.web.authentication.rememberme.JdbcTokenRepositoryImpl;importorg.springframework.security.web.authentication.rememberme.PersistentTokenRepository;importcom.Gary.GaryRESTful.filter.ValidateCodeFilter;importcom.Gary.GaryRESTful.handler.LoginFailureHandler;importcom.Gary.GaryRESTful.handler.LoginSuccessHandler;importcom.Gary.GaryRESTful.properties.GarySecurityProperties;//Web应用安全适配器

@Configurationpublic class SecurityConfig extendsWebSecurityConfigurerAdapter{//告诉SpringSecurity密码用什么加密的

@BeanpublicPasswordEncoder passwordEncoder()

{return newBCryptPasswordEncoder();

}

@AutowiredprivateLoginSuccessHandler loginSuccessHandler;

@AutowiredprivateLoginFailureHandler loginFailureHandler;

@AutowiredprivateGarySecurityProperties garySecurityProperties;

@AutowiredprivateDataSource dataSource;//负责操作数据库

publicPersistentTokenRepository persistentTokenRepository()

{

JdbcTokenRepositoryImpl tokenRepository= newJdbcTokenRepositoryImpl();

tokenRepository.setDataSource(dataSource);returntokenRepository;

}

@AutowiredpublicUserDetailsService userDetailService;protected void configure(HttpSecurity http) throwsException{//声明我们自己写的过滤器

ValidateCodeFilter validateCodeFilter = newValidateCodeFilter();//给过滤器赋值

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记录】

4fa09a4e357f2a74826a4d514966d155.gif

8f900a89c6347c561fdf2122f13be562.png

961ddebeb323a10fe0623af514929fc1.png

Insert title here

Gary登陆页面

用户名:


密码:


图片验证码:

记住我

login.html

8f900a89c6347c561fdf2122f13be562.png

961ddebeb323a10fe0623af514929fc1.png

#datasource

spring.datasource.url=jdbc:mysql:///springsecurity?serverTimezone=UTC&characterEncoding=utf-8spring.datasource.username=root

spring.datasource.password=123456spring.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

8f900a89c6347c561fdf2122f13be562.png

961ddebeb323a10fe0623af514929fc1.png

packagecom.Gary.GaryRESTful.properties;importorg.springframework.boot.context.properties.ConfigurationProperties;

@ConfigurationProperties(prefix= "gary.security")public classGarySecurityProperties {//LoginType登陆的方式,默认为JSON(restful设计风格)

private LoginType loginType =LoginType.JSON;private ValidateCodeProperties code = newValidateCodeProperties();private int rememberMeSeconds = 60*60;public intgetRememberMeSeconds() {returnrememberMeSeconds;

}public void setRememberMeSeconds(intrememberMeSeconds) {this.rememberMeSeconds =rememberMeSeconds;

}publicValidateCodeProperties getCode() {returncode;

}public voidsetCode(ValidateCodeProperties code) {this.code =code;

}publicLoginType getLoginType() {returnloginType;

}public voidsetLoginType(LoginType loginType) {this.loginType =loginType;

}

}

GarySecurityProperties.java

8f900a89c6347c561fdf2122f13be562.png

961ddebeb323a10fe0623af514929fc1.png

packagecom.Gary.GaryRESTful.config;importjavax.sql.DataSource;importorg.springframework.beans.factory.annotation.Autowired;importorg.springframework.context.annotation.Bean;importorg.springframework.context.annotation.Configuration;importorg.springframework.security.config.annotation.web.builders.HttpSecurity;importorg.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;importorg.springframework.security.core.userdetails.UserDetailsService;importorg.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;importorg.springframework.security.crypto.password.PasswordEncoder;importorg.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;importorg.springframework.security.web.authentication.rememberme.JdbcTokenRepositoryImpl;importorg.springframework.security.web.authentication.rememberme.PersistentTokenRepository;importcom.Gary.GaryRESTful.filter.ValidateCodeFilter;importcom.Gary.GaryRESTful.handler.LoginFailureHandler;importcom.Gary.GaryRESTful.handler.LoginSuccessHandler;importcom.Gary.GaryRESTful.properties.GarySecurityProperties;//Web应用安全适配器

@Configurationpublic class SecurityConfig extendsWebSecurityConfigurerAdapter{//告诉SpringSecurity密码用什么加密的

@BeanpublicPasswordEncoder passwordEncoder()

{return newBCryptPasswordEncoder();

}

@AutowiredprivateLoginSuccessHandler loginSuccessHandler;

@AutowiredprivateLoginFailureHandler loginFailureHandler;

@AutowiredprivateGarySecurityProperties garySecurityProperties;

@AutowiredprivateDataSource dataSource;//负责操作数据库

publicPersistentTokenRepository persistentTokenRepository()

{

JdbcTokenRepositoryImpl tokenRepository= newJdbcTokenRepositoryImpl();

tokenRepository.setDataSource(dataSource);returntokenRepository;

}

@AutowiredpublicUserDetailsService userDetailService;protected void configure(HttpSecurity http) throwsException{//声明我们自己写的过滤器

ValidateCodeFilter validateCodeFilter = newValidateCodeFilter();//给过滤器赋值

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值