自动登录是将用户的登录信息保存在用户浏览器的cookie中,当用户下次访问时,自动实现校验 并建立登录态的一种机制。

Spring Security提供了两种非常好的令牌:

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

散列算法在Spring Security中是通过加密几个关键信息实现的:

hashInfo = md5Hex(username + ":" + expirationTime + ":" + password + ":" + key)
rememberCookie = base64(username + ":" + expirationTime + ":" + hashInfo)

其中,expirationTime指本次自动登录的有效期,key为指定的一个散列盐值,用于防止令牌被修 改。通过这种方式生成cookie后,在下次登录时,SpringSecurity首先用Base64简单解码得到用户名、 过期时间和加密散列值;然后使用用户名得到密码;接着重新以该散列算法正向计算,并将计算结果与旧的加密散列值进行对比,从而确认该令牌是否有效。

一、散列加密方案

1、修改配置

spring security配置登陆时提出上次登陆 spring security 登录_用户名

 1、rememberMeCookieName设置的是生成的cookie的名字

2、rememberMeParameter设置的是前端登录是传参的名字,如下图,SpringSecurity会使用这个名字取前端的参数

spring security配置登陆时提出上次登陆 spring security 登录_持久化_02

 3、key是一个散列盐值,没有指定的时候是一个随机的UUID字符串,这样每次启动服务,或者部署多台机器都会导致自动登录使用的cookie失效。所以直接指定一个固定的。

4、userDetailService需要指定,用来查询用户信息进行对比

2.前端代码修改

<div class="layui-form-item">
              <div class="layui-input-inline">
                <input type="checkbox" name="remember" title="记住我" >
              </div>
              <div class="layui-form-mid" style="float: right">
                <a href="#" class="wait" style="color: #777777">忘记密码</a>
              </div>
            </div>

具体可以查看开头的demo源码

3.启动服务

spring security配置登陆时提出上次登陆 spring security 登录_自动登录_03

 登录后,查看cookie,会发现有了一个uc-token。

spring security配置登陆时提出上次登陆 spring security 登录_自动登录_04

 之前每次重启项目都需要重新登录,现在重新启动服务,发现不需要登录了。

二、持久化令牌方案

持久化令牌方案在交互上与散列加密方案一致,都是在用户勾选Remember-me之后,将生成的令 牌发送到用户浏览器,并在用户下次访问系统时读取该令牌进行认证。不同的是,它采用了更加严谨 的安全性设计。

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

这样设计有什么好处呢?

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

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

1.数据库表

SpringSecurity相关的代码逻辑已经实现了,对应的实体:

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;
	}

}

因此我们需要按照实体,创建一个数据库表:

数据库sql也有提供:

public class JdbcTokenRepositoryImpl extends JdbcDaoSupport implements PersistentTokenRepository {

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

这里做了一些小改动,也可以按原样:

-- ---------------
-- 自动登录
-- ---------------
CREATE TABLE `persistent_logins` (
    `series` VARCHAR(64) NOT NULL DEFAULT '' COMMENT '主键',
    `username` VARCHAR(64) NOT NULL DEFAULT '' COMMENT '用户名',
    `token` VARCHAR(64) NOT NULL DEFAULT '' COMMENT 'token',
    `last_used` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '最后使用时间',
    PRIMARY KEY (`series`)
)ENGINE = InnoDB DEFAULT CHARSET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci COMMENT ='用户表';

表的主键是series,Spring Security可以通过series查询表中的其他信息。有了存储自动登录信息的表 之后,就可以继续配置Spring Security的Remember-me功能了。由于需要使用持久化令牌方案,所以指定tokenRepository。

2.修改配置类

spring security配置登陆时提出上次登陆 spring security 登录_安全_05

spring security配置登陆时提出上次登陆 spring security 登录_用户名_06

仍然直接使用SpringSecurity提供的。

3.运行

输入账号密码登录成功后,查看数据库,会有一条数据产生。

spring security配置登陆时提出上次登陆 spring security 登录_用户名_07

 重启项目等都不需要再次登录。