春-Redisのセッションのカスタムキーと有効期限

分散アプリケーションのために、遭遇した問題は、ストレージのセッションの開始で、いくつかのソリューションは大体あります

  • それはなどRedisのは、MySQL、など、あなたが保存したいセッションに保存することができ、使用スプリングセッション
  • 使用JWTsが、それはトークンの正当性を検証するためのアルゴリズムを使用して、期限が切れている、とトークンが偽造することができない、情報も改ざんすることはできません

本論文では、主に春セッションRedisのは、セッション、実装の原則を保存有効期限の変更、およびその他のカスタムキーに使用すると述べました

簡単に使用するバネのセッション内部システムまたはすることができ、が、ユーザーの量が出てくる場合には、費用対効果のない、素晴らしいセッションRedisのストレージのオーバーヘッドを持っています。

使用

話に簡単に使用するのは簡単、鉛パックは、configure、注釈を追加。このような以下の3つのステップとして、我々は、使用Redisのセッションを設定し

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>

<dependency>
    <groupId>org.springframework.session</groupId>
    <artifactId>spring-session-data-redis</artifactId>
</dependency>
spring.redis.host=localhost  
# 其它 超时,端口,库,连接池,集群,就自己去找了
@EnableRedisHttpSession(maxInactiveIntervalInSeconds= 1800)

テスト:のgetSessionセッションは、私たちは結果を見てたら、インターフェースで呼び出すことがある場合、それが作成されていないため

@GetMapping("/sessionId")
public String sessionId(){
    HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
    HttpSession session = request.getSession();
    session.setAttribute("user","sanri");
    return session.getId();
}

これは、次の結果を格納します

hash spring:session:sessions:e3d4d84f-cc9f-44d5-9199-463cd9de8272
string spring:session:sessions:expires:e3d4d84f-cc9f-44d5-9199-463cd9de8272
set spring:session:expirations:1577615340000

セッションのいくつかの属性情報と、ユーザによっていくつかの基本的な情報セットのハッシュを格納するための第1の構成

CREATIONTIME作成されました

lastAccessedTime最終アクセス時間

長いmaxInactiveIntervalが満了すると、デフォルトでは30分、記憶された第2の値です。

sessionAttr:ユーザーは、このプロパティにsession.setAttributeを通過するために私のセットです

2番目の文字列の構造は、それが何の価値、唯一のTTL情報を持っていない、ライブにはまだ長いキーのこのグループを特定、TTLを使用して表示することができます

第三セット構造は、期限切れのキーを保存する必要があります

原則

説明:ソースがそれを読んで、これは達成するためにはるかに困難ではないですが、私はやった、唯一のフィルタアプリケーションです。

まず、インターネットから学んだ、それはセッションがRedisの中に保存されている達成するためにフィルタを使用し、目標はそれを格納する方法であるフィルタを確認することですので、各要求は、Redisのからセッションを取得することですが、また、どのようにそれを取得します。

私たちは、その唯一の入り口から見ることができ@EnableRedisHttpSession、それが導入されて、ビューにRedisHttpSessionConfigurationから継承されたタイマーのターンを、SpringHttpSessionConfigurationあなたは注意することができ、RedisHttpSessionConfiguration豆作成RedisOperationsSessionRepositoryそれは、セッションを保存するためのコアクラスがあるので、リポジトリは意味のリポジトリです。そのフィルタそれは見てどこでSpringHttpSessionConfiguration、それは確かに、フィルタ、春・セッション・データのRedisで行わ抽象的な概念であり、具体的な実装、それはパックの春のセッションを管理するために使用されたスプリング・セッション・コアパッケージに属していることここで作成した、と彼女はそれを作成する見ることができるSessionRepositoryFilterフィルタを、次のようにフィルタを見て保存しました。

SessionRepositoryFilter

フィルタは、使用して、いくつかの方法のdoFilterビューdoFilterメソッド、春でなければなりませんOncePerRequestFilterdoFilterInternal方法を表示するために、最終的に達成するためにdoFilterInternalを呼び出して、のdoFilterにパッケージの層を

実装は、要求パッケージは確かのgetSessionを書き換えられますので、あなたが見ることができるように、我々は一般的に、でrequest.getSession()から、一般的にセッションを取り、パッケージング要求と応答レスポンスを充填した設計にどのように使われるかをgetSessionメソッドからの眺めRedisのは、セッションを取得します。

関連する既存のセッションのすべての前で判決、ここで重要な情報

S session = SessionRepositoryFilter.this.sessionRepository.createSession();

SessionRepositoryは、ここで私たちがセッションにアクセスするために使用するものであるRedisOperationsSessionRepositoryビュー方式のCreateSessionへ

RedisOperationsSessionRepository

// 这里保存了在 redis 中 hash 结构能看到的数据
RedisSession redisSession = new RedisSession();

this(new MapSession());
this.delta.put(CREATION_TIME_ATTR, getCreationTime().toEpochMilli());
this.delta.put(MAX_INACTIVE_ATTR, (int) getMaxInactiveInterval().getSeconds());
this.delta.put(LAST_ACCESSED_ATTR, getLastAccessedTime().toEpochMilli());
this.isNew = true;
this.flushImmediateIfNecessary();

redisFlushModeがある場合flushImmediateIfNecessary方法では、IMMEDIATEパターン、それはすぐにRedisのにセッションが、保存デフォルトの設定では、それはそれをのRedisに格納されON_SAVE、である、我々はときようやくで、フィルタ法doFilterInternal先頭に戻りますあります

wrappedRequest.commitSession();

それは私たちが行くとコア声明文を参照して、セッションがRedisのに格納されていることをここにいました

SessionRepositoryFilter.this.sessionRepository.save(session);
session.saveDelta();
if (session.isNew()) {
    String sessionCreatedKey = getSessionCreatedChannel(session.getId());
    this.sessionRedisOperations.convertAndSend(sessionCreatedKey, session.delta);
    session.setNew(false);
}

ここでハッシュ構造のセットに入るとsaveDelta、

getSessionBoundHashOperations(sessionId).putAll(this.delta);

最後の行は、有効期限を設定し、現在のキーセット、ビューを読者に参加しました。

RedisOperationsSessionRepository.this.expirationPolicy
                    .onExpirationUpdated(originalExpiration, this);

いくつかのパラメータを変更します。

実際のビジネスは、あなたが私たちのビジネスのニーズを達成するために、いくつかのパラメータを変更する必要があり、最も一般的な要件は、セッションの有効期限を変更することで、EnableRedisHttpSessionノートは、次のようないくつかの基本的な構成が提供されています

maxInactiveIntervalInSeconds 最大过期时间,默认 30 分钟 
redisNamespace 插入到 redis 的 session 命名空间,默认是 spring:session 
cleanupCron 过期 session 清理任务,默认是 1 分钟清理一次
redisFlushMode 刷新方式 ,其实在上面原理的 flushImmediateIfNecessary 方法中有用到,默认是 ON_SAVE

redisNamespaceが変更されると確信して、変更が他のプロジェクトには影響しません、私たちのプロジェクトの名前の一般的な使用は、追加のキーワードセッションキーの操作を行い、セッション情報が、このプロジェクトであることを示しています。

しかし、このような構成は、最大有効期限は十分ではなかった、そこには、代わりにコードを書くのは、設定ファイルに追加しましたが、機能がないプレースホルダに戻って提供する必要がありRedisOperationsSessionRepository、作成、maxInactiveIntervalInSecondsの最終的な構成をセットまたはこのBeanに行くために、私たちはこのBeanを作成するプロセスをカバーすることができ、次のように、書き換えmaxInactiveIntervalInSeconds取得プロセスは、解決されます

@Autowired
RedisTemplate sessionRedisTemplate;

@Autowired
ApplicationEventPublisher applicationEventPublisher;

@Value("${server.session.timeout}")
private int sessionTimeout = 1800;

