Use redis to manage the user login session

  • 2020-06-15 10:29:08
  • OfStack

Login and cookie cache

For cookie used for login, there are two common ways to store login information in cookie: a signature (signed) cookie and a token (token) cookie.

Signing cookie typically stores the user name, possibly ID, the time of the last successful login, and any other information the site finds useful. In addition to the user's information, signature cookie contains a signature that the server can use to verify that the sent information is unchanged (such as changing the login username in cookie to another customer).

Token cookie stores a string of random bytes as a token in cookie, and the server can look up the owner of the token in the database based on the token. The following table shows the advantages and disadvantages of signature cookie and token cookie.

cookie类型 优点 缺点
签名cookie 验证cookie所需的1切信息都存储在cookie里面。cookie可以包含额外的信息(additional information),并且对这些信息进行签名也很容易 正确地处理签名很难。很容易忘记对数据进行签名,或者忘记验证数据的签名,从而造成安全漏洞
令牌cookie 添加信息非常容易。cookie的体积非常小,因此移动端和速度较慢的客户端可以更快地发送请求 需要在服务器中存储更多信息。如果使用的是关系数据库,那么载入和存储cookie的代价可能会更高

Here is an example written in java


import java.util.ArrayList;
import java.util.Set;
import redis.clients.jedis.Jedis;
public class Login {
 public String checkToken(Jedis conn,String token){
  return conn.hget("login:", token);
 }
 public void updateToken(Jedis conn,String token,String user,String item){
  long time=System.currentTimeMillis()/1000;
  conn.hset("login:", token, user);// Maintains the mapping between token and user 
  conn.zadd("recent:", time, token);// Save the token last 1 The time of the second occurrence 
  if(item!=null){
   conn.zadd("viewd:"+token, time, item);// Based on this token, set the name of the item that the user accesses at this timestamp 
   conn.zremrangeByRank("viewd:"+token, 0, -26);// Remove existing user records and keep only those that the user has browsed 25 A commodity. 
   conn.zincrby("viewd:", -1, item);
  }
 }
 public class CleanSessionsThread extends Thread{
  private Jedis conn;
  private int limit;
  private boolean quit;
  public CleanSessionsThread(int limit) {
   // TODO Auto-generated constructor stub
   this.conn=new Jedis("localhost");
   conn.select(15);
   this.limit=limit;
  }
  public void quit(){
   quit=true;
  }
  @Override
  public void run() {
   // TODO Auto-generated method stub
   while(!quit){
    long size=conn.zcard("recent:");// Determine the number of people online according to the login time 
    if(size<=limit){
     try {
      Thread.sleep(1000);
     } catch (InterruptedException e) {
      // TODO Auto-generated catch block
      e.printStackTrace();
     }
    }else{
     long endIndex=Math.min(size-limit,100);
     Set<String> tokensSet=conn.zrange("recent:", 0, endIndex-1);
     String[] tokens=tokensSet.toArray(new String[tokensSet.size()]);
     ArrayList<String> sessionKeys=new ArrayList<>();
     for(String token:tokens){
      sessionKeys.add("viewd:"+token);
     }
     conn.del(sessionKeys.toArray(new String[sessionKeys.size()]));
     conn.hdel("login:", tokens);
     conn.zrem("recent:", tokens);
    }
   }
  }
 }
}

Related articles: