單點登入與訊息佇列以及在J2EE中的實現方案
前言
很久都沒有寫部落格了,這次為大家簡單介紹兩個在WEB開發中經常使用的概念——單點登入和訊息佇列以及具體到J2EE中的一些實現方案。本文原創性的工作比較少,主要是一些總結概括和自己的理解。
單點登入SSO
SSO的業務場景
所謂單點登入就是在一個站點登入之後可以授信給其他站點,這樣就可以做到一次登入,到處操作。單點登入的實質就是安全上下文(Security Context)或憑證(Credential)在多個應用系統之間的傳遞或共享。
大部分的網站採用Cookie作為登入的一種簡單實現方案,在同一個一級域名下面,這樣做並無問題,不需要對各個子系統分別驗證。但是Cookie無法跨域傳遞。將使用者的登入、憑證取得等解耦處理單獨作為一個子系統是合理的選擇。
SSO的核心要素
- 共享同一個身份認證系統,也就是說所有站點的身份驗證操作在同一個系統下完成
- 每個子系統從共同的身份認證系統中取得使用者憑證,包含使用者的身份、許可權資訊等
示意圖如下:
SSO的一種簡單實現方案
下面以採用Cookie的一種方案為例來解釋:
我們首先定義授信伺服器A,受信伺服器B,客戶C;當前的業務是B需要驗證C的身份。需要注意的是B和C都會保有session來記錄C的登入狀態,均會向C 的Header中寫入對應自己域名的Cookie以儲存憑證資訊。Cookie中含有tokenId來標示C,也就是說對於A和B他們的Cookie中對應於同一個C,其tokenId應該一致。
C向B發起請求後,會有以下幾種情形:
- B含有session,C含有Cookie,且session和Cookie中的token一致,那麼不需要向A求助
- C中對於B無Cookie或Cookie過期或session與Cookie不一致,將向A發起請求。之後根據A的情形,有以下情況:
- A中session與C中Cookie的token一致,重新生成憑證資訊返回給B,B重新寫入Cookie與session
- A中Cookie過期或資訊不一致,將重定向到登入頁面
- 對於登入情形,A將更新Cookie與session,然後C再向B發起請求,這時就會變成2中第一種情況,導致A和B的資訊完成同步。
訊息佇列
MQ的業務場景
訊息佇列本身是簡單的,可以直接看做一個佇列,重點是如何定義儲存在佇列中的資料格式,以滿足我們對應的操作需求。MQ常常應用於那些併發量大而對於實時性要求不高的情況。舉個例子,比如一個使用者量較大的社交網站的評論釋出,為什麼這麼說呢?對於這個任務,佇列中只用儲存評論相關資訊,對於從佇列中取的一方,只需要進行插入操作,符合前面所說的併發量大且可以有延時,同時並不難實現。
MQ的兩種模式
訊息佇列在WEB開發中主要有兩種模式:
- 生產者/消費者模式:對於一則訊息,只有一個消費者執行緒會去處理它,適用於我們上面所說的評論系統
- 釋出者/訂閱者模式:對於所有訂閱者,它可以讀取所有在它加入之後釋出的訊息
在J2EE中加入訊息佇列,我個人認為應該是這樣的:對於特定的HTTP請求,呼叫生產者/釋出者的介面,入隊必要訊息,這個並不困難。大有蹊蹺的我覺得在於處理訊息的一方,可以實現listener將其交由容器管理,也可以自己開闢池來排程。舉例來說明,對於前者Spring-redis實現的pub/sub模式佇列就是直接在配置檔案中設定RedisListener的實現類,對於後者,你可以直接獨立出來寫離線指令碼來監聽佇列。
MQ的實現方案
目前業界有比較成熟的MQ解決產品,如下:
- RabbitMQ
- ActiveMQ
- kafka
- Redis
MQ的Spring+Redis實現簡單示例
在Pom.xml中加入以下依賴
<dependency> <groupId>org.springframework.data</groupId> <artifactId>spring-data-redis</artifactId> <version>1.4.2.RELEASE</version> </dependency> <dependency> <groupId>org.apache.commons</groupId> <artifactId>commons-pool2</artifactId> <version>2.3</version> </dependency> <dependency> <groupId>redis.clients</groupId> <artifactId>jedis</artifactId> <version>2.6.2</version> </dependency>
在ApplicationContext.xml的頭部插入schema
xmlns:redis="http://www.springframework.org/schema/redis"
在ApplicationContext中加入Redis的配置
<!-- 配置redis池,依次為最大例項數,最大空閒例項數,(建立例項時)最大等待時間,(建立例項時)是否驗證 --> <bean id="jedisPoolConfig" class="redis.clients.jedis.JedisPoolConfig"> <property name="maxTotal" value="${redis.maxTotal}"/> <property name="maxIdle" value="${redis.maxIdle}"/> <property name="maxWaitMillis" value="${redis.maxWaitMillis}"/> <property name="testOnBorrow" value="${redis.testOnBorrow}"/> </bean> <!-- 配置資料來源--> <bean id="redisConnectionFactory" class="org.springframework.data.redis.connection.jedis.JedisConnectionFactory"> <property name="hostName" value="127.0.0.1"></property> <property name="port" value="6379"></property> <property name="usePool" value="true"></property> </bean> <!-- 配置資料操作 --> <bean id="redisTemplate" class="org.springframework.data.redis.core.RedisTemplate"> <property name="connectionFactory" ref="redisConnectionFactory"></property> </bean> <bean id="jdkSerializer" class="org.springframework.data.redis.serializer.JdkSerializationRedisSerializer" /> <bean id="messageListener" class="org.springframework.data.redis.listener.adapter.MessageListenerAdapter"> <property name="delegate" ref="messageDelegateListener" /> <!--這裡的messageDelegateListener在後面的檔案中註解的,這裡對應的具體訊息處理類的實現--> <property name="serializer" ref="jdkSerializer" /> </bean> <!-- 將訊息handler註冊 --> <redis:listener-container> <redis:listener ref="messageListener" method="handleMessage" serializer="jdkSerializer" topic="java"/> </redis:listener-container>
上文在定義Listener的時候採用了註解物件作為實現類,也可以手動在配置檔案中再寫一個bean,如下
<bean id="messageDelegateListener" class="***.***.***" />
最後我們給出一個接收方的實現
import java.io.Serializable; import org.springframework.stereotype.Component; @Component(value="messageDelegateListener") public class ListenMessage { public void handleMessage(Serializable message){ System.out.println(message); } }
相關文章
- Python中執行緒的MQ訊息佇列實現以及訊息佇列的優點解析Python執行緒MQ佇列
- Redis實現簡單訊息佇列Redis佇列
- “簡單”的訊息佇列與kafka佇列Kafka
- Redis實現訊息佇列Redis佇列
- 訊息佇列函式以及其簡單使用佇列函式
- 訊息佇列在大型分散式系統中的實戰要點分析!佇列分散式
- 訊息佇列中的Oracle佇列Oracle
- .NET Compact Framework 中的點對點訊息佇列Framework佇列
- 訊息佇列——數十萬級訊息的消費方案佇列
- Redis?使用?List?實現訊息佇列的優缺點猜陂Redis佇列
- PHP基於Redis訊息佇列實現的訊息推送的方法PHPRedis佇列
- 訊息佇列概念與作用佇列
- 如何實現MQ佇列訊息監控MQ佇列
- Redis 竟然能用 List 實現訊息佇列Redis佇列
- 使用Spring Boot實現訊息佇列Spring Boot佇列
- 單點登入原理與簡單實現
- 訊息佇列系列一:訊息佇列應用佇列
- 訊息機制篇——初識訊息與訊息佇列佇列
- WPF下使用FreeRedis操作RedisStream實現簡單的訊息佇列Redis佇列
- 訊息佇列佇列
- 訊息佇列之-RocketMQ入門佇列MQ
- python多執行緒中訊息佇列如何實現?Python執行緒佇列
- Go中使用Redis實現訊息佇列教程GoRedis佇列
- 訊息佇列概念與認知佇列
- Redis 使用 List 實現訊息佇列能保證訊息可靠麼?Redis佇列
- redis訊息佇列簡單應用Redis佇列
- 訊息佇列(MQ)佇列MQ
- Kafka訊息佇列Kafka佇列
- RabbitMQ訊息佇列MQ佇列
- kafka 訊息佇列Kafka佇列
- POSIX訊息佇列佇列
- 訊息佇列(一)佇列
- 訊息佇列(二)佇列
- 訊息佇列二佇列
- [Redis]訊息佇列Redis佇列
- [訊息佇列]rocketMQ佇列MQ
- [訊息佇列]RabbitMQ佇列MQ
- RabbitMQ 訊息佇列之佇列模型MQ佇列模型