热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

SpringSecurity添加记住我功能(转载)

在网站的登录页面中,记住我选项是一个很常见的功能,勾选记住我后在一段时间内,用户无需进行登录操作就可以访问系统资源。在SpringSecurity中添加记住我功能很简单,大致过程是

在网站的登录页面中,记住我选项是一个很常见的功能,勾选记住我后在一段时间内,用户无需进行登录操作就可以访问系统资源。在Spring Security中添加记住我功能很简单,大致过程是:当用户勾选了记住我选项并登录成功后,Spring Security会生成一个token标识,然后将该token标识持久化到数据库,并且生成一个与该token相对应的COOKIE返回给浏览器。当用户过段时间再次访问系统时,如果该COOKIE没有过期,Spring Security便会根据COOKIE包含的信息从数据库中获取相应的token信息,然后帮用户自动完成登录操作。


一、token持久化

Spring Security的记住我功能的实现需要使用数据库来持久化token。我们在上一节Spring Security添加图形验证码的基础上来添加记住我的功能。


1、添加依赖

在application.yml中添加数据源配置:


spring:
datasource:
driver-class-name: com.mysql.jdbc.Driver
url: jdbc:mysql://127.0.0.1:3306/goldwind?useUnicode=yes
&characterEncoding=UTF-8&useSSL=false
username: root
password: 123456aa

添加数据库依赖:



<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-jdbcartifactId>
dependency>
<dependency>
<groupId>mysqlgroupId>
<artifactId>mysql-connector-javaartifactId>
<version>5.1.47version>
dependency>


2、配置bean

然后我们在BeanConfig中配置个token持久化对象:


package com.goldwind.config;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.authentication.rememberme.JdbcTokenRepositoryImpl;
import org.springframework.security.web.authentication.rememberme.PersistentTokenRepository;
import javax.sql.DataSource;
/**
* @Author: zy
* @Description: 定义一些bean
* @Date: 2020-2-9
*/
@Configuration
public class BeanConfig {
/**
* 从配置文件注入
*/
@Autowired
private DataSource dataSource;
/**
* token持久化对象
*
@return
*/
@Bean
public PersistentTokenRepository persistentTokenRepository(){
JdbcTokenRepositoryImpl jdbcTokenRepositoryImpl
= new JdbcTokenRepositoryImpl();
jdbcTokenRepositoryImpl.setDataSource(dataSource);
jdbcTokenRepositoryImpl.setCreateTableOnStartup(
false);
return jdbcTokenRepositoryImpl;
}

...
}

PersistentTokenRepository为一个接口类,这里我们用的是数据库持久化,所以实例用的是PersistentTokenRepository的实现类JdbcTokenRepositoryImpl。

JdbcTokenRepositoryImpl需要指定数据源,所以我们将配置好的数据源对象DataSource注入进来并配置到JdbcTokenRepositoryImpl的dataSource属性中。createTableOnStartup属性用于是否启动项目时创建保存token信息的数据表,这里设置为false,我们自己手动创建。

查看JdbcTokenRepositoryImpl的源码,可以看到其包含了一个CREATE_TABLE_SQL属性:


/** 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 = ?";

这个其实就是用于保存token对象数据表的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
)


二、修改登录页

完成上述配置后,我们稍微改造下登录页,加入记住我的勾选选项:


<input type="checkbox" name="remember-me"/> 记住我
<br>

其中name属性必须为remember-me.


三、配置生效

最后我们需要在Spring Security的认证流程中启用记住我的功能,在BrowserSecurityConfig的configure方法中开启记住我功能:


@Autowired
private PersistentTokenRepository persistentTokenRepository;
@Autowired
private CustomUserDetailService userDetailService;
/**
* 配置拦截请求资源
*
@param http:HTTP请求安全处理
*
@throws Exception
*/
@Override
protected void configure(HttpSecurity http) throws Exception {
http.addFilterBefore(validateCodeFilter, UsernamePasswordAuthenticationFilter.
class) // 添加验证码校验过滤器
.authorizeRequests() // 授权配置
.antMatchers("/code/image")
.permitAll()
// 无需认证的请求路径
.anyRequest() // 任何请求
.authenticated() //都需要身份认证
.and()
.formLogin()
// 或者httpBasic()
.loginPage("/login") // 指定登录页的路径
.loginProcessingUrl("/login") // 指定自定义form表单请求的路径
.successHandler(authenticationSucessHandler) // 处理登录成功
.failureHandler(authenticationFailureHandler) // 处理登录失败
// 必须允许所有用户访问我们的登录页(例如未验证的用户,否则验证流程就会进入死循环)
// 这个formLogin().permitAll()方法允许所有用户基于表单登录访问/login这个page。
.permitAll()
.and()
.rememberMe()
.tokenRepository(persistentTokenRepository)
// 配置 token 持久化仓库
.tokenValiditySeconds(3600) // remember 过期时间,单为秒
.userDetailsService(userDetailService) // 处理自动登录逻辑
.and()
.logout()
.permitAll()
.and()
//默认都会产生一个hiden标签 里面有安全相关的验证 防止请求伪造 这边我们暂时不需要 可禁用掉
.csrf().disable();
}

