Spring Security学习之rememberMe自动登录的实现

前言

自动登录是将用户的登录信息保存在用户浏览器的cookie中,当用户下次访问时,自动实现校验并建立登录态的一种机制。
Spring Security提供了两种非常好的令牌:

散列算法加密用户必要的登录信息并生成令牌
数据库等持久性数据存储机制用的持久化令牌

散列加密方案

在Spring Security中加入自动登录的功能非常简单:

 @Override
 protected void configure(HttpSecurity http) throws Exception {
  http.authorizeRequests()
    .antMatchers("/api/user/**").hasRole("user") //user 角色访问/api/user/开头的路由
    .antMatchers("/api/admin/**").hasRole("admin") //admin 角色访问/api/admin/开头的路由
    .antMatchers("/api/public/**").permitAll()     //允许所有可以访问/api/public/开头的路由
    .and()
    .formLogin()
    .and()
    .rememberMe().userDetailsService(userDetailsService());  //记住密码
 }

重启服务后访问受限 API,这次在表单登录页中多了一个可选框:

勾选“Remember me on this computer”可选框(简写为Remember-me),按照正常的流程登录,并在开发者工具中查看浏览器cookie,可以看到除JSESSIONID外多了一个值:

这是Spring Security默认自动登录的cookie字段。在不配置的情况下,过期时间是两个星期:

Spring Security会在每次表单登录成功之后更新此令牌,具体处理方式在源码中:

RememberConfigurer:

持久化令牌方案

在持久化令牌方案中,最核心的是series和token两个值,它们都是用MD5散列过的随机字符串。不同的是,series仅在用户使用密码重新登录时更新,而token会在每一个新的session中都重新生成。

解决了散列加密方案中一个令牌可以同时在多端登录的问题。每个会话都会引发token的更新,即每个token仅支持单实例登录。

自动登录不会导致series变更,而每次自动登录都需要同时验证series和token两个值,当该令牌还未使用过自动登录就被盗取时,系统会在非法用户验证通过后刷新 token 值,此时在合法用户的浏览器中,该token值已经失效。当合法用户使用自动登录时,由于该series对应的 token 不同,系统可以推断该令牌可能已被盗用,从而做一些处理。例如,清理该用户的所有自动登录令牌,并通知该用户可能已被盗号等

Spring Security使用PersistentRememberMeToken来表明一个验证实体:

public class PersistentRememberMeToken {
  private final String username;
  private final String series;
  private final String tokenValue;
  private final Date date;

  public PersistentRememberMeToken(String username, String series, String tokenValue, Date date) {
    this.username = username;
    this.series = series;
    this.tokenValue = tokenValue;
    this.date = date;
  }

  public String getUsername() {
    return this.username;
  }

  public String getSeries() {
    return this.series;
  }

  public String getTokenValue() {
    return this.tokenValue;
  }

  public Date getDate() {
    return this.date;
  }
}

需要使用持久化令牌方案,需要传入PersistentTokenRepository的实例:

PersistentTokenRepository接口主要涉及token的增删查改四个接口:

MyPersistentTokenRepositoryImpl使我们实现PersistentTokenRepository接口:

@Service
public class MyPersistentTokenRepositoryImpl implements PersistentTokenRepository {

  @Autowired
  private JPAPersistentTokenRepository repository;

  @Override
  public void createNewToken(PersistentRememberMeToken persistentRememberMeToken) {
    MyPersistentToken myPersistentToken = new MyPersistentToken();
    myPersistentToken.setSeries(persistentRememberMeToken.getSeries());
    myPersistentToken.setUsername(persistentRememberMeToken.getUsername());
    myPersistentToken.setTokenValue(persistentRememberMeToken.getTokenValue());
    myPersistentToken.setUser_last(persistentRememberMeToken.getDate());
    repository.save(myPersistentToken);
  }

  @Override
  public void updateToken(String series, String tokenValue, Date lastUsed) {
    MyPersistentToken myPersistentToken = repository.findBySeries(series);
    myPersistentToken.setUser_last(lastUsed);
    myPersistentToken.setTokenValue(tokenValue);
    repository.save(myPersistentToken);
  }

  @Override
  public PersistentRememberMeToken getTokenForSeries(String series) {
    MyPersistentToken myPersistentToken = repository.findBySeries(series);
    PersistentRememberMeToken persistentRememberMeToken = new PersistentRememberMeToken(myPersistentToken.getUsername(), myPersistentToken.getSeries(), myPersistentToken.getTokenValue(), myPersistentToken.getUser_last());
    return persistentRememberMeToken;
  }

  @Override
  @Transactional
  public void removeUserTokens(String username) {
    repository.deleteByUsername(username);
  }
}
public interface JPAPersistentTokenRepository extends JpaRepository<MyPersistentToken,Long> {
  MyPersistentToken findBySeries(String series);
  void deleteByUsername(String username);
}
@Entity
@Table(name = "persistent_token")
public class MyPersistentToken {
  @Id
  @GeneratedValue(strategy = GenerationType.SEQUENCE)
  private Long id;
  private String username;
  @Column(unique = true)
  private String series;
  private String tokenValue;
  private Date user_last;

