当前位置: 移动技术网 > IT编程>开发语言>Java > Spring Security之多次登录失败后账户锁定功能的实现

Spring Security之多次登录失败后账户锁定功能的实现

2019年11月28日  | 移动技术网IT编程  | 我要评论

file

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

一、基础知识回顾

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

  • 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 的定时器轮询,当然这是最差的方案。

    期待您的关注

  • 向您推荐博主的系列文档:
  • 本文转载注明出处(必须带连接,不能只转文字):。

如对本文有疑问, 点击进行留言回复!!

相关文章:

验证码:
移动技术网