preface

Today at Moyu nuggets, I saw an article, ‘Ali interviewer asked me: Ten minutes login 5 consecutive failure, need to wait 30 minutes to login ‘, feel very interesting, although it is a common demand, but the solution very much, so he half an hour to draw a diagram, write a few lines, pseudo code to solve this demand, after all the CRUD also pretty boring, everyday is not the best solution, only for discussion to learn each other, I want you to spray lightly.

The original link

Interviewer Ali asked me: How can I design the login interface? If I fail to log in 5 times within 10 minutes, I have to wait 30 minutes before I can log in?

Directly above

The illustration

  • The login request
  • Verify lock bold. Lock returns that too many login attempts have been locked
  • The password of the authentication account is not locked
  • Number of authentication failures Count times =5. Lock the cache
  • Verification succeeded in deleting the count cache

Code implementation

package com.demo.login; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.redis.core.RedisTemplate; import org.springframework.stereotype.Service; import java.util.concurrent.TimeUnit; /** * @auther public class LoginService {@autoWired private RedisTemplate<String Integer> redisTemplate; private static final String FAIL_COUNTER = "user_login_fail_counter"; private static final String FAIL_LOCK = "user_login_fail_lock"; /** * @param username * @param password * @return */ public String login(String username, String password) { // 1. Boolean lock = isLock(username); If (lock) {// Get expiration time long t = unlockTime(username); Return "Login authentication failed too many times, please" + t + "try again in minutes!" ; } boolean check = loginCheck(username, password); if (! check) { setCheckFailCounter(username); Return "Login failed!" ; } deleteLoginFailCounter(username); Return "Login succeeded "; } /** * @param username */ public void setCheckFailCounter(String username) {String key = String. Join (":", FAIL_COUNTER, username); Integer count = redisTemplate.opsForValue().get(key); redisTemplate.opsForValue().increment(key); If (count == null) {redistemplate. expire(key, 10, timeunit.minutes); } if (count.intValue() == 5) {// Fail to set cache lock for five times; }} /** * @param username */ public void deleteLoginFailCounter(String username) { redisTemplate.delete(String.join(":", FAIL_COUNTER, username)); } @param username */ public void lock(String username) {String key = String. Join (":", FAIL_LOCK, username); redisTemplate.opsForValue().set(key, 1, 30, TimeUnit.MINUTES); } @param username * @return */ public Boolean isLock(String username) {return redisTemplate.hasKey(String.join(":", FAIL_LOCK, username)); } @param username * @return */ public long unlockTime(String username) {String key = String. Join (":",  FAIL_LOCK, username); return redisTemplate.opsForValue().getOperations().getExpire(key, TimeUnit.MINUTES); } public Boolean loginCheck(String username, String username, String username, String username, String username) String password) {// Verify that the account password is correct omit... return false; }}Copy the code

conclusion

Use two caches, one login failure count cache and one lock cache, trigger count cache when count reaches 5, continue count until count reaches 5, and clear count cache until success reaches 5. The advantage is that the redis space is not much, each user has two keys, the full use of expiration mechanism and redis increment, on the basis of the original demand can also remind the user how long can log in again. I hope we can communicate with each other and make progress together.

I write other login related articles

Understand user login verification process (attached picture) – Juejin (juejin. Cn)

Quickly build a gateway service, dynamic routing, authentication will see (including flow chart) – Juejin (cn)