rememberMe()用于开启记住我功能;tokenRepository(persistentTokenRepository())用于指定token持久化方法;tokenValiditySeconds配置了token的有效时长,单为为秒;userDetailsService(userDetailService)用于处理通过token对象自动登录,这里为我们自定义的UserDetailsService接口实现。

配置好后,重启项目,登录页面如下所示:

技术分享图片

 

勾选并成功登录后,可以看到网页多了个remember-me的COOKIE对象:

技术分享图片

 查看数据库表persistent_logins:

技术分享图片

可以看到token信息已经成功持久化了,并且浏览器也成功生成了相应的COOKIE。在COOKIE未失效之前,无论是重开浏览器或者重启项目,用户都无需再次登录就可以访问系统资源了。

参考文章:
[1] Spring Security添加记住我功能(转载)


推荐阅读
  • 我的读书清单(持续更新)201705311.《一千零一夜》2006(四五年级)2.《中华上下五千年》2008(初一)3.《鲁滨孙漂流记》2008(初二)4.《钢铁是怎样炼成的》20 ... [详细]
  • 本文探讨了一种常见的C++面试题目——实现自己的String类。通过此过程,不仅能够检验开发者对C++基础知识的掌握程度,还能加深对其高级特性的理解。文章详细介绍了如何实现基本的功能,如构造函数、析构函数、拷贝构造函数及赋值运算符重载等。 ... [详细]
  • 本文介绍了如何通过安装 sqlacodegen 和 pymysql 来根据现有的 MySQL 数据库自动生成 ORM 的模型文件(model.py)。此方法适用于需要快速搭建项目模型层的情况。 ... [详细]
  • 在1995年,Simon Plouffe 发现了一种特殊的求和方法来表示某些常数。两年后,Bailey 和 Borwein 在他们的论文中发表了这一发现,这种方法被命名为 Bailey-Borwein-Plouffe (BBP) 公式。该问题要求计算圆周率 π 的第 n 个十六进制数字。 ... [详细]
  • 二维码的实现与应用
    本文介绍了二维码的基本概念、分类及其优缺点,并详细描述了如何使用Java编程语言结合第三方库(如ZXing和qrcode.jar)来实现二维码的生成与解析。 ... [详细]
  • 本文介绍了如何通过C#语言调用动态链接库(DLL)中的函数来实现IC卡的基本操作,包括初始化设备、设置密码模式、获取设备状态等,并详细展示了将TextBox中的数据写入IC卡的具体实现方法。 ... [详细]
  • 本文回顾了作者在求职阿里和腾讯实习生过程中,从最初的迷茫到最后成功获得Offer的心路历程。文中不仅分享了个人的面试经历,还提供了宝贵的面试准备建议和技巧。 ... [详细]
  • 随着Linux操作系统的广泛使用,确保用户账户及系统安全变得尤为重要。用户密码的复杂性直接关系到系统的整体安全性。本文将详细介绍如何在CentOS服务器上自定义密码规则,以增强系统的安全性。 ... [详细]
  • 3DSMAX制作超现实的体育馆模型
    这篇教程是向脚本之家的朋友介绍3DSMAX制作超现实的体育馆模型方法,教程制作出来的体育馆模型非常地不错,不过教程有点难度,需要有一定基础的朋友学习,推荐到脚本之家,喜欢的朋友可 ... [详细]
  • 本文介绍了如何在AngularJS应用中使用ng-repeat指令创建可单独点击选中的列表项,并详细描述了实现这一功能的具体步骤和代码示例。 ... [详细]
  • 默认情况下,Git 使用 Nano 编辑器进行提交信息的编辑,但如果您更喜欢使用 Vim,可以通过简单的配置更改来实现这一变化。本文将指导您如何通过修改全局配置文件来设置 Vim 作为默认的 Git 提交编辑器。 ... [详细]
  • 为何Compose与Swarm之后仍有Kubernetes的诞生?
    探讨在已有Compose和Swarm的情况下,Kubernetes是如何以其独特的设计理念和技术优势脱颖而出,成为容器编排领域的领航者。 ... [详细]
  • 本文介绍了SIP(Session Initiation Protocol,会话发起协议)的基本概念、功能、消息格式及其实现机制。SIP是一种在IP网络上用于建立、管理和终止多媒体通信会话的应用层协议。 ... [详细]
  • 在日常生活中,支付宝已成为不可或缺的支付工具之一。本文将详细介绍如何通过支付宝实现免费提现,帮助用户更好地管理个人财务,避免不必要的手续费支出。 ... [详细]
  • 本文详细介绍了C++中的构造函数,包括其定义、特点以及如何通过构造函数进行对象的初始化。此外,还探讨了转换构造函数的概念及其在不同情境下的应用,以及如何避免不必要的隐式类型转换。 ... [详细]
author-avatar
瑶2012瑶_881
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有