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自动登录内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

时间: 2020-06-26

SpringSecurity rememberme功能实现过程解析

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

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

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

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

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

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

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

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

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

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

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

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

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

Spring Boot中使用 Spring Security 构建权限系统的示例代码

Spring Security是一个能够为基于Spring的企业应用系统提供声明式的安全访问控制解决方案的安全框架.它提供了一组可以在Spring应用上下文中配置的Bean,为应用系统提供声明式的安全访问控制功能,减少了为企业系统安全控制编写大量重复代码的工作. 权限控制是非常常见的功能,在各种后台管理里权限控制更是重中之重.在Spring Boot中使用 Spring Security 构建权限系统是非常轻松和简单的.下面我们就来快速入门 Spring Security .在开始前我们需要一对

详解spring cloud构建微服务架构的网关(API GateWay)

前言 在我们前面的博客中讲到,当服务A需要调用服务B的时候,只需要从Eureka中获取B服务的注册实例,然后使用Feign来调用B的服务,使用Ribbon来实现负载均衡,但是,当我们同时向客户端暴漏多个服务的时候,客户端怎么调用我们暴漏的服务了,如果我们还想加入安全认证,权限控制,过滤器以及动态路由等特性了,那么就需要使用Zuul来实现API GateWay了,下面,我们先来看下Zuul怎么使用. 一.加入Zuul的依赖 <dependency> <groupId>org.spri

SpringBoot与spring security的结合的示例

权限控制,也是我们再日常开发中经常遇到的场景,需要根据用户的角色决定是否可以看到某个资源.目前,市面上此类框架主要有shiro与我们今天要讲到的spring security.关于权限的控制有复杂的控制,例如几乎每个公司都有单点登录系统,根据用户名来到数据库中拿到对应的权限,在展示该权限下能看到的资源.还有一种就是简单的控制,也就是我们今天所要提到的.将账号,密码,角色配置到代码中,也可以进行简单的控制,缺点不言而喻,扩展性不好,只有固定的账号,但是作为演示还是够用的. 好了废话不多说,上pom

Spring Boot2.0使用Spring Security的示例代码

一.Spring Secutity简介 Spring 是一个非常流行和成功的 Java 应用开发框架.Spring Security 基于 Spring 框架,提供了一套 Web 应用安全性的完整解决方案.一般来说,Web 应用的安全性包括用户认证(Authentication)和用户授权(Authorization)两个部分.用户认证指的是验证某个用户是否为系统中的合法主体,也就是说用户能否访问该系统.用户认证一般要求用户提供用户名和密码.系统通过校验用户名和密码来完成认证过程.用户授权指的是

Spring Security Remember me使用及原理详解

Remember me功能就是勾选"记住我"后,一次登录,后面在有效期内免登录. 先看具体配置: pom文件: <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-jpa</artifactId> </dependency> <dependency> <group

Spring security实现登陆和权限角色控制

 随笔简介 1.spring版本:4.3.2.RELEASE+spring security 版本:4.1.2.RELEASE(其它不做说明) 2.所展示内容全部用注解配置 3.springmvc已经配置好,不作说明 4.会涉及到springmvc,spel,el的东西,不熟悉的同学可以先去看一下这方面内容,特别是springmvc 首先想一下,登陆需要什么,最简单的情况下,用户名,密码,然后比对数据库,如果吻合就跳转到个人页面,否则回到登陆页面,并且提示用户名密码错误.这个过程中应该还带有权限