@Primary        // 使用 Primary 来覆盖默认的 Bean 
@Bean
public RedisOperationsSessionRepository sessionRepository() {
    RedisOperationsSessionRepository sessionRepository = new RedisOperationsSessionRepository(sessionRedisTemplate);
    // 这里要把原来的属性引用过来,避免出错 ,可以引用原来的类并复制属性 ;像 redisNamespace,redisFlushMode 都要复制过来
    return sessionRepository;
}

問題のRedisのシーケンスがあり、デフォルトではJDKオブジェクトのシリアル化を使用することで、逆シリアル化を低下させない表示されるフィールドまたはフィールドを追加する傾向があるので、シリアライズは、プロジェクト場合は、キャッシュを変更する必要がありそれは、オブジェクトのシリアル化のために使用されてきた、それはあなたが建物に行くために、単一のredisTemplateとのセットを書きたい直面しているRedisOperationsSessionRepository設定時間redisTemplateを

もう一つは、キー値で生成されたUUIDフォームをのRedis、ユーザがログインする場所である現在の鍵は、私たちが実際にどのようなユーザーを示すために、userId_ip_timeのそのキーの形を変更することができることを知っている方法はありませんされています私は(彼らは変化するであろうが、実際に使用されるが、そこにピットがありません)遊んでいたので、前に記録されているIPした時刻:

以前のソースコード分析した後、セッションを作成し、Redisのに保存されたことはあるRedisOperationsSessionRepositoryのCreateSession方法が、ここでは書き込みが死んで建設RedisSessionは空ですが、RedisSessionは、最終的な内部クラス、デフォルトへのアクセス、また新しいMapSessionデフォルトの建設でありますそして最後にidはUUIDを使用するように、我々は正常にログインするためにセッションキーを変更する必要があり、何も実際には、ここで作成したセッションは、ユーザーがログインの状態が必ずしも成功しているではありません、行わないことができるようだが、幸いRedisOperationsSessionRepository、findById方法を提供し、我々は上記の、最初のRedisSessionで大騒ぎチェックアウト行い、その後、反射を得ることができMapSession、その後、気づいMapSession自体も法changeSessionIdを提供し、IDを変更することができ、我々が正常に書き込み、その後、SETID修正セッションIDログインを呼び出すことができます次のように戻って、そしてRedisSessionこのコードは同じパッケージのコードであることが必要です。

package org.springframework.session.data.redis;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.session.MapSession;
import org.springframework.stereotype.Component;
import org.springframework.util.ReflectionUtils;

import java.lang.reflect.Field;

@Component
public class SessionOperation {
    @Autowired
    private RedisOperationsSessionRepository redisOperationsSessionRepository;

    public void loginSuccess(String userId){
        String sessionId = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest().getSession().getId();
        RedisOperationsSessionRepository.RedisSession redisSession = redisOperationsSessionRepository.findById(sessionId);
        Field cached = ReflectionUtils.findField(RedisOperationsSessionRepository.RedisSession.class, "cached");
        ReflectionUtils.makeAccessible(cached);
        MapSession mapSession = (MapSession) ReflectionUtils.getField(cached, redisSession);
        mapSession.setId("userId:1");
        redisOperationsSessionRepository.save(redisSession);
    }
}

送信元アドレス:https://gitee.com/sanri/example/tree/master/test-redis-session

リトル・プロモーション

書き込みは容易ではない、私はgiteeポイントスター、フォーク、プット・バグへの歓迎、オープンソースソフトウェアのサポートを期待して、私のガジェット。

エクセル共通インポートとエクスポート、サポートエクセル数式
のブログのアドレス:https://blog.csdn.net/sanri1993/article/details/100601578
gitee:https://gitee.com/sanri/sanri-excel-poi

ガジェットは、データベースからコードを生成、テンプレートコードを使用し、いくつかのプロジェクトは、多くの場合に使用することができます
ブログのアドレス:https://blog.csdn.net/sanri1993/article/details/98664034
gitee:https://gitee.com/ sanri / sanri-ツール-達人

おすすめ

転載: www.cnblogs.com/sanri1993/p/12116996.html