日日操夜夜添-日日操影院-日日草夜夜操-日日干干-精品一区二区三区波多野结衣-精品一区二区三区高清免费不卡

公告:魔扣目錄網(wǎng)為廣大站長(zhǎng)提供免費(fèi)收錄網(wǎng)站服務(wù),提交前請(qǐng)做好本站友鏈:【 網(wǎng)站目錄:http://www.ylptlb.cn 】, 免友鏈快審服務(wù)(50元/站),

點(diǎn)擊這里在線咨詢客服
新站提交
  • 網(wǎng)站:51998
  • 待審:31
  • 小程序:12
  • 文章:1030137
  • 會(huì)員:747

一、背景引入

由于Http協(xié)議本身是無(wú)狀態(tài)的,那么服務(wù)器是怎么識(shí)別兩次請(qǐng)求是不是來(lái)自同一個(gè)客戶端呢,傳統(tǒng)用戶識(shí)別是基于seeion和cookie實(shí)現(xiàn)的。大致流程如下:

Java基于JWT的token認(rèn)證

 

  1. 用戶向服務(wù)器發(fā)送用戶名和密碼請(qǐng)求用戶進(jìn)行校驗(yàn),校驗(yàn)通過(guò)后創(chuàng)建session繪畫,并將用戶相關(guān)信息保存到session中服務(wù)器將sessionId回寫到用戶瀏覽器cookie中用戶以后的請(qǐng)求,都會(huì)鞋帶cookie發(fā)送到服務(wù)器服務(wù)器得到cookie中的sessionId,從session集合中找到該用戶的session回話,識(shí)別用戶

這種模式有很多缺點(diǎn),對(duì)于分布式架構(gòu)的支持以及擴(kuò)展性不是很好。而且session是保存在內(nèi)存中,單臺(tái)服務(wù)器部署如果登陸用戶過(guò)多占用服務(wù)器資源也多,做集群必須得實(shí)現(xiàn)session共享的話,集群數(shù)量又不易太多,否則服務(wù)器之間頻繁同步session也會(huì)非常耗性能。當(dāng)然也可以引入持久層,將session保存在數(shù)據(jù)庫(kù)或者redis中,保存數(shù)據(jù)庫(kù)的話效率不高,存redis效率高,但是對(duì)redis依賴太重,如果redis掛了,影響整個(gè)應(yīng)用。還有一種辦法就是不存服務(wù)器,而是把用戶標(biāo)識(shí)數(shù)據(jù)存在瀏覽器,瀏覽器每次請(qǐng)求都攜帶該數(shù)據(jù),服務(wù)器做校驗(yàn),這也是JWT的思想。

二、JWT介紹

2.1 概念介紹

Json Web Token(JWT)是目前比較流行的跨域認(rèn)證解決方案,是一種基于JSON的開(kāi)發(fā)標(biāo)準(zhǔn),由于數(shù)據(jù)是可以經(jīng)過(guò)簽名加密的,比較安全可靠,一般用于前端和服務(wù)器之間傳遞信息,也可以用在移動(dòng)端和后臺(tái)傳遞認(rèn)證信息。

2.2 組成結(jié)構(gòu)

JWT就是一段字符串,格式如下:

eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJhdWQiOiIxIn0.qfd0GelhE1aGr15LrnYlIZ_3UToaOM5HeMcXrmDG

由于三部分組成,之間用"."接。第一部分是頭信息Header,中間部分是載荷Payload,最后部分是簽名信息Signature。

頭信息Header:描述JWT基本信息,typ表示采用JWT令牌,alg(algorithm)表示采用什么算法進(jìn)行簽名,常見(jiàn)算法有HmacSHA256(HS256)、HmacSHA384(HS384)、HmacSHA512(HS512)、SHA256withECDSA(ES256)、SHA256withRSA(RS256)、SHA512withRSA(RS512)等。如果采用HS256則頭信息結(jié)構(gòu)為:

{
 "typ": "JWT",
 "alg": "HS256
}

