springsecurity remember-me 功能

本文基于spring-security-web-4.1.2.RELEASE。

要实现rememberMe,有两种方案。

1.基于简单加密token的方法

首先需要在配置文件中加入<remember-me />,然后在登录页表单中加入复选框即可。

<input type="checkbox" name="remember-me" value="true" checked="checked"/>两周之内不必登陆

分析:

这种方式实现方式是在当用户选择了记住我成功登录后,Spring Security会判断request中是否包含remember-me参数,判断逻辑在spring-security-web包的

  org.springframework.security.web.authentication.rememberme.AbstractRememberMeServices中,如下:

        String paramValue = request.getParameter(parameter);

        if (paramValue != null) {
            if (paramValue.equalsIgnoreCase("true") || paramValue.equalsIgnoreCase("on")
                    || paramValue.equalsIgnoreCase("yes") || paramValue.equals("1")) {
                return true;
            }
        }

然后服务器将会生成一个token放入cookie(该cookie默认名称remember-me)中。token值由如下方式组成:

base64(username+":"+expirationTime+":"+md5Hex(username+":"+expirationTime+":"+password+":"+key))

  • username:登录的用户名。
  • password:登录的密码。
  • expirationTime:token失效的日期和时间,以毫秒表示。
  • key:用来防止修改token的一个key。

生成cookie的逻辑在org.springframework.security.web.authentication.rememberme.TokenBasedRememberMeServices中。源码如下:

String username = retrieveUserName(successfulAuthentication);
        String password = retrievePassword(successfulAuthentication);

        // If unable to find a username and password, just abort as
        // TokenBasedRememberMeServices is
        // unable to construct a valid token in this case.
        if (!StringUtils.hasLength(username)) {
            logger.debug("Unable to retrieve username");
            return;
        }

        if (!StringUtils.hasLength(password)) {
            UserDetails user = getUserDetailsService().loadUserByUsername(username);
            password = user.getPassword();

            if (!StringUtils.hasLength(password)) {
                logger.debug("Unable to obtain password for user: " + username);
                return;
            }
        }

        int tokenLifetime = calculateLoginLifetime(request, successfulAuthentication);
        long expiryTime = System.currentTimeMillis();
        // SEC-949
        expiryTime += 1000L * (tokenLifetime < 0 ? TWO_WEEKS_S : tokenLifetime);
      //生成加密后的token
        String signatureValue = makeTokenSignature(expiryTime, username, password);

        setCookie(new String[] { username, Long.toString(expiryTime), signatureValue },
                tokenLifetime, request, response);

以后客户端再次访问受限资源时,spring-security解码名为remember-me的cookie,获得有效期限和username,判断后自动在系统中认证,从而实现免登录。

这样做是存在安全隐患的,那就是在用户获取到实现记住我功能的cookie后,任何用户都可以在该cookie过期之前通过该cookie进行自动登录,即是说无法防范cookie被盗用后带来的风险。

如果希望我们的应用能够更安全一点,可以使用接下来要介绍的持久化token方式,或者不使用Remember-Me功能,因为Remember-Me功能总是有点不安全的。

2.基于persistent(持久化)token的方法

最简单的实现方式如下:

a.配置文件:

<!-- token有两种持久化方案,一种基于内存(InMemoryTokenRepositoryImpl),一种基于数据库(JdbcTokenRepositoryImpl)-->
<!-- 这里我们选择基于数据库的方式,需要注入dataSource(请自行配置DataSource)-->

  <remember-me data-source-ref="dataSource"/>

b.数据库中插入表 persistent_logins,插入表的语句是 org.springframework.security.web.authentication.rememberme.JdbcTokenRepositoryImpl 提供的,其中还定义了固定的sql语句来查询token。请自行阅读源码。

 create table persistent_logins (username varchar(64) not null default ‘‘, series varchar(64) primary key, token varchar(64) not null , last_used timestamp not null)

c.在登录页表单中加入复选框

<input type="checkbox" name="remember-me" value="true" checked="checked"/>两周之内不必登陆

这样就完成了持久化token的设置。

分析:

基于持久化token的方法采用这样的实现逻辑:

(1)用户选择了“记住我”成功登录后,将会把username、随机产生的序列号、生成的token存入一个数据库表中,同时将它们的组合生成一个cookie发送给客户端浏览器。

(2)当下一次没有登录的用户访问系统时,首先检查cookie,如果对应cookie中包含的username、序列号和token与数据库中保存的一致,则表示其通过验证,系统将重新生成一个新的token替换数据库中对应组合的旧token,序列号保持不变,同时删除旧的cookie,重新生成包含新生成的token,就的序列号和username的cookie发送给客户端。

(3)如果检查cookie时,cookie中包含的username和序列号跟数据库中保存的匹配,但是token不匹配。这种情况极有可能是因为你的cookie被人盗用了,由于盗用者使用你原本通过认证的cookie进行登录了导致旧的token失效,而产生了新的token。这个时候Spring Security就可以发现cookie被盗用的情况,它将删除数据库中与当前用户相关的所有token记录,这样盗用者使用原有的cookie将不能再登录,同时提醒用户其帐号有被盗用的可能性。

