2017-10-19 83 views
0

我剛剛瞭解到Redis和Redisson。基本上我試圖使用Redis來存儲AcessTokens/RefreshTokens用於授權在我的應用程序。 所以我想存儲具有到期時間的令牌。我使用Spring Data Redis來存儲令牌,但沒有Api會使Map中的每個條目過期。我遇到了這個帖子Spring Data Redis Expire Key,因此擡頭看着Redisson。我嘗試了一個簡單的Maven Java項目來測試過期。 這裏的pom.xml:已過期Redisson Keys仍在Redis Cli中可見

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> 
    <modelVersion>4.0.0</modelVersion> 

    <groupId>com.bridgelabz</groupId> 
    <artifactId>redissonApp</artifactId> 
    <version>0.0.1-SNAPSHOT</version> 
    <packaging>jar</packaging> 

    <name>redissonApp</name> 
    <url>http://maven.apache.org</url> 

    <properties> 
     <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> 
    </properties> 

    <dependencies> 
     <dependency> 
      <groupId>junit</groupId> 
      <artifactId>junit</artifactId> 
      <version>3.8.1</version> 
      <scope>test</scope> 
     </dependency> 

     <dependency> 
      <groupId>org.redisson</groupId> 
      <artifactId>redisson</artifactId> 
      <version>3.3.0</version> 
     </dependency> 

    </dependencies> 
</project> 

下面是Token類

package com.bridgelabz.redissonApp; 

public class Token { 

    private String accessToken; 
    private int id; 

    public Token() { } 


    public Token(String accessToken, int id) { 

     this.accessToken = accessToken; 
     this.id = id; 
    } 

    public String getAccessToken() { 
     return accessToken; 
    } 

    public void setAccessToken(String accessToken) { 
     this.accessToken = accessToken; 
    } 

    public int getId() { 
     return id; 
    } 

    public void setId(int id) { 
     this.id = id; 
    } 

    @Override 
    public String toString() { 
     return "Token [accessToken=" + accessToken + ", id=" + id + "]"; 
    } 

} 

這裏是我的演示應用程序:

package com.bridgelabz.redissonApp; 

import java.util.concurrent.TimeUnit; 

import org.redisson.Redisson; 
import org.redisson.api.LocalCachedMapOptions; 
import org.redisson.api.RMapCache; 
import org.redisson.api.RedissonClient; 
import org.redisson.api.LocalCachedMapOptions.EvictionPolicy; 
import org.redisson.config.Config; 


public class App { 
    public static void main(String[] args) { 
     Config config = new Config(); 

     config.useSingleServer().setAddress("127.0.0.1:6379"); 

     // LocalCachedMapOptions localCachedMapOptions = 
     // LocalCachedMapOptions.defaults() 
     // .evictionPolicy(EvictionPolicy.LFU); 

     RedissonClient redisson = Redisson.create(config); 

     try { 

      RMapCache<Integer, Token> map = redisson.getMapCache("TestMap"); 

      Token myToken = new Token("abc", 1); 

      map.put(1, myToken, 10, TimeUnit.SECONDS); 

      System.out.println("Stored value with key 1 is: " + map.get(1)); 

     } 

     finally { 

      redisson.shutdown(); 

     } 

    } 
} 

運行App.java後,我得到的輸出我得到輸出爲:

SLF4J: Failed to load class "org.slf4j.impl.StaticLoggerBinder". 
SLF4J: Defaulting to no-operation (NOP) logger implementation 
SLF4J: See http://www.slf4j.org/codes.html#StaticLoggerBinder for further details. 
Stored value with key 1 is: Token [accessToken=abc, id=1] 

和公正的評論看跌期權代碼,10秒鐘後運行的應用程序給我的部分期望的結果:

LF4J: Failed to load class "org.slf4j.impl.StaticLoggerBinder". 
SLF4J: Defaulting to no-operation (NOP) logger implementation 
SLF4J: See http://www.slf4j.org/codes.html#StaticLoggerBinder for further details. 
Stored value with key 1 is: null 

但是當我運行Redis的-CLI我仍然在輸出所獲得的價值:

127.0.0.1:6379> hget TestMap 1 
"\x00\x00\x00\x00\x00\x00\x00\x00H\x00\x00\x00\x00\x00\x00\x00{\"@class\":\"com.bridgelabz.redissonApp.Token\",\"accessToken\":\"abc\",\"id\":1}" 

爲什麼不從redis中刪除密鑰?僅供參考:我的本地機器上的所有測試只包括redis。

回答

1

Redis不支持單個元素驅逐開箱即用。因此Redisson建立了自己的解決方案並將其命名爲MapCache

因此,與MapCache一樣,您現在有兩個級別的過期控制:Redis提供的關鍵級別和Redisson提供的現場級別。

