在上一次写的文章中,为大家说到了如何动态的从数据库加载用户、角色、权限信息,从而实现登录验证及授权。在实际的开发过程中,我们通常会有这样的一个需求:当用户多次登录失败的时候,我们应该将账户锁定,等待一定的时间之后才能再次进行登录操作。

一、基础知识回顾

要实现多次登录失败账户锁定的功能,我们需要先回顾一下基础知识:

  • Spring Security 不需要我们自己实现登录验证逻辑,而是将用户、角色、权限信息以实现UserDetails和UserDetailsService接口的方式告知Spring Security。具体的登录验证逻辑Spring Security 会帮助我们实现。
  • UserDetails接口中有一个方法叫做isAccountNonLocked()用于判断账号是否被锁定,也就是说我们应该通过该方法对应的set方法setAccountNonLocked(false)告知Spring Security该登录账户被锁定。
  • 那么应该在哪里判断账号登录失败的次数并执行锁定机制呢?当然是我们之前文章给大家介绍的《自定义登录成功及失败结果处理》的AuthenticationFailureHandler。

建议您先阅读本文,如果您对本文的实现过程感到迷惑,建议您再翻看本号之前的相关内容。

二、实现多次登录失败锁定的原理

一般来说实现这个需求,我们需要针对每一个用户记录登录失败的次数nLock和锁定账户的到期时间releaseTime。具体你是把这2个信息存储在mysql、还是文件中、还是redis中等等,完全取决于你对你所处的应用架构适用性的判断。具体的实现逻辑无非就是:

  • 登陆失败之后,从存储中将nLock取出来加1。
  • 如果nLock大于登陆失败阈值(比如3次),则将nLock=0,然后设置releaseTime为当前时间加上锁定周期。通过setAccountNonLocked(false)告知Spring Security该登录账户被锁定。
  • 如果nLock小于等于1,则将nLock再次存起来。
  • 在一个合适的时机,将锁定状态重置为setAccountNonLocked(true)。

这是一种非常典型的实现方式,笔者向大家介绍一款非常有用的开源软件叫做:ratelimitj。这个软件的功能主要是为API访问进行限流,也就是说可以通过制定规则限制API接口的访问频率。那恰好登录验证接口也是API的一种啊,我们正好也需要限制它在一定的时间内的访问次数。

三、具体实现

首先需要将ratelimitj通过maven坐标引入到我们的应用里面来。我们使用的是内存存储的版本,还有redis存储的版本,大家可以根据自己的应用情况选用。

        <dependency>
<groupId>es.moki.ratelimitj</groupId>
<artifactId>ratelimitj-inmemory</artifactId>
<version>0.4.1</version>
</dependency>

之后通过继承SimpleUrlAuthenticationFailureHandler ,实现onAuthenticationFailure方法。该实现是针对登录失败的结果的处理,在我们之前的文章中已经讲过。

@Component
public class MyAuthenticationFailureHandler extends SimpleUrlAuthenticationFailureHandler { @Autowired
UserDetailsManager userDetailsManager; //规则定义:1小时之内5次机会,就触发限流行为
Set<RequestLimitRule> rules =
Collections.singleton(RequestLimitRule.of(1 * 60, TimeUnit.MINUTES,5));
RequestRateLimiter limiter = new InMemorySlidingWindowRequestRateLimiter(rules); @Override
public void onAuthenticationFailure(HttpServletRequest request,
HttpServletResponse response,
AuthenticationException exception)
throws IOException, ServletException { String userId = //从request或request.getSession中获取登录用户名
//计数器加1,并判断该用户是否已经到了触发了锁定规则
boolean reachLimit = limiter.overLimitWhenIncremented(userId); if(reachLimit){ //如果触发了锁定规则,通过UserDetails告知Spring Security锁定账户
user.setAccountNonLocked(false);
userDetailsManager.updateUser(user);
SysUser user = (SysUser) userDetailsManager.loadUserByUsername(userId);
} //此处省略通过response做json或html响应
}
}
  • 核心实现注意看代码中的注释
  • 代码中的SysUser为UserDetails的实现类,如果不知道如何实现请参考本号之前的文章
  • userDetailsManager被用于管理UserDetails信息,通过改变UserDetails改变Spring Security验证行为。

四、重置锁定状态的时机

user.setAccountNonLocked(true);

重置锁定状态很简单,就是上面的代码。但是更重要的是如何选择重置锁定状态的时机。笔者能想到几种方案如下

  • 下一次登陆的时候,自定义过滤器,加在Spring Boot过滤器链最前端做锁定状态重置的判断。
  • 当登录账户被锁定之后,之后用户的每一次登录都会抛出LockedException。我们完全可以通过Spring Boot的全局异常捕获机制,在其中捕获LockedException,并做锁定状态的判断及重置行为。
  • 写一个Spring 的定时器轮询,当然这是最差的方案。

期待您的关注

