欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Spring框架整合Java Web Token問(wèn)題

 更新時(shí)間:2024年09月05日 10:53:13   作者:Sams-ara  
這篇文章主要介紹了Spring框架整合Java Web Token問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教

Java Web Token

JSON Web Token(JWT)是一個(gè)非常輕巧的規(guī)范。

這個(gè)規(guī)范允許我們使用JWT在用戶和服務(wù)器之間傳遞安全可靠的信息。

JWT組成

一個(gè)JWT實(shí)際上就是一個(gè)字符串,它由三部分組成,頭部、載荷與簽名。

荷載

{
"iss": "John Wu JWT",
"iat": 1441593502,
"exp": 1441594722,
"aud": "www.example.com",
"sub": "jrocket@example.com",
"from_user": "B",
"target_user": "A"
}

這里面的前五個(gè)字段都是由JWT的標(biāo)準(zhǔn)所定義的。

  • iss: 該JWT的簽發(fā)者
  • sub: 該JWT所面向的用戶
  • aud: 接收該JWT的一方
  • exp(expires): 什么時(shí)候過(guò)期,這里是一個(gè)Unix時(shí)間戳
  • iat(issued at): 在什么時(shí)候簽發(fā)的

這些定義都可以在標(biāo)準(zhǔn)中找到。

將上面的JSON對(duì)象進(jìn)行[base64編碼]可以得到下面的字符串。

這個(gè)字符串我們將它稱作JWT的Payload(載荷)。

eyJpc3MiOiJKb2huIFd1IEpXVCIsImlhdCI6MTQ0MTU5MzUwMiwiZXhwIjoxNDQxNTk0NzIyLCJhdWQiOiJ3d3cuZXhhbXBsZS5jb20iLCJzdWIiOiJqcm9ja2V0QGV4YW1wbGUuY29tIiwiZnJvbV91c2VyIjoiQiIsInRhcmdldF91c2VyIjoiQSJ9

頭部

JWT還需要一個(gè)頭部,頭部用于描述關(guān)于該JWT的最基本的信息,例如其類型以及簽名所用的算法等。

這也可以被表示成一個(gè)JSON對(duì)象。

{
“typ”: “JWT”,
“alg”: “HS256”
}

在這里,我們說(shuō)明了這是一個(gè)JWT,并且我們所用的簽名算法(后面會(huì)提到)是HS256算法。(算法根據(jù)實(shí)際情況而變)

eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9

簽名

簽名就是將荷載和頭部編碼用.號(hào)連接在一起就形成了

eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJmcm9tX3VzZXIiOiJCIiwidGFyZ2V0X3VzZXIiOiJBIn0

我們將上面拼接完的字符串用HS256算法進(jìn)行加密。

在加密的時(shí)候,我們還需要提供一個(gè)密鑰(secret)。

如果我們用mystar作為密鑰的話,那么就可以得到我們加密后的內(nèi)容

rSWamyAYwuHCo7IFAgd1oRpSP7nzL7BF5t7ItqpKViM

最后將這一部分簽名也拼接在被簽名的字符串后面,我們就得到了完整的JWT

eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJmcm9tX3VzZXIiOiJCIiwidGFyZ2V0X3VzZXIiOiJBIn0.rSWamyAYwuHCo7IFAgd1oRpSP7nzL7BF5t7ItqpKViM

簽名的目的:

最后一步簽名的過(guò)程,實(shí)際上是對(duì)頭部以及載荷內(nèi)容進(jìn)行簽名。一般而言,加密算法對(duì)于不同的輸入產(chǎn)生的輸出總是不一樣的。對(duì)于兩個(gè)不同的輸入,產(chǎn)生同樣的輸出的概率極其地?。ㄓ锌赡鼙任页墒澜缡赘坏母怕蔬€?。?。所以,我們就把“不一樣的輸入產(chǎn)生不一樣的輸出”當(dāng)做必然事件來(lái)看待吧。

所以,如果有人對(duì)頭部以及載荷的內(nèi)容解碼之后進(jìn)行修改,再進(jìn)行編碼的話,那么新的頭部和載荷的簽名和之前的簽名就將是不一樣的。而且,如果不知道服務(wù)器加密的時(shí)候用的密鑰的話,得出來(lái)的簽名也一定會(huì)是不一樣的。

服務(wù)器應(yīng)用在接受到JWT后,會(huì)首先對(duì)頭部和載荷的內(nèi)容用同一算法再次簽名。那么服務(wù)器應(yīng)用是怎么知道我們用的是哪一種算法呢?別忘了,我們?cè)贘WT的頭部中已經(jīng)用alg字段指明了我們的加密算法了。