  public Long getId() {
    return id;
  }

  public void setId(Long id) {
    this.id = id;
  }

  public String getUsername() {
    return username;
  }

  public void setUsername(String username) {
    this.username = username;
  }

  public String getSeries() {
    return series;
  }

  public void setSeries(String series) {
    this.series = series;
  }

  public String getTokenValue() {
    return tokenValue;
  }

  public void setTokenValue(String tokenValue) {
    this.tokenValue = tokenValue;
  }

  public Date getUser_last() {
    return user_last;
  }

  public void setUser_last(Date user_last) {
    this.user_last = user_last;
  }
}

当自动登录认证时,Spring Security 通过series获取用户名、token以及上一次自动登录时间三个信息,通过用户名确认该令牌的身份,通过对比 token 获知该令牌是否有效,通过上一次自动登录时间获知该令牌是否已过期,并在完整校验通过之后生成新的token。

总结

到此这篇关于Spring Security学习之rememberMe自动登录实现的文章就介绍到这了,更多相关Spring Security rememberMe自动登录内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • Spring Security 构建rest服务实现rememberme 记住我功能

    Spring security记住我基本原理: 登录的时候,请求发送给过滤器UsernamePasswordAuthenticationFilter,当该过滤器认证成功后,会调用RememberMeService,会生成一个token,将token写入到浏览器cookie,同时RememberMeService里边还有个TokenRepository,将token和用户信息写入到数据库中.这样当用户再次访问系统,访问某一个接口时,会经过一个RememberMeAuthenticationFilt

  • Spring Security 自动踢掉前一个登录用户的实现代码

    登录成功后,自动踢掉前一个登录用户,松哥第一次见到这个功能,就是在扣扣里边见到的,当时觉得挺好玩的. 自己做开发后,也遇到过一模一样的需求,正好最近的 Spring Security 系列正在连载,就结合 Spring Security 来和大家聊一聊这个功能如何实现. 本文是本系列的第十三篇,阅读前面文章有助于更好的理解本文: 挖一个大坑,Spring Security 开搞! 松哥手把手带你入门 Spring Security,别再问密码怎么解密了 手把手教你定制 Spring Securi

  • Spring Security实现两周内自动登录"记住我"功能

    本文是Spring Security系列中的一篇.在上一篇文章中,我们通过实现UserDetailsService和UserDetails接口,实现了动态的从数据库加载用户.角色.权限相关信息,从而实现了登录及授权相关的功能.这一节就在此基础上新增,登录过程中经常使用的"记住我"功能,也就是我们经常会在各种网站登陆时见到的"两周内免登录","三天内免登录"的功能.该功能的作用就是:当我们登录成功之后,一定的周期内当我们再次访问该网站,不需要重新登

  • 详解使用Spring Security进行自动登录验证

    在之前的博客使用SpringMVC创建Web工程并使用SpringSecurity进行权限控制的详细配置方法 中,我们描述了如何配置一个基于SpringMVC.SpringSecurity框架的网站系统.在这篇博客中,我们将继续描述如何使用Spring Security进行登录验证. 总结一下Spring Security的登录验证关键步骤: 1.在数据库中建好三张表,即users.authorities和persistent_logins三个.注意字段的定义,不能少,可以多,名字必须按规定来.

  • SpringSecurity rememberme功能实现过程解析

    记住我功能原理分析 还记得前面咱们分析认证流程时,提到的记住我功能吗? 现在继续跟踪找到AbstractRememberMeServices对象的loginSuccess方法: 再点进去上面if判断中的rememberMeRequested方法,还在当前类中: 如果上面方法返回true,就表示页面勾选了记住我选项了. 继续顺着调用的方法找到PersistentTokenBasedRememberMeServices的onLoginSuccess方法: 注意name和value属性的值不要写错哦!

  • Spring security实现记住我下次自动登录功能过程详解

    一.原理分析 第一次登陆时,如果用户勾选了readme选项,登陆成功后springsecurity会生成一个cookie返回给浏览器端,浏览器下次访问时如果携带了这个cookie,springsecurity就会放行这次访问. 二.实现方式 2.1 简单实现方式 (1) 在springsecurity的配置文件中,http节点下增加一个remember-me配置 <security:http auto-config="true" use-expressions="fal

  • spring security实现下次自动登录功能过程解析

    这篇文章主要介绍了spring security实现记住我下次自动登录功能,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 一.原理分析 第一次登陆时,如果用户勾选了readme选项,登陆成功后springsecurity会生成一个cookie返回给浏览器端,浏览器下次访问时如果携带了这个cookie,springsecurity就会放行这次访问. 二.实现方式 2.1 简单实现方式 (1) 在springsecurity的配置文件中,http节

  • Spring Security学习之rememberMe自动登录的实现

    前言 自动登录是将用户的登录信息保存在用户浏览器的cookie中,当用户下次访问时,自动实现校验并建立登录态的一种机制. Spring Security提供了两种非常好的令牌: 散列算法加密用户必要的登录信息并生成令牌 数据库等持久性数据存储机制用的持久化令牌 散列加密方案 在Spring Security中加入自动登录的功能非常简单: @Override protected void configure(HttpSecurity http) throws Exception { http.au

  • Spring Security 实现短信验证码登录功能

    之前文章都是基于用户名密码登录,第六章图形验证码登录其实还是用户名密码登录,只不过多了一层图形验证码校验而已:Spring Security默认提供的认证流程就是用户名密码登录,整个流程都已经固定了,虽然提供了一些接口扩展,但是有些时候我们就需要有自己特殊的身份认证逻辑,比如用短信验证码登录,它和用户名密码登录的逻辑是不一样的,这时候就需要重新写一套身份认证逻辑. 开发短信验证码接口 获取验证码 短信验证码的发送获取逻辑和图片验证码类似,这里直接贴出代码. @GetMapping("/code/

  • Spring Security学习笔记(一)

    介绍 这里学习SpringSecurity,对SpringSecurity进行学习. 基本用法 添加依赖 <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-security</artifactId> </dependency> 添加接口 package com.example.demo.web; import

  • SpringBoot集成Spring Security用JWT令牌实现登录和鉴权的方法

    最近在做项目的过程中 需要用JWT做登录和鉴权 查了很多资料 都不甚详细 有的是需要在application.yml里进行jwt的配置 但我在导包后并没有相应的配置项 因而并不适用 在踩过很多坑之后 稍微整理了一下 做个笔记 一.概念 1.什么是JWT Json Web Token (JWT)是为了在网络应用环境间传递声明而执行的一种基于JSON的开放标准(RFC 7519) 该token被设计为紧凑且安全的 特别适用于分布式站点的单点登录(SSO)场景 随着JWT的出现 使得校验方式更加简单便

  • Springboot+Spring Security实现前后端分离登录认证及权限控制的示例代码

    目录 前言 本文主要的功能 一.准备工作 1.统一错误码枚举 2.统一json返回体 3.返回体构造工具 4.pom 5.配置文件 二.数据库表设计 初始化表数据语句 三.Spring Security核心配置:WebSecurityConfig 四.用户登录认证逻辑:UserDetailsService 1.创建自定义UserDetailsService 2.准备service和dao层方法 五.用户密码加密 六.屏蔽Spring Security默认重定向登录页面以实现前后端分离功能 1.实

  • SpringBoot + Spring Security 基本使用及个性化登录配置详解

    Spring Security 基本介绍 这里就不对Spring Security进行过多的介绍了,具体的可以参考官方文档 我就只说下SpringSecurity核心功能: 认证(你是谁) 授权(你能干什么) 攻击防护(防止伪造身份) 基本环境搭建 这里我们以SpringBoot作为项目的基本框架,我这里使用的是maven的方式来进行的包管理,所以这里先给出集成Spring Security的方式 <dependencies> ... <dependency> <groupI

  • Spring security如何实现记录用户登录时间功能

    一.原理分析 spring security提供了一个接口 AuthenticationSuccessHandler,该接口中只有一个方法,用来进行登录成功后的操作 public interface AuthenticationSuccessHandler { /** * Called when a user has been successfully authenticated. * * @param request the request which caused the successfu

  • Spring Security组件一键接入验证码登录和小程序登录的详细过程

    目录 DSL配置风格 为什么这么灵活? 使用方法 普通登录 验证码登录 小程序登录 最近实现了一个多端登录的Spring Security组件,用起来非常丝滑,开箱即用,可插拔,而且灵活性非常强.我觉得能满足大部分场景的需要.目前完成了手机号验证码和微信小程序两种自定义登录,加上默认的Form登录,一共三种,现在开源分享给大家,接下来简单介绍一下这个插件包. DSL配置风格 切入正题,先来看看配置: @Bean SecurityFilterChain defaultSecurityFilterC

  • Spring Security基于散列加密方案实现自动登录功能

    目录 前言 一. 自动登录简介 1. 为什么要自动登录 2. 自动登录的实现方案 二. 基于散列加密方案实现自动登录 1. 配置加密令牌的key 2. 配置SecurityConfig类 3. 添加测试接口 4. 启动项目测试 三. 散列加密方案实现原理 1. cookie的加密原理分析 2. cookie的解码原理分析 3. 自动登录的源码分析 3.1 令牌生成的源码分析 3.2 令牌解析的源码分析 前言 在前面的2个章节中,一一哥 带大家实现了在Spring Security中添加图形验证码

随机推荐