天天看點

權限認證(六):JWT 通路令牌使用對稱與非對稱加密

  • jwt簡介
# 頭部:包含令牌的類型(JWT) 與加密的簽名算法((如 SHA256 或 ES256) ,Base64編碼後加入第一部分
# 有效載荷:通俗一點講就是token中需要攜帶的資訊都将存于此部分,比如:使用者id、權限辨別等資訊。
注:該部分資訊任何人都可以讀出來,是以添加的資訊需要加密才會保證資訊的安全性
# 簽名:用于防止 JWT 内容被篡改, 會将頭部和有效載荷分别進行 Base64編碼,編碼後用 . 連接配接組成新的字元串,然後再使用頭部聲明的簽名算法進行簽名。在具有秘鑰的情況下,可以驗證JWT的準确性,是否被篡改      
  • 在demo06的基礎上開發,首先測試通過
# 擷取授權碼
http://localhost:8090/auth/oauth/authorize?client_id=mengxuegu-pc&response_type=code      
權限認證(六):JWT 通路令牌使用對稱與非對稱加密
權限認證(六):JWT 通路令牌使用對稱與非對稱加密
權限認證(六):JWT 通路令牌使用對稱與非對稱加密
權限認證(六):JWT 通路令牌使用對稱與非對稱加密
權限認證(六):JWT 通路令牌使用對稱與非對稱加密
權限認證(六):JWT 通路令牌使用對稱與非對稱加密
  • ​在認證伺服器中使用對稱加密jwt令牌​

# server子子產品中的TokenConfig中配置如下
    public static final String SIGNING_KEY = "mengxeugu-key";
    @Bean
    public JwtAccessTokenConverter jwtAccessTokenConverter() {
        JwtAccessTokenConverter converter = new JwtAccessTokenConverter();
        // 對稱加密進行簽名令牌,資源伺服器也要采用此密鑰來進行解密,來校驗令牌合法性
        converter.setSigningKey(SIGNING_KEY);
        return converter;
    }
    @Bean
    public TokenStore tokenStore() {
        // jdbc管理令牌
        //return new JdbcTokenStore(dataSource());
        // Jwt管理令牌
        return new JwtTokenStore(jwtAccessTokenConverter());
    }

# server子子產品中的AuthorizationServerConfig中配置如下
@Autowired // jwt轉換器
    private JwtAccessTokenConverter jwtAccessTokenConverter;
    @Override
    public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
        // 令牌的管理方式
        //endpoints.tokenStore(tokenStore);
        endpoints.tokenStore(tokenStore).accessTokenConverter(jwtAccessTokenConverter);
    }      
  • 啟動認證伺服器和資源伺服器測試
  • 使用密碼模式擷取一個token
  • 權限認證(六):JWT 通路令牌使用對稱與非對稱加密
  • 檢查該令牌
  • 權限認證(六):JWT 通路令牌使用對稱與非對稱加密
  • ​資源伺服器對稱解密jwt令牌​

# resource子子產品中配置TokenConfig
@Configuration
public class TokenConfig {
    public static final String SIGNING_KEY = "mengxeugu-key";
    @Bean
    public JwtAccessTokenConverter jwtAccessTokenConverter() {
        JwtAccessTokenConverter converter = new JwtAccessTokenConverter();
        // 對稱加密進行簽名令牌,資源伺服器也要采用此密鑰來進行解密,來校驗令牌合法性
        converter.setSigningKey(SIGNING_KEY);
        // 非對稱加密,資源伺服器使用公鑰解密 public.txt
//        ClassPathResource resource = new ClassPathResource("public.txt");
//        String publicKey = null;
//        try {
//            publicKey = IOUtils.toString(resource.getInputStream(), "UTF-8");
//        } catch (IOException e) {
//            e.printStackTrace();
//        }
//        converter.setVerifierKey(publicKey);
        return converter;
    }
    @Bean
    public TokenStore tokenStore() {
        // Jwt管理令牌
        return new JwtTokenStore(jwtAccessTokenConverter());
    }
}