如果服務(wù)器應(yīng)用對(duì)頭部和載荷再次以同樣方法簽名之后發(fā)現(xiàn),自己計(jì)算出來(lái)的簽名和接受到的簽名不一樣,那么就說(shuō)明這個(gè)Token的內(nèi)容被別人動(dòng)過(guò)的,我們應(yīng)該拒絕這個(gè)Token,返回一個(gè)HTTP 401 Unauthorized響應(yīng)。

我們可以看到,JWT適合用于向Web應(yīng)用傳遞一些非敏感信息。例如在上面提到的完成加好友的操作,還有諸如下訂單的操作等等。

其實(shí)JWT還經(jīng)常用于設(shè)計(jì)用戶認(rèn)證和授權(quán)系統(tǒng),甚至實(shí)現(xiàn)Web應(yīng)用的單點(diǎn)登錄。

Spring使用JWT

Maven配置方式

<dependency>
    <groupId>com.auth0</groupId>
    <artifactId>java-jwt</artifactId>
    <version>3.2.0</version>
</dependency>

JWT算法(了解)

JWS算法介紹
HS256HMAC256HMAC with SHA-256
HS384HMAC384HMAC with SHA-384
HS512HMAC512HMAC with SHA-512
RS256RSA256RSASSA-PKCS1-v1_5 with SHA-256
RS384RSA384RSASSA-PKCS1-v1_5 with SHA-384
RS512RSA512RSASSA-PKCS1-v1_5 with SHA-512
ES256ECDSA256ECDSA with curve P-256 and SHA-256
ES384ECDSA384ECDSA with curve P-384 and SHA-384
ES512ECDSA512ECDSA with curve P-521 and SHA-512

使用方法

選擇算法:

算法定義了一個(gè)令牌是如何被簽名和驗(yàn)證的。它可以用HMAC算法的原始值來(lái)實(shí)例化,也可以在RSA和ECDSA算法的情況下對(duì)密鑰對(duì)或密鑰提供程序進(jìn)行實(shí)例化。創(chuàng)建后,該實(shí)例可用于令牌簽名和驗(yàn)證操作。

在使用RSA或ECDSA算法時(shí),只需要簽署JWTs,就可以通過(guò)傳遞null值來(lái)避免指定公鑰。當(dāng)您需要驗(yàn)證JWTs時(shí),也可以使用私鑰進(jìn)行操作

使用靜態(tài)的字符密文或者key來(lái)獲取算法器:

//HMAC
Algorithm algorithmHS = Algorithm.HMAC256("secret");

//RSA
RSAPublicKey publicKey = //Get the key instance
RSAPrivateKey privateKey = //Get the key instance
Algorithm algorithmRS = Algorithm.RSA256(publicKey, privateKey);

使用一個(gè)key提供者來(lái)獲取算法:

通過(guò)使用KeyProvider,您可以在運(yùn)行時(shí)更改密鑰,用于驗(yàn)證令牌簽名或?yàn)镽SA或ECDSA算法簽署一個(gè)新的令牌。

這是通過(guò)實(shí)現(xiàn)RSAKeyProvider或ECDSAKeyProvider方法實(shí)現(xiàn)的:

  • getPublicKeyById(String kid): 它在令牌簽名驗(yàn)證中調(diào)用,它應(yīng)該返回用于驗(yàn)證令牌的密鑰。如果使用了關(guān)鍵的輪換,例如JWK,它可以使用id來(lái)獲取正確的輪換鍵(或者只是一直返回相同的鍵)。
  • getPrivateKey(): 在令牌簽名期間調(diào)用它,它應(yīng)該返回用于簽署JWT的密鑰。
  • getPrivateKeyId():在令牌簽名期間調(diào)用它,它應(yīng)該返回標(biāo)識(shí)由getPrivateKey()返回的鍵的id的id。這個(gè)值比JWTCreator.Builder和keyid(String)方法中的值更受歡迎。如果您不需要設(shè)置孩子的值,就避免使用KeyProvider實(shí)例化算法。

創(chuàng)建JWT

try {
Algorithm algorithm = Algorithm.HMAC256("secret");
String token = JWT.create()
    .withIssuer("auth0")
    .sign(algorithm);
} catch (UnsupportedEncodingException exception){
    //UTF-8 encoding not supported
} catch (JWTCreationException exception){
    //Invalid Signing configuration / Couldn't convert Claims.
}

