點(diǎn)擊上方藍(lán)色字體,選擇“標(biāo)星公眾號”
優(yōu)質(zhì)文章,第一時間送達(dá)
cookie機(jī)制
關(guān)于cookie和seesion的聯(lián)系
cookie中會包含那些信息
名字,值,過期時間,路徑,域
cookie會帶到http請求頭中發(fā)送給服務(wù)端
如果cookie沒有設(shè)置過期時間的話,那么cookie的默認(rèn)生命周期是瀏覽器的會話
session機(jī)制
1,session是容器對象,客戶端在請求服務(wù)端的時候,服務(wù)端會根據(jù)客戶端的請求判斷是否包含了jsessionId的標(biāo)識
2,如果已經(jīng)包含了,說明客戶端之前已經(jīng)創(chuàng)建了會話。sessionId是一個唯一的值
3,如果sessionid不存在,那么服務(wù)端為這個客戶端生成一個sessionid. JESSIONID
session cookie 存儲的是JSESSIONID
session存儲在服務(wù)器端 cookie存儲在瀏覽器端
服務(wù)器端(Tomcat) 會生成一個唯一的sessionId號存儲在cookie中 叫 jessionid
在服務(wù)器端(tomcat)中存儲serssion 使用concurrentMap (ConcurrentMap key JSESSIONID values session)
瀏覽器端下次請求服務(wù)器端是將jsessionId帶過來 找到對應(yīng)的session 獲取session中存儲的信息(用戶信息)
客戶端瀏 覽器禁用了cookie怎么辦?
[如果客戶端瀏 覽器禁用了cookie,一般會通過URL重寫的方式來進(jìn)行會 話會話嗯個總,也就是在url中攜帶sessionid]
解決session跨域共享問題
1. session sticky :會話保存在單機(jī)上 保證會話請求落在同一臺服務(wù)器上
采用源地址哈希法進(jìn)行負(fù)載均衡,同一IP地址的客戶端,當(dāng)后端服務(wù)器列 表不變時,它每次都會映射到同一臺后端服務(wù)器進(jìn)行訪問
根據(jù)獲取客戶端的IP地址,通過哈希函數(shù)計算得到的一個 數(shù)值,用該數(shù)值對服務(wù)器列表的大小進(jìn)行取模運(yùn)算,得到的結(jié)果便是客服端要訪問服務(wù)器的序號。采用源地址哈希 法進(jìn)行負(fù)載均衡,同一IP地址的客戶端,當(dāng)后端服務(wù)器列表不變時,它每次都會映射到同一臺后端服務(wù)器進(jìn)行訪問
這種實(shí)現(xiàn)方式會有些問題: 如果一臺web服務(wù)器宕機(jī)或者重啟,那么這臺機(jī)器上保 存的會話數(shù)據(jù)都會丟失,會造成用戶暫時無法訪問的問 題,或者用戶之前的授權(quán)操作需要再執(zhí)行一次
2. session replication:session 復(fù)制 每一臺服務(wù)器上都保持一份相同的session (造成額外的存儲開銷和網(wǎng)絡(luò)開銷)
session復(fù)制,通過相關(guān)技術(shù)實(shí)現(xiàn)session復(fù)制,使得集群 中的各個服務(wù)器相互保存各自節(jié)點(diǎn)存儲的 session 數(shù)據(jù)。tomcat本身就可以實(shí)現(xiàn)session復(fù)制的功能,基于IP組播 放方式。
這種實(shí)現(xiàn)方式的問題:
1. 同步session數(shù)據(jù)會造成網(wǎng)絡(luò)開銷,隨著集群規(guī)模越大, 同步session帶來的帶寬影響也越大
2. 每個節(jié)點(diǎn)需要保存集群中所有節(jié)點(diǎn)的 session 數(shù)據(jù),就 需要比較大的內(nèi)存來存儲。
3. session 集中存儲 :存儲在db、 存儲在緩存服務(wù)器 (redis)
使用 spring-session -data-redis
http://www.glmapper.com/
4. 基于cookie (主流)
a)
access_token(userid/token/timestamp(過期時間) 加密)
將access_token存儲在客戶端的cookie中 每次 客戶端過來訪問 服務(wù)器端攔截其中 獲取cookie中的access_token 根據(jù) userid和timestamp(過期時間) 判斷是否有效
b)基于JWT的解決方案
json web Token 客戶端和服務(wù)端信息安全傳遞,身份認(rèn)證的一種解決方案。用在登陸上
jwt由三個組成:header,payload 載荷,signature
header{
typ:"jwt" //類型
alg:"HS256" //加密算法
zip: "gzip/deflate" //壓縮算法 加密之后的字符串 比較長的時候 可以使用壓縮算法
}
payload :jwt本身規(guī)范提供的格式 claims
{
iss:“簽發(fā)者”
iat:“簽發(fā)時間”
exp:“過期時間”
sub:
}
可以自己定一些claims,放入自定義的信息如 uid 等
signature:將 header+ payload 組合成為一個字符串
Base64(header).Base64(payload) + head中定義的算法 +密鑰 生成一個字符串 str.簽名字符串 就是 JWT的token