# ResourceServerConfig中配置如下
# 删除如下
public ResourceServerTokenServices tokenService(){
//        // 遠端認證伺服器進行校驗 token 是否有效
//        RemoteTokenServices service = new RemoteTokenServices();
//        // 請求認證伺服器校驗的位址,預設情況 這個位址在認證伺服器它是拒絕通路,要設定為認證通過可通路
//        service.setCheckTokenEndpointUrl("http://localhost:8090/auth/oauth/check_token");
//        service.setClientId("mengxuegu-pc");
//        service.setClientSecret("mengxuegu-secret");
//        return service;
//    }

.tokenServices(tokenService())

# 添加如下
@Autowired
private TokenStore tokenStore;

.tokenStore(tokenStore)      
  • 測試
  • 權限認證(六):JWT 通路令牌使用對稱與非對稱加密
    權限認證(六):JWT 通路令牌使用對稱與非對稱加密
  • ​認證伺服器非對稱加密jwt令牌:使用私鑰進行加密,使用公鑰進行解密​

# 本機安裝jdk後,生成密鑰
# 打開cmd,生成密鑰時顯示'keytool' 不是内部或外部指令,也不是可運作的程式,需進入C:\Program Files\Java\jdk-11.0.13\bin目錄進行操作
# 報錯:keytool 錯誤: java.io.FileNotFoundException: oauth2.jks (拒絕通路。),解決方案是以管理者身份進入jdk目錄進行操作
# 以管理者的身份進入C:\Program Files\Java\jdk-11.0.13\bin目錄,執行如下指令
keytool -genkeypair -alias oauth2 -keyalg RSA -keypass oauth2 -keystore oauth2.jks
-storepass oauth2

# 密碼:oauth2
# 姓氏:meng
# 組織:mxg
# 城市:bj
# 國家:cn
# 是否确認:y

# 在執行指令的路徑下生成oauth2.jks      
權限認證(六):JWT 通路令牌使用對稱與非對稱加密
  • 配置非對稱加密
# 将oauth2.jks剪切到認證伺服器子子產品的resource目錄下

# TokenConfig中配置如下
KeyStoreKeyFactory factory = new KeyStoreKeyFactory(
                new ClassPathResource("oauth2.jks"), "oauth2".toCharArray());
        converter.setKeyPair(factory.getKeyPair("oauth2"));

# 删除如下
converter.setSigningKey(SIGNING_KEY);      
  • 拓展
keytool 
-genkeypair -alias oauth2 # 設定别名oauth2
-keyalg RSA -keypass oauth2 # 設定keypass為oauth2
-keystore oauth2.jks # 設定生成的檔案名oauth2.jks
-storepass oauth2

KeyStoreKeyFactory factory = new KeyStoreKeyFactory(
                new ClassPathResource("oauth2.jks"),  # 加載oauth2.jks檔案
                "oauth2".toCharArray()); # 使用之前設定的keypass
        converter.setKeyPair(factory.getKeyPair("oauth2")); # 使用之前設定的别名      
  • 測試:啟動認證伺服器和資源伺服器
  • 權限認證(六):JWT 通路令牌使用對稱與非對稱加密
  • ​資源伺服器非對稱解密jwt令牌​

# 進入網站http://slproweb.com/products/Win32OpenSSL.html下載下傳openssl      
權限認證(六):JWT 通路令牌使用對稱與非對稱加密
  • 生成公鑰
# 下載下傳openssl後輕按兩下直接安裝
# 配置環境變量:Path = C:\Program Files\OpenSSL-Win64\bin
# 将之前生成oauth2.jks發到c盤根目錄下,以管理者的身份進入C:\Program Files\Java\jdk-11.0.13\bin目錄執行如下指令生成公鑰
C:\Program Files\Java\jdk-11.0.13\bin>keytool -list -rfc --keystore C:\oauth2.jks | openssl x509 -inform pem -pubkey
輸入密鑰庫密碼:  oauth2
-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEArws0jvq7ciIW1ea7IZwm
kk4CxWKTk0R9hwZO1hEQA5+9hDs+mBBfYpw6kYETLtgGtDm8ayLnbMoq6sTkOELN
1nYj1fIqffQCKKzBiiTMa9VDndLnATHIZpCOHnzqOPZBFg5TrQV0xMyWU9FT8qRB
GsntUdeI21tk/cN6rmVnDEGkFJmpT7JO+MlDMN6wAeANUUk+gZql/ZX8Hzn+xZrv
qYZ3HLCKFpRFbp/+b39d7VS8CwjP5Q1GtJKrVMAJ/Vm6GaQKtvsGDjkGj1E+lfDV
szbnK/p6R7B9ynXUvEDXkEjAnzTjJLL05MJdYbS3Osd7cSAcHB8pzHXD5WbpYWeJ
JQIDAQAB
-----END PUBLIC KEY-----
-----BEGIN CERTIFICATE-----
MIIDQzCCAiugAwIBAgIEK51NDzANBgkqhkiG9w0BAQsFADBSMQswCQYDVQQGEwJj
bjELMAkGA1UECBMCd3oxCzAJBgNVBAcTAmJqMQwwCgYDVQQKEwNteGcxDDAKBgNV
BAsTA214ZzENMAsGA1UEAxMEbWVuZzAeFw0yMjA0MDQwMjE0MDJaFw0yMjA3MDMw
MjE0MDJaMFIxCzAJBgNVBAYTAmNuMQswCQYDVQQIEwJ3ejELMAkGA1UEBxMCYmox
DDAKBgNVBAoTA214ZzEMMAoGA1UECxMDbXhnMQ0wCwYDVQQDEwRtZW5nMIIBIjAN
BgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEArws0jvq7ciIW1ea7IZwmkk4CxWKT
k0R9hwZO1hEQA5+9hDs+mBBfYpw6kYETLtgGtDm8ayLnbMoq6sTkOELN1nYj1fIq
ffQCKKzBiiTMa9VDndLnATHIZpCOHnzqOPZBFg5TrQV0xMyWU9FT8qRBGsntUdeI
21tk/cN6rmVnDEGkFJmpT7JO+MlDMN6wAeANUUk+gZql/ZX8Hzn+xZrvqYZ3HLCK
FpRFbp/+b39d7VS8CwjP5Q1GtJKrVMAJ/Vm6GaQKtvsGDjkGj1E+lfDVszbnK/p6
R7B9ynXUvEDXkEjAnzTjJLL05MJdYbS3Osd7cSAcHB8pzHXD5WbpYWeJJQIDAQAB
oyEwHzAdBgNVHQ4EFgQUA7Y9cGQZshEWO/WaGLtdxRkP1wcwDQYJKoZIhvcNAQEL
BQADggEBAD7ZCX02zuHcjaaod0UH2cKc7z2eCZl35IshGbEpJQ1TiQ4Rl9I4mDh+
kQjLEeMbAD9LM2N/0kpSfBPvc0b2qFuU8hLqmfDWC2TAF1st9EGx+i+b1m9sXaDl
2QgSvyt5KE81NxlnS5PpLDuFl2Bv/8RD4KSmdzM2zF+EFuYr1ZxNEoi5JIKxFcjF
JRYQSzLLL9sCLO5B+YXuobY7UW42oi0guWvVFuzkSrsEZb3gyZjbkWOXFXUPZCIK
H83FJWe0JytXziUhwdrwIDaTo4Q4mSJfYTRyKDKnwrGq0aWN3OTOzWtQpNu/9HLk
Wv5Gx47xMdHHHwffUliFSB24HvqVuG8=
-----END CERTIFICATE-----      
  • 在資源伺服器的resource目錄下建立public.txt
-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEArws0jvq7ciIW1ea7IZwm
kk4CxWKTk0R9hwZO1hEQA5+9hDs+mBBfYpw6kYETLtgGtDm8ayLnbMoq6sTkOELN
1nYj1fIqffQCKKzBiiTMa9VDndLnATHIZpCOHnzqOPZBFg5TrQV0xMyWU9FT8qRB
GsntUdeI21tk/cN6rmVnDEGkFJmpT7JO+MlDMN6wAeANUUk+gZql/ZX8Hzn+xZrv
qYZ3HLCKFpRFbp/+b39d7VS8CwjP5Q1GtJKrVMAJ/Vm6GaQKtvsGDjkGj1E+lfDV
szbnK/p6R7B9ynXUvEDXkEjAnzTjJLL05MJdYbS3Osd7cSAcHB8pzHXD5WbpYWeJ
JQIDAQAB
-----END PUBLIC KEY-----      
  • 配置如下
# resource子子產品TokenConfig配置如下
# 删除如下:
converter.setSigningKey(SIGNING_KEY);
# 添加如下:
ClassPathResource resource = new ClassPathResource("public.txt");
String publicKey = null;
try {
    publicKey = IOUtils.toString(resource.getInputStream(), "UTF-8");
} catch (IOException e) {
    e.printStackTrace();
}
converter.setVerifierKey(publicKey);      
  • 測試
  • 權限認證(六):JWT 通路令牌使用對稱與非對稱加密