如果Claim不能轉(zhuǎn)換為JSON,或者在簽名過(guò)程中使用的密鑰無(wú)效,那么將會(huì)拋出JWTCreationException異常。

驗(yàn)證令牌

首先需要通過(guò)調(diào)用jwt.require()和傳遞算法實(shí)例來(lái)創(chuàng)建一個(gè)JWTVerifier實(shí)例。

如果您要求令牌具有特定的Claim值,請(qǐng)使用構(gòu)建器來(lái)定義它們。

方法build()返回的實(shí)例是可重用的,因此您可以定義一次,并使用它來(lái)驗(yàn)證不同的標(biāo)記。

最后調(diào)用verifier.verify()來(lái)驗(yàn)證token

String token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXUyJ9.eyJpc3MiOiJhdXRoMCJ9.AbIJTDMFc7yUa5MhvcP03nJPyCPzZtQcGEp-zWfOkEE";
try {
    Algorithm algorithm = Algorithm.HMAC256("secret");
    JWTVerifier verifier = JWT.require(algorithm)
        .withIssuer("auth0")
        .build(); //Reusable verifier instance
    DecodedJWT jwt = verifier.verify(token);
} catch (UnsupportedEncodingException exception){
    //UTF-8 encoding not supported
} catch (JWTVerificationException exception){
    //Invalid signature/claims
}

時(shí)間驗(yàn)證

當(dāng)驗(yàn)證一個(gè)令牌時(shí),時(shí)間驗(yàn)證會(huì)自動(dòng)發(fā)生,導(dǎo)致在值無(wú)效時(shí)拋出一個(gè)JWTVerificationException。如果前面的任何一個(gè)字段都丟失了,那么在這個(gè)驗(yàn)證中就不會(huì)考慮這些字段。

要指定令牌仍然被認(rèn)為有效的余地窗口,在JWTVerifier builder中使用accept回旋()方法,并傳遞一個(gè)正值的秒值。這適用于上面列出的每一項(xiàng)。

JWTVerifier verifier = JWT.require(algorithm)
.acceptLeeway(1) // 1 sec for nbf, iat and exp
.build();

您還可以為給定的日期聲明指定一個(gè)自定義值,并為該聲明覆蓋缺省值。

JWTVerifier verifier = JWT.require(algorithm)
.acceptLeeway(1)   //1 sec for nbf and iat
.acceptExpiresAt(5)   //5 secs for exp
.build();

信息解析

Algorithm (“alg”)

返回jwt的算法值或,如果沒(méi)有定義則返回null

String algorithm = jwt.getAlgorithm();

如果您需要在您的lib/app中測(cè)試此行為,將驗(yàn)證實(shí)例轉(zhuǎn)換為basever可視化,以獲得verific.build()方法的可見(jiàn)性,該方法可以接受定制的時(shí)鐘。

例如:

BaseVerification verification = (BaseVerification) JWT.require(algorithm)
.acceptLeeway(1)
.acceptExpiresAt(5);
Clock clock = new CustomClock(); //Must implement Clock interface
JWTVerifier verifier = verification.build(clock);

Type (“typ”)

返回jwt的類型值,如果沒(méi)有定義則返回null(多數(shù)情況類型值為jwt)

String type = jwt.getType();

Content Type (“cty”)

返回內(nèi)容的類型,如果沒(méi)有定義則返回null

String contentType = jwt.getContentType();

Key Id (“kid”)

返回key的id值,如果沒(méi)有定義則返回null

String keyId = jwt.getKeyId();

自定義字段

在令牌的頭部中定義的附加聲明可以通過(guò)調(diào)用getHeaderClaim() 獲取,即使無(wú)法找到,也會(huì)返回。您可以通過(guò)調(diào)用claim.isNull()來(lái)檢查聲明的值是否為null。

Claim claim = jwt.getHeaderClaim("owner");

當(dāng)使用jwt.create()創(chuàng)建一個(gè)令牌時(shí),您可以通過(guò)調(diào)用withHeader()來(lái)指定頭聲明,并同時(shí)傳遞聲明的映射。

Map<String, Object> headerClaims = new HashMap();
headerClaims.put("owner", "auth0");
String token = JWT.create()
    .withHeader(headerClaims)
    .sign(algorithm);

提示:在簽名過(guò)程之后,alg和typ值將始終包含在Header中。

JWT的負(fù)載(Payload)聲明

Issuer ("iss")

返回簽發(fā)者的名稱值,如果沒(méi)有在負(fù)載中定義則返回null

String issuer = jwt.getIssuer();
Subject ("sub")