<!-- https://mvnrepository.com/artifact/com.auth0/java-jwt -->
<dependency>
<groupId>com.auth0</groupId>
<artifactId>java-jwt</artifactId>
<version>3.3.0</version>
</dependency>
<!-- https://mvnrepository.com/artifact/joda-time/joda-time -->
<dependency>
<groupId>joda-time</groupId>
<artifactId>joda-time</artifactId>
<version>2.9.9</version>
</dependency>
/**
* @Auther: tengxiao
* @Date: 2018/9/13 16:47
* @Description:
*/
public class JWTTokenUtil {
private static final String JWT_KEY_USER_ID="JWT_KEY_USER_ID";
private static final int EXPIRED_TIME=6000;
private static final String SECRET_KEY="tengvincent_user";
public static String generatorToken(Long userId)throws Exception{
//header Map
Map<String,Object> headerMap=new HashMap<>();
headerMap.put("typ","JWT");
headerMap.put("alg","HS256");
String token=JWT.create()
.withHeader(headerMap)
.withClaim("iss","Service")//簽發(fā)者
.withClaim("aud","APP")
.withClaim(JWT_KEY_USER_ID,userId)
.withIssuedAt(DateTime.now().toDate())//sign time
.withExpiresAt(DateTime.now().plusMinutes(EXPIRED_TIME).toDate())//expired time
.sign(Algorithm.HMAC256(SECRET_KEY));
return token;
}
public static Map<String,Claim> varifyToken(String token){
DecodedJWT jwt=null;
try{
JWTVerifier verifer= JWT.require(Algorithm.HMAC256(SECRET_KEY)).build();
jwt=verifer.verify(token);
}catch (Exception e){
// e.printStackTrace();
// token 校驗(yàn)失敗, 拋出Token驗(yàn)證非法異常
}
return jwt.getClaims();
}
public static Long getTokenInfo(String token){
Map<String, Claim> claims = varifyToken(token);
Claim user_id_claim = claims.get("user_id");
if (null == user_id_claim || StringUtils.isEmpty(user_id_claim.asString())) {
// token 校驗(yàn)失敗, 拋出Token驗(yàn)證非法異常
}
return Long.valueOf(user_id_claim.asString());
}
}
1.token+redis與jwt的區(qū)別
(1)簡單的說,token只是一個標(biāo)識,以token加redis為例,服務(wù)端將token保存在redis中,客服端訪問時帶上token,如果在redis中能夠查到這個token,說明身份有效。
(2)jwt不需要查庫,本身已經(jīng)包含了用戶的相關(guān)信息,可以直接通過服務(wù)端解析出相關(guān)的信息,與session,token的最大區(qū)別就是服務(wù)端不保存任何信息(服務(wù)端只需要保存密鑰key)。
2.如何實(shí)現(xiàn)jwt續(xù)期
在jwt中保存過期時間,解析時進(jìn)行判定,如果即將超時則重新設(shè)置過期時間返回一個新的jwt給客戶端。
3.jwt登出失效
登出時將相關(guān)的信息比如用戶名存儲在redis中,并設(shè)置過期時間。當(dāng)再次訪問時,從jwt中解析出用戶名去redis中查找,如果存在則表示此jwt已登出失效。這里需要注意的是,如果用此方法,則驗(yàn)證jwt是否登出應(yīng)該放在第一位。思考一個場景,如果redis中存儲的是用戶名,那么當(dāng)用戶登出后,redis中已經(jīng)有了相應(yīng)的用戶名,當(dāng)用戶再次登錄時,解析jwt發(fā)現(xiàn)此用戶已登出,則jwt失效,所以在登錄時要清空相關(guān)的登出緩存。
版權(quán)聲明:本文為博主原創(chuàng)文章,遵循 CC 4.0 BY-SA 版權(quán)協(xié)議,轉(zhuǎn)載請附上原文出處鏈接和本聲明。
本文鏈接:
https://blog.csdn.net/tengxvincent/article/details/82685042