在您的測試代碼:

RMapCache<Integer, Token> map = redisson.getMapCache("TestMap"); 

Token myToken = new Token("abc", 1); 

map.put(1, myToken, 10, TimeUnit.SECONDS); 

您已設置在該領域的哈希TestMap1到期。這意味着哈希沒有對它設置的期限,而是對其中一個字段設置了到期日。因此,當您使用redis-cli來查找時,散列仍然存在。當Redisson到期過程開始時,它最終會消失。

0

我不知道推理,但是當我在Spring Web App中使用相同的代碼但未在簡單的Java應用程序中工作時,密鑰已過期。 這裏是TokenDaoImpl.java代碼:

import java.io.IOException; 
import java.util.UUID; 
import java.util.concurrent.TimeUnit; 

import javax.annotation.PostConstruct; 
import javax.annotation.PreDestroy; 

import org.apache.log4j.Logger; 
import org.redisson.Redisson; 
import org.redisson.api.RMapCache; 
import org.redisson.api.RedissonClient; 
import org.redisson.config.Config; 
import org.springframework.stereotype.Repository; 

import com.bridgelabz.restApiDemo.entity.Token; 

@Repository 
public class TokenDaoImpl implements TokenDao { 

    Logger logger = Logger.getLogger(TokenDaoImpl.class); 

    RedissonClient redissonClient; 

    RMapCache<String, Token> tokenMap; 

    @PostConstruct 
    public void initRedisson() { 

     Config config = null; 
     try { 
      config = Config.fromJSON("{\n" + " \"singleServerConfig\":{\n" 
        + "  \"idleConnectionTimeout\":10000,\n" + "  \"pingTimeout\":1000,\n" 
        + "  \"connectTimeout\":10000,\n" + "  \"timeout\":3000,\n" + "  \"retryAttempts\":3,\n" 
        + "  \"retryInterval\":1500,\n" + "  \"reconnectionTimeout\":3000,\n" 
        + "  \"failedAttempts\":3,\n" + "  \"password\":null,\n" 
        + "  \"subscriptionsPerConnection\":5,\n" + "  \"clientName\":null,\n" 
        + "  \"address\": \"redis://127.0.0.1:6379\",\n" 
        + "  \"subscriptionConnectionMinimumIdleSize\":1,\n" 
        + "  \"subscriptionConnectionPoolSize\":50,\n" + "  \"connectionMinimumIdleSize\":10,\n" 
        + "  \"connectionPoolSize\":64,\n" + "  \"database\":0,\n" 
        + "  \"dnsMonitoring\":false,\n" + "  \"dnsMonitoringInterval\":5000\n" + " },\n" 
        + " \"threads\":0,\n" + " \"nettyThreads\":0,\n" + " \"codec\":null,\n" 
        + " \"useLinuxNativeEpoll\":false\n" + "}"); 
     } catch (IOException e1) { 
      logger.info("******Inside Config Catch"); 
      e1.printStackTrace(); 
     } 

     logger.info("**************Config Object" + config); 

     redissonClient = Redisson.create(config); 

     tokenMap = redissonClient.getMapCache("tokenMap"); 
    } 

    @PreDestroy 
    public void redissonShutdown() { 
     redissonClient.shutdown(); 
    } 

    public TokenDaoImpl() { 

    } 

    @Override 
    public Token generateToken(String tokenType, int uid) { 

     // first generate the token 
     String tokenValue = UUID.randomUUID().toString().replaceAll("-", ""); 
     logger.info("******Generated access token is " + tokenValue); 

     Token token = new Token(tokenType, tokenValue, uid); 

     // save the token in redis cache with expiration depending upon tokenType 
     switch (tokenType) { 
     case "accessToken": 
      tokenMap.put(tokenValue, token, 15, TimeUnit.MINUTES); 
      break; 

     case "refreshToken": 
      tokenMap.put(tokenValue, token, 30, TimeUnit.MINUTES); 
      break; 

     case "forgotToken": 
      tokenMap.put(tokenValue, token, 30, TimeUnit.MINUTES); 
      break; 

     default: 
      logger.info("**********Please specify correct token type!"); 
      break; 
     } 

     return token; 
    } 

    @Override 
    public boolean verifyToken(String tokenValue) { 

     Token token = tokenMap.get(tokenValue); 

     logger.info("******Token from redis for verification" + token); 

     if (token != null) { 
      return true; 
     } 

     return false; 
    } 

} 

此前,運行Java應用程序的時候,我在其中具有MapName_session_timeout redis-其中一個我創建即TokenMap和新映射表地圖,甚至之後的鍵將保持指定的到期日。現在所有的鍵都被正確刪除。