載荷Payload:載荷(也可以叫載體)是具體的傳輸內(nèi)容,包括一些標(biāo)準(zhǔn)屬性,iss: 該JWT的簽發(fā)者,exp: 過(guò)期時(shí)間戳,iat: 簽發(fā)時(shí)間戳,jti: JWTID等等。也可以添加其他需要傳遞的內(nèi)容數(shù)據(jù)。結(jié)構(gòu)為:

{
 "iss": "kkk",
 "iat": 1548818203,
 "exp": 1548818212,
 "sub": "test.com
}

簽名Signature:對(duì)頭信息和載荷進(jìn)行簽名,保證傳輸過(guò)程中信息不被篡改,比如:將頭信息和載荷分別進(jìn)行base64加密得到字符串a(chǎn)和b,將字符串a(chǎn)和b以點(diǎn)相連并簽名得到字符串c,將字符串a(chǎn)、b、c以點(diǎn)相連得到最終token。

2.3 驗(yàn)證流程

使用JWT的驗(yàn)證流程為:

  1. 用戶提交用戶名,密碼到服務(wù)器后臺(tái)后臺(tái)驗(yàn)證通過(guò),服務(wù)器端生成Token字符串,返回到客戶端客戶端保存Token,下一次請(qǐng)求資源時(shí),附帶上Token信息服務(wù)器端驗(yàn)證Token是否由服務(wù)器簽發(fā)的(一般在攔截器中驗(yàn)證),若Token驗(yàn)證通過(guò),則返回需要的資源

驗(yàn)證流程和基于session大體相同,只不過(guò)不是基于session,而是采用攔截器在代碼中實(shí)驗(yàn)驗(yàn)證,返回給客戶端的也不是sessionid,而是經(jīng)過(guò)一定算法得出來(lái)的token字符串。

2.4 源碼分析

JAVA中有封裝好的開(kāi)源哭JWT可以直接使用,下面就分析下關(guān)鍵代碼驗(yàn)證以下內(nèi)容。

Header頭信息結(jié)構(gòu)分析關(guān)鍵源碼如下:

//token生成方法
public static void main(String[] args) {
 String token= JWT.create().withAudience("audience")
 .withIssuedAt(new Date())
 .withSubject("subject")
 .withExpiresAt(new Date()).withJWTId("jtiid")
 .sign(Algorithm.HMAC256(user.getPassword()));
}
public abstract class Algorithm {
 private final String name;
 private final String description;
 //...其他方法省略...
 public static Algorithm HMAC256(String secret) throws IllegalArgumentException {
 return new HMACAlgorithm("HS256", "HmacSHA256", secret);
 }
 //...其他方法省略...
}
class HMACAlgorithm extends Algorithm {
 private final CryptoHelper crypto;
 private final byte[] secret;
 //...其他方法省略...
HMACAlgorithm(String id, String algorithm, byte[] secretBytes)
throws IllegalArgumentException {
this(new CryptoHelper(), id, algorithm, secretBytes);
}
//...其他方法省略..
}
public String sign(Algorithm algorithm) throws IllegalArgumentException,
JWTCreationException {
 if (algorithm == null) {
 throw new IllegalArgumentException("The Algorithm cannot be null.");
} else {
 this.headerClaims.put("alg", algorithm.getName());
 this.headerClaims.put("typ", "JWT");
 String signingKeyId = algorithm.getSigningKeyId();
 if (signingKeyId != null) {
 this.withKeyId(signingKeyId);
}
public final class JWTCreator {
 private final Algorithm algorithm;
 private final String headerJson;
 private final String payloadJson;
 private JWTCreator(Algorithm algorithm,
 Map<String, Object> headerClaims,
 Map<String, Object> payloadClaims) throws JWTCreationException {
 this.algorithm = algorithm;
 try {
 ObjectMApper mapper = new ObjectMapper();
 SimpleModule module = new SimpleModule();
 module.addSerializer(ClaimsHolder.class, new PayloadSerializer());
 mapper.registerModule(module);
 mapper.configure(MapperFeature.SORT_PROPERTIES_ALPHABETICALLY, true);
 this.headerJson = mapper.writeValueAsString(headerClaims);
 this.payloadJson =
 mapper.writeValueAsString(new ClaimsHolder(payloadClaims));
 } catch (JsonProcessingException var6) {
 throw new JWTCreationException(
 "Some of the Claims couldn't be converted to a valid JSON format.",
 var6);
 }
}
//...其他方法省略...

headerClaims是一個(gè)Map,包括兩個(gè)屬性typ和alg,typ值固定JWT,alg傳過(guò)來(lái)的簽名算法這里使用的

HmacSHA256簡(jiǎn)稱HS256。typ和alg組成Header頭信息。

Payload載荷結(jié)構(gòu)分析關(guān)鍵源碼如下:

public abstract class JWT {
 public JWT() {
 }
 public static DecodedJWT decode(String token) throws JWTDecodeException {
 return new JWTDecoder(token);
 }
 public static Verification require(Algorithm algorithm) {
 return JWTVerifier.init(algorithm);
 }
 public static Builder create() {
 return JWTCreator.init();
 }
}
public static class Builder {
 private final Map<String, Object> payloadClaims = new HashMap();
 private Map<String, Object> headerClaims = new HashMap();
 Builder() {
 }
 public JWTCreator.Builder withHeader(Map<String, Object> headerClaims) {
 this.headerClaims = new HashMap(headerClaims);
 return this;
 }
 public JWTCreator.Builder withKeyId(String keyId) {
 this.headerClaims.put("kid", keyId);
 return this;
 }
 public JWTCreator.Builder withIssuer(String issuer) {
 this.addClaim("iss", issuer);//簽發(fā)人
 return this;
 }
 public JWTCreator.Builder withSubject(String subject) {
 this.addClaim("sub", subject);//主題
 return this;
 }
 public JWTCreator.Builder withAudience(String... audience) {
 this.addClaim("aud", audience);//接受一方
 return this;
 }
 public JWTCreator.Builder withExpiresAt(Date expiresAt) {
 this.addClaim("exp", expiresAt);//過(guò)期時(shí)間
 return this;
 }
 public JWTCreator.Builder withNotBefore(Date notBefore) {
 this.addClaim("nbf", notBefore);//生效時(shí)間
 return this;
 }
 public JWTCreator.Builder withIssuedAt(Date issuedAt) {
 this.addClaim("iat", issuedAt);//簽發(fā)時(shí)間
 return this;
 }
 public JWTCreator.Builder withJWTId(String jwtId) {
 this.addClaim("jti", jwtId);//編號(hào)
 return this;
 }
 public JWTCreator.Builder withClaim(String name, Boolean value)
 throws IllegalArgumentException {
 this.assertNonNull(name);
 this.addClaim(name, value);
 return this;
 }
 public JWTCreator.Builder withClaim(String name, Integer value)
 throws IllegalArgumentException {
 this.assertNonNull(name);
 this.addClaim(name, value);
 return this;
 }
 //...其他方法省略...
}

Payload是一個(gè)json對(duì)象,存放需要傳遞的數(shù)據(jù),JTW默認(rèn)規(guī)定了幾個(gè)屬性,如果需要添加其他屬性可以調(diào)用其重載方法witchClaim()添加。

Signature簽名部分源碼如下:

private String sign() throws SignatureGenerationException {
 String header = Base64.encodeBase64URLSafeString(
 this.headerJson.getBytes(StandardCharsets.UTF_8));
 String payload = Base64.encodeBase64URLSafeString(
 this.payloadJson.getBytes(StandardCharsets.UTF_8));
 String content = String.format("%s.%s", header, payload);
 byte[] signatureBytes = this.algorithm.sign(
 content.getBytes(StandardCharsets.UTF_8));
 String signature = Base64.encodeBase64URLSafeString(signatureBytes);
 return String.format("%s.%s", content, signature);
}

從這里可以看出,所謂token就是分別對(duì)header和payload的json字符串做Base64加密得到a和b,并將結(jié)果拼接一起,在進(jìn)行簽名得到c,最終把a(bǔ)、b、c三部分內(nèi)容以點(diǎn)拼接起來(lái)形成token,返回客戶端保存,客戶端以后每次請(qǐng)求都在header中加入token,服務(wù)器采用攔截器方式獲取header中的token做校驗(yàn),識(shí)別用戶。

三、示例

3.1 數(shù)據(jù)準(zhǔn)備

創(chuàng)建用戶表

Java基于JWT的token認(rèn)證

 

3.2 搭建springboot工程

Java基于JWT的token認(rèn)證

 

設(shè)置工程Group、Artifact、Version、Name等信息

Java基于JWT的token認(rèn)證

 

Spring Boot的版本選擇2.0.8,選擇導(dǎo)入web的起步器

Java基于JWT的token認(rèn)證

 

創(chuàng)建工程成功之后,將各個(gè)包創(chuàng)建出來(lái),工程目錄結(jié)構(gòu)如下:

Java基于JWT的token認(rèn)證

 

3.3 引入pom依賴

Java基于JWT的token認(rèn)證

 


Java基于JWT的token認(rèn)證

 

3.4%20編寫application.yml配置文件

 

3.5 編寫User實(shí)體類

Java基于JWT的token認(rèn)證

 

Result類:用于統(tǒng)一返回消息的封裝

Java基于JWT的token認(rèn)證

 

TokenUtil類,用于生成token

Java基于JWT的token認(rèn)證

 


Java基于JWT的token認(rèn)證

 

VerifyToken注解類:加到controller方法上表示該方法需要驗(yàn)證token。

Java基于JWT的token認(rèn)證

 

3.6 編寫mapper接口和service層

mapper類:

Java基于JWT的token認(rèn)證

 

UserService接口:

Java基于JWT的token認(rèn)證

 

UserServiceImpl實(shí)現(xiàn)類:

Java基于JWT的token認(rèn)證

 

3.7 編寫攔截器和全局異常處理器

AuthInterceptor攔截器類:用于token驗(yàn)證。

Java基于JWT的token認(rèn)證

 


Java基于JWT的token認(rèn)證

 


Java基于JWT的token認(rèn)證

 

全局異常處理器GloabllExceptionHandler:用于異常的捕獲。

Java基于JWT的token認(rèn)證

 

3.8 編寫配置類及controller

攔截器配置類InterceptorConfig:配置攔截所有請(qǐng)求

Java基于JWT的token認(rèn)證

 


Java基于JWT的token認(rèn)證

 

UserController類:

Java基于JWT的token認(rèn)證

 

3.9 測(cè)試

測(cè)試1:使用postman發(fā)送get請(qǐng)求http://localhost:8088/user/getUser?id=1

Java基于JWT的token認(rèn)證

 

測(cè)試2:發(fā)送post請(qǐng)求http://localhost:8088/user/login 密碼故意輸錯(cuò)

Java基于JWT的token認(rèn)證

 

測(cè)試3:發(fā)送post請(qǐng)求http://localhost:8088/user/login 填正確的用戶名密碼

分享到:
標(biāo)簽:認(rèn)證 Java token
用戶無(wú)頭像

網(wǎng)友整理

注冊(cè)時(shí)間:

網(wǎng)站:5 個(gè)   小程序:0 個(gè)  文章:12 篇

  • 51998

    網(wǎng)站

  • 12

    小程序

  • 1030137

    文章

  • 747

    會(huì)員

趕快注冊(cè)賬號(hào),推廣您的網(wǎng)站吧!
最新入駐小程序

數(shù)獨(dú)大挑戰(zhàn)2018-06-03

數(shù)獨(dú)一種數(shù)學(xué)游戲,玩家需要根據(jù)9

答題星2018-06-03

您可以通過(guò)答題星輕松地創(chuàng)建試卷

全階人生考試2018-06-03

各種考試題,題庫(kù),初中,高中,大學(xué)四六

運(yùn)動(dòng)步數(shù)有氧達(dá)人2018-06-03

記錄運(yùn)動(dòng)步數(shù),積累氧氣值。還可偷

每日養(yǎng)生app2018-06-03

每日養(yǎng)生,天天健康

體育訓(xùn)練成績(jī)?cè)u(píng)定2018-06-03

通用課目體育訓(xùn)練成績(jī)?cè)u(píng)定