引言:最近看了一個開源項目,涉及了些比較陌生的東西,爲了加深印象,做點小筆記;
JWT
json web token,簡單來說,就是客戶端與服務器進行驗證的解決方案之一;另外一種就是使用session的方式;
使用原理:
當客戶端第一次登陸後,服務端會返回JWT格式的令牌,包含一些用戶的信息,客戶端則會保存這個JWT信息至Cookie或者其他數據層框架,用於下次登陸時驗證。
此時,服務端不需要去存儲任何當前用戶的信息。而下次請求時,客戶端都需要攜帶次JWT信息,客戶端則會去解析該信息,重新認證該用戶,授權該用戶;
使用方法:
項目權限認證使用的spring security框架,第一次登陸時,在相應的successHandle中添加成功處理邏輯:
- 登陸成功生成JWT:
// jwt
token = SecurityConstant.TOKEN_SPLIT + Jwts.builder()
//主題 放入用戶名
.setSubject(username)
//自定義屬性 放入用戶擁有請求權限
.claim(SecurityConstant.AUTHORITIES, new Gson().toJson(list))
//失效時間
.setExpiration(new Date(System.currentTimeMillis() + tokenExpireTime * 60 * 1000))
//簽名算法和密鑰
.signWith(SignatureAlgorithm.HS512, SecurityConstant.JWT_SIGN_KEY)
.compact();
ResponseUtil.out(response, ResponseUtil.resultMap(true,200,"登錄成功", token));
再次請求校驗jwt:
只需要在Jwt認證的過濾器中添加該校驗;
private UsernamePasswordAuthenticationToken getAuthentication(String header, HttpServletResponse response) {
// 用戶名
String username = null;
// 權限
List<GrantedAuthority> authorities = new ArrayList<>();
try {
// 解析token
Claims claims = Jwts.parser()
.setSigningKey(SecurityConstant.JWT_SIGN_KEY)
.parseClaimsJws(header.replace(SecurityConstant.TOKEN_SPLIT, ""))
.getBody();
//獲取用戶名
username = claims.getSubject();
//獲取權限
String authority = claims.get(SecurityConstant.AUTHORITIES).toString();
if(StrUtil.isNotBlank(authority)){
List<String> list = new Gson().fromJson(authority, new TypeToken<List<String>>(){}.getType());
for(String ga : list){
authorities.add(new SimpleGrantedAuthority(ga));
}
}
} catch (ExpiredJwtException e) {
ResponseUtil.out(response, ResponseUtil.resultMap(false,401,"登錄已失效,請重新登錄"));
} catch (Exception e){
log.error(e.toString());
ResponseUtil.out(response, ResponseUtil.resultMap(false,500,"解析token錯誤"));
}
比較Session
衆所周知,Session方式的用戶信息認證是將登陸信息存儲在服務器端,redis緩存中,或者持久化;
而在分佈式的系統中,就只能持久化;
另外,session方式返回給瀏覽器端的認證信息一般只需要一個id,而JWT是將複雜的用戶信息,甚至加密加長後返給客戶端,這可能讓存儲4k的Cookie比較難爲情了;以致於前端可能需要拓展另外的方案解決認證問題;
總結:
JWT是將用戶登錄信息存儲在客戶端的一種方便拓展的認證方案,而Session則是將用戶信息存儲在服務器端的更安全的解決方案;