Spring Security之多次登录失败后账户锁定功能的实现的更多相关文章

  1. Spring Security 入门(1-3-1)Spring Security - http元素 - 默认登录和登录定制

    登录表单配置 - http 元素下的 form-login 元素是用来定义表单登录信息的.当我们什么属性都不指定的时候 Spring Security 会为我们生成一个默认的登录页面. 如果不想使用默 ...

  2. 七:Spring Security 前后端分离登录,非法请求直接返回 JSON

    Spring Security 前后端分离登录,非法请求直接返回 JSON 解决方案 在 Spring Security 中未获认证的请求默认会重定向到登录页,但是在前后端分离的登录中,这个默认行为则 ...

  3. spring security 动态 修改当前登录用户的 权限

    1.前言 spring security 可以获取当前登录的用户信息,同时提供了接口 来修改权限列表信息 , 使用这个方法 ,可以动态的修改当前登录用户权限. 那么问题来了... 如果我是管理员 ,如 ...

  4. SpringCloud微服务实战——搭建企业级开发框架(四十):使用Spring Security OAuth2实现单点登录(SSO)系统

    一.单点登录SSO介绍   目前每家企业或者平台都存在不止一套系统,由于历史原因每套系统采购于不同厂商,所以系统间都是相互独立的,都有自己的用户鉴权认证体系,当用户进行登录系统时,不得不记住每套系统的 ...

  5. Spring Security OAuth2 SSO 单点登录

    基于 Spring Security OAuth2 SSO 单点登录系统 SSO简介 单点登录(英语:Single sign-on,缩写为 SSO),又译为单一签入,一种对于许多相互关连,但是又是各自 ...

  6. spring security实现记录用户登录时间等信息

    目录 spring security实现记录用户登录时间等信息 一.原理分析 二.实现方式 2.1 自定义AuthenticationSuccessHandler实现类 2.2 在spring-sec ...

  7. linux尝试登录失败后锁定用户账户的两种方法

    linux尝试登录失败后锁定用户账户的两种方法 更新时间:2017年06月23日 08:44:31   作者:Carey    我要评论   这篇文章主要给大家分享了linux尝试登录失败后锁定用户账 ...

  8. Spring Security默认的用户登录表单 页面源代码

    Spring Security默认的用户登录表单 页面源代码 <html><head><title>Login Page</title></hea ...

  9. Spring Security之用户名+密码登录

    自定义用户认证逻辑 处理用户信息获取逻辑 实现UserDetailsService接口 @Service public class MyUserDetailsService implements Us ...

随机推荐

  1. 像使用SQL一样对List对象集合进行排序

    在开始之前,我先卖个关子提一个问题:假设我们有一个Movie类,这个类有三个成员变量分别是starred(是否收藏), title(电影名称), rating(评分).你知道怎么对一个Movie对象组 ...

  2. Newtonsoft—Json.NET常用方法简述

    Json.NET常用方法汇总(可解决日常百分之90的需求) 0.Json.NET基础用法 首先去官网下载最新的Newtonsoft.Json.dll(也可以使用VS自带的NuGet搜索Json.NET ...

  3. Python字典及相关操作(内含例题)

    Python字典类型 今天将会介绍一种在python中十分常见的组合数据类型——字典 通过一些实例来理解字典中的常规操作 什么是字典类型? 列表中查找是通过整数的索引(元素在列表中的序号)来实现查找功 ...

  4. POJ2431 优先队列+贪心 - biaobiao88

    以下代码可对结构体数组中的元素进行排序,也差不多算是一个小小的模板了吧 #include<iostream> #include<algorithm> using namespa ...

  5. github 下载子目录内容 亲测可用!

    下载我的LYBTouchID项目的Kit目录内容 (1)在github上点开这个目录,浏览器地址栏可以得到这个地址 https://github.com/Liuyubao/LYBTouchID/tre ...

  6. 学习笔记59_python字符串处理

    python中,字符串可以使用 '或"括起来 1. 要想写成  "hellow "aaaa"  ",在python中,可以"hellow ' ...

  7. 【PyTorch教程】P2. Python编辑器的选择、安装及配置

    温馨提示:为了更好的教程体验,提供视频.阅读地址 Youtube: https://www.youtube.com/playlist?list=PLgAyVnrNJ96CqYdjZ8v9YjQvCBc ...

  8. 入门react

    前言:今天翻到了好久之前学习react时的笔记,拿出来记录一下以免忘掉,里面主要是记录了安装环境,创建项目,启动项目,jsx,组件介绍,组件通信,多层嵌套,路由搭建,路由传参,redux.记录的比较浅 ...

  9. 『题解』POJ1753 Flip Game

    题目传送门 题意描述 有\(4 \times 4\)的正方形,每个格子要么是黑色,要么是白色,当把一个格子的颜色改变(黑\(\to\)白 或 白\(\to\)黑)时,其周围上下左右(如果存在的话)的格 ...

  10. [转载]2.4 UiPath循环活动While的介绍和使用

    一.While循环的介绍 先判断条件是否满足, 如果满足, 再执行循环体, 直到判断条件不满足, 则跳出循环 二.While循环在UiPath中的使用 1. 打开设计器,在设计库中新建一个Flowch ...