(4)如果对应cookie不存在,或者包含的username和序列号与数据库中保存的不一致,那么将会引导用户到登录页面。

从以上逻辑我们可以看出持久化token的方法比简单加密token的方法更安全,因为一旦你的cookie被人盗用了,你只要再利用原有的cookie试图自动登录一次,那么该用户相关token将会失效,同时用户可以发现自己的cookie有被盗用的可能性。

另外,可以通过复写 类org.springframework.security.web.authentication.rememberme.JdbcTokenRepositoryImpl 并配置<remember-me token-repository-ref=‘‘/>来应用自定义的数据库表,相信看过源码的同学们都做得到。

时间: 2024-10-10 08:00:44

springsecurity remember-me 功能的相关文章

Apache Shiro简单介绍

1. 概念 Apache Shiro 是一个开源安全框架,提供身份验证.授权.密码学和会话管理.Shiro 框架具有直观.易用等特性,同时也能提供健壮的安全性,虽然它的功能不如 SpringSecurity 那么强大,但是在普通的项目中也够用了. 2. 由来 Shiro 的前身是 JSecurity,2004年,Les Hazlewood 和 Jeremy Haile 创办了 Jsecurity.当时他们找不到适用于应用程序级别的合适 Java 安全框架,同时又对 JAAS 非常失望. 2004

web应用安全框架选型:Spring Security与Apache Shiro

一. SpringSecurity 框架简介 官网:https://projects.spring.io/spring-security/ 源代码: https://github.com/spring-projects/spring-security/ Spring Security 是强大的,且容易定制的,基于Spring开发的实现认证登录与资源授权的应用安全框架. SpringSecurity 的核心功能: Authentication:认证,用户登陆的验证(解决你是谁的问题) Author

[原创]SpringSecurity控制授权(鉴权)功能介绍

1.spring security 过滤器链 ? spring security中的除了用户登录校验相关的过滤器,最后还包含了鉴权功能的过滤器,还有匿名资源访问的过滤器链,相关的图解如下: 2.控制授权的相关类 ? 这里是整个spring security的过滤器链中的授权流程中控制权限的类的相关图示: ? 这里主要是从AccessDecisionVoter的投票者(译称)把信息传递给投票管理者AccessDecisionManager,最终来判断是过还是不过(也就是有没有权限).有两种可能的类

SpringMVC + Mybatis + SpringSecurity(权限控制到方法按钮) + Rest(服务) + Webservice(服务) + Quartz(定时调度)+ Lucene(搜索引擎) + HTML5 bootstrap + Maven项目构建绝对开源平台

框架整合: Springmvc + Mybatis + Shiro(权限) + REST(服务) + WebService(服务) + JMS(消息) + Lucene(搜搜引擎) + Quartz(定时调度) + Bootstrap Html5(支持PC.IOS.Android) 需要源码请加Q:3121026417   此处[源码获取地址] 框架简介: 项目Maven构建,真实大型互联网架构,做到高并发,大数据处理,整个项目使用定制化服务思想,提供模块化.服务化.原子化的方案,将功能模块进行

springsecurity启动出现org.springframework.beans.factory.parsing.BeanDefinitionParsingException: Configuration problem: You must use a 3.0 schema with Spring Security 3.0.

在换了spring-security的jar包以后启动出现org.springframework.beans.factory.parsing.BeanDefinitionParsingException: Configuration problem: You must use a 3.0 schema with Spring Security 3.0.Please update your schema declarations to the 3.0.3 schema (spring-securi

springmvc+mybatis+sql server实现简单登录功能【转】

一.源码: 1.Users.java package com.login.entity;import java.io.Serializable;public class Users implements Serializable {  /**    *     */  private static final long serialVersionUID = 1L;  private Integer id;  private String username;  private String pas

SpringSecurity数据库中存储用户、角色、资源

这几天项目中用到了SpringSecurity做登陆安全.所以在这写一下也许可以帮助一下其他人,自己也熟悉一下 SpringSecurity配置文件如下: <beans:beans xmlns="http://www.springframework.org/schema/security" xmlns:beans="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w

SpringMVC+springSecurity+flexPaper 配置--类似百度文库在线预览

背景:现在项目需要做一个类似百度文库的在线预览功能,在网上找了下很多人推荐使用FlexPaper,所以今天尝试学习了FlexPaper顺便集成到现有的框架中 由于网上目前的说的都不是很详细,所以现在记录在此,希望对需要的人有所帮助 准备:1. FlexPaper_2.2.4.zip 下载地址:http://flexpaper.devaldi.com/download/             2.swftools 下载地址:http://www.swftools.org/download.htm

【JavaWeb】SSM+SpringSecurity+EhCache+JCaptcha 完整Web基础框架(六)

Showings 我个人的项目,当前不断地在更新. 我希望做成一个好项目,同时,也是在锻炼自己的技术. 在项目中发现问题,学习知识,是比较可取的一条路子. 这样学习到的知识,虽然分散,但是都很实用,而且能够极大的加深程序设计与现实需求之间的关联. 网站地址:www.showings.com.cn Github源码[不断更新中]:https://github.com/wuxinzhe/HouseRent.git 这不算是一个多有技术含量的项目,我会不断在更新这个SAAS系统的功能,不断在完善业务逻