返回jwt所面向的用戶的值,如果沒(méi)有在負(fù)載中定義則返回null

String subject = jwt.getSubject();
Audience ("aud")

返回該jwt由誰(shuí)接收,如果沒(méi)有在負(fù)載中定義則返回null

List<String> audience = jwt.getAudience();
Expiration Time ("exp")

返回該jwt的過(guò)期時(shí)間,如果在負(fù)載中沒(méi)有定義則返回null

Date expiresAt = jwt.getExpiresAt();
Not Before ("nbf")

Returns the Not Before value or null if it’s not defined in the Payload.

Date notBefore = jwt.getNotBefore();
Issued At ("iat")

返回在什么時(shí)候簽發(fā)的,如果在負(fù)載中沒(méi)有定義則返回null

Date issuedAt = jwt.getIssuedAt();
JWT ID ("jti")

返回該jwt的唯一標(biāo)志,如果在負(fù)載中沒(méi)有定義則返回null

String id = jwt.getId();

自定義聲明

在令牌有效負(fù)載中定義的附加聲明可以通過(guò)調(diào)用getClaims()或 getClaim()和傳遞聲明名來(lái)獲得。即使無(wú)法找到聲明,也將會(huì)有返回值。您可以通過(guò)調(diào)用claim.isNull()來(lái)檢查聲明的值是否為null。

Map<String, Claim> claims = jwt.getClaims();    //Key is the Claim name
Claim claim = claims.get("isAdmin");

或者:

Claim claim = jwt.getClaim("isAdmin");

當(dāng)使用jwt.create()創(chuàng)建一個(gè)令牌時(shí),您可以通過(guò)調(diào)用withClaim()來(lái)指定自定義聲明,并同時(shí)傳遞名稱和值。

String token = JWT.create()
    .withClaim("name", 123)
    .withArrayClaim("array", new Integer[]{1, 2, 3})
    .sign(algorithm);

您還可以通過(guò)調(diào)用withClaim()來(lái)驗(yàn)證jwt.require()的自定義聲明,并傳遞該名稱和所需的值。

JWTVerifier verifier = JWT.require(algorithm)
    .withClaim("name", 123)
    .withArrayClaim("array", 1, 2, 3)
    .build();
DecodedJWT jwt = verifier.verify("my.jwt.token");    

實(shí)例

package course.utils;

import com.auth0.jwt.JWT;
import com.auth0.jwt.JWTVerifier;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.exceptions.JWTVerificationException;
import com.auth0.jwt.interfaces.DecodedJWT;
import com.google.common.collect.Maps;
import course.pojo.User;

import java.io.UnsupportedEncodingException;
import java.util.Date;
import java.util.Map;

public class JwtUtils {

    //創(chuàng)建token
    public static String creatToken(User user) throws IllegalArgumentException, UnsupportedEncodingException{
        Algorithm algorithm = Algorithm.HMAC256("secret");
        String username = user.getUsername();
        Map<String, Object> map = Maps.newHashMap();
        map.put("alg", "HS256");
        map.put("typ", "JWT");
        String token = JWT.create().withHeader(map)
                .withClaim("username", username)
                .withExpiresAt(new Date(System.currentTimeMillis()+360000))
                .sign(algorithm);
        return token;
    }

    //驗(yàn)證jwt
    public static DecodedJWT verifyJwt(String token){
        DecodedJWT decodedJWT = null;
        try{
            Algorithm algorithm = Algorithm.HMAC256("secret");
            JWTVerifier jwtVerifier = JWT.require(algorithm).build();
            decodedJWT = jwtVerifier.verify(token);
        }catch(IllegalArgumentException e){
            e.printStackTrace();
        }catch (UnsupportedEncodingException e){
            e.printStackTrace();
        }catch(JWTVerificationException e) {
            e.printStackTrace();
        }
        return decodedJWT;
    }

    public static void main(String[] args) throws UnsupportedEncodingException{
//        String username = "root";
//        Integer id =1;
//        System.out.println(creatToken(username,id));
//        String token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE1MDgxMzgxNDAsInVzZXJJZCI6MSwidXNlcm5hbWUiOiJyb290In0.OeRdHJZKmxFBqIN-A-uSNQK8JyKdzX-wcFR883oMqFA";
//        System.out.println(verifyJwt("eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE1MDgxMzgxNDAsInVzZXJJZCI6MSwidXNlcm5hbWUiOiJyb290In0.OeRdHJZKmxFBqIN-A-uSNQK8JyKdzX-wcFR883oMqFA"));
//        System.out.println(verifyJwt(token).getClaims().get("username").asString());
    }
}

總結(jié)

以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。

相關(guān)文章

  • Spring boot通過(guò)HttpSessionListener監(jiān)聽(tīng)器統(tǒng)計(jì)在線人數(shù)的實(shí)現(xiàn)代碼

    Spring boot通過(guò)HttpSessionListener監(jiān)聽(tīng)器統(tǒng)計(jì)在線人數(shù)的實(shí)現(xiàn)代碼

    這篇文章主要介紹了Spring boot通過(guò)HttpSessionListener監(jiān)聽(tīng)器統(tǒng)計(jì)在線人數(shù)的實(shí)現(xiàn)代碼,非常不錯(cuò),具有參考借鑒價(jià)值,需要的朋友可以參考下
    2018-02-02
  • 解決SpringBoot自定義攔截器和跨域配置沖突的問(wèn)題

    解決SpringBoot自定義攔截器和跨域配置沖突的問(wèn)題

    這篇文章主要介紹了解決SpringBoot自定義攔截器和跨域配置沖突的問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2021-08-08
  • Java常用 Date 時(shí)間格式化、Calender日歷、正則表達(dá)式的用法小結(jié)

    Java常用 Date 時(shí)間格式化、Calender日歷、正則表達(dá)式的用法小結(jié)

    SimpleDateFormat?是Java中用于格式化和解析日期的類,它允許你將日期對(duì)象轉(zhuǎn)換為特定格式的字符串,或者將特定格式的字符串轉(zhuǎn)換為日期對(duì)象,這篇文章主要介紹了Java常用 Date 時(shí)間格式化、Calender日歷、正則表達(dá)式的用法,需要的朋友可以參考下
    2024-12-12
  • MyBatis的緩存解析

    MyBatis的緩存解析

    這篇文章主要介紹了MyBatis的緩存解析,一級(jí)緩存是SqlSession級(jí)別的,通過(guò)同一個(gè)SqlSession查詢的數(shù)據(jù)會(huì)緩存,下次查詢相同的數(shù)據(jù)就會(huì)從緩存中直接獲取,不會(huì)從數(shù)據(jù)重新訪問(wèn),前提必須是同一個(gè)SqlSession對(duì)象,并且查詢的數(shù)據(jù)相同,需要的朋友可以參考下
    2023-09-09
  • java正則表達(dá)式的應(yīng)用 java讀取文件并獲取電話號(hào)碼

    java正則表達(dá)式的應(yīng)用 java讀取文件并獲取電話號(hào)碼

    這篇文章主要介紹了java正則表達(dá)式的應(yīng)用,應(yīng)用的內(nèi)容是java讀取文件并獲取電話號(hào)碼,感興趣的小伙伴們可以參考一下
    2015-11-11
  • java返回前端實(shí)體類json數(shù)據(jù)時(shí)忽略某個(gè)屬性方法

    java返回前端實(shí)體類json數(shù)據(jù)時(shí)忽略某個(gè)屬性方法

    這篇文章主要給大家介紹了關(guān)于java返回前端實(shí)體類json數(shù)據(jù)時(shí)忽略某個(gè)屬性的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),需要的朋友可以參考下
    2023-08-08
  • 如何基于java實(shí)現(xiàn)Gauss消元法過(guò)程解析

    如何基于java實(shí)現(xiàn)Gauss消元法過(guò)程解析

    這篇文章主要介紹了如何基于java實(shí)現(xiàn)Gauss消元法過(guò)程解析,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2020-10-10
  • 深入講解Java?synchronized的核心原理

    深入講解Java?synchronized的核心原理

    這篇文章主要為大家詳細(xì)介紹了Java中synchronized的核心原理以及簡(jiǎn)單的用法,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下
    2023-07-07
  • 淺談常用Java數(shù)據(jù)庫(kù)連接池(小結(jié))

    淺談常用Java數(shù)據(jù)庫(kù)連接池(小結(jié))

    這篇文章主要介紹了淺談常用Java數(shù)據(jù)庫(kù)連接池(小結(jié)),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2019-07-07
  • SpringBoot整合Caffeine使用示例

    SpringBoot整合Caffeine使用示例

    Spring Boot 和 Caffeine 可以很容易地進(jìn)行整合,Caffeine 是一個(gè)現(xiàn)代化的 Java 緩存庫(kù),提供了高性能和靈活的緩存策略,本文給大家介紹了SpringBoot整合Caffeine使用示例,需要的朋友可以參考下
    2024-07-07

最新評(píng)論