一,jwt的三個組成部件
先來看一個由IdentityServer頒發的一個標準令牌git
eyJhbGciOiJSUzI1NiIsImtpZCI6IjBiNTE3ZjIzYWY0OGM4ZjkyZjExMzM5MDMwZTI5NDkwIiwidHlwIjoiSldUIn0.
eyJuYmYiOjE1Njk4MDUxNzgsImV4cCI6MTU2OTgwNTQ3OCwiaXNzIjoiaHR0cDovL2xvY2FsaG9zdDo1MDAwIiwiYXVkIjoiYXBpQ2xpZW50SHlicmlkIiwibm9uY2UiOiI2MzcwNTQwMTk
2OTg5ODM3MjAuTnpZM016RTFObVF0WXpBMFlpMDBNR1k1TFdGbE1qY3RORGc0WldJMVl6RmpOemMzWW1Sa05URXdabUV0T1RKbU9DMDBZemRsTFdFNE16TXRaV0l6T0dabE5tWmlOamRoIi
wiaWF0IjoxNTY5ODA1MTc4LCJhdF9oYXNoIjoiMzRmemR5QzJmWFNCN3QzYl9mOW1VUSIsInNpZCI6IjIyOWU0OWRmOTZkY2U0OTVjMjZkMzI4MDhjMDM3MTk3Iiwic3ViIjoiMCIsImF1d
GhfdGltZSI6MTU2OTgwNTE3NSwiaWRwIjoibG9jYWwiLCJuYW1lIjoiYXBpVXNlciIsInBob25lbW9kZWwiOiJodWF3ZWkiLCJhbXIiOlsicHdkIl19.
rjksvMQkguG6qgQed7NZumdtcyDiEBuy9pDpEB-DOCGjqHF8BwI9CAWEOEbdb6PI9qBdFaZdafREZSodoL8qZMbd5ss2yrt01jhCaT00V54_ySFfyaBwpy8PFlasdygQEgEF44ZMLkaMWuV
u_dV22wkE1y5TCsPj-5hM7CpLiDDwaQvEVMe8FEZbJAZ8wskvnAFLY7P37LzjjPDWXW3hB10e-teNel2yXzsnlwpebQnLwUD46tKwAt4XDJ7yYqkuQ1y_dVvqJYf2awEeZPSn7tzThTaz5H
PCNvPwiO_9w7O1nb9gk-t97DR9uOC1Iz5fFHPuRjI7Gcm5dm3dgmgBfg
這個令牌用符號「.」把其分紅了三個部份:算法
1,頭部:一個通過Base64編碼的JSON字符串 安全
"alg"字段表示了這個令牌的簽名加密方式,上面咱們用的是RSA256非對稱加密,"type"則表示這是一個JWT格式令牌。「kid」是由令牌頒發者自由定義的一個值,用處不一,能夠用來表示一個消息序號,但更多用來加大簽名的複雜度。好比一個字符串用md5加密,若是這個字符串很簡單,有規律,那麼很容易被人破解,但用必定的算法加工後,好比字符串先後加上一組密鑰,那麼被破解的難度就很大了,但這個加工算法不要被人容易猜到,由於kid值是任何人均可以看到的。bash
2,消息主體:payload,也是一個通過Base64編碼的JSON字符串,包含令牌Claim,也是利用令牌獲取信息的主要部分。服務器
3,簽名字符串。ide
令牌一旦頒發,前面兩個部分的內容是任何人可見的,沒有任何的安全措施。那麼如何保證令牌不被人篡改和僞造呢?就是經過由簽名算法生成的一個簽名字符串。測試
IdentityServer4的簽名算法使用RSA加密算法,RSA是一個非對稱加密算法,用私鑰來加密,用公鑰來解密。私鑰只保存在IdentityServer端,而公鑰能夠公佈出去,IdentityServer是經過公開一個URL:http://localhost:5000/.well-known/openid-configuration/jwks發佈公鑰。這裏就要注意一個問題,因爲公鑰是公開的,那麼私鑰就要保護好了,若是私鑰被泄露就很容易被人篡改和僞造令牌。IdentityServer4爲了保護私鑰安全,分開了開發環境和發佈環境的密鑰加載。IdentityServer4公開了兩個方法AddSigningCredential和AddDeveloperSigningCredential,分別用於開發環境和發佈環境加載密鑰。AddDeveloperSigningCredential會建立一個臨時密鑰供調試環境用。實際應用時開發環境的密鑰證書能夠直接放在服務器上,項目發佈到服務器後經過配置文件指向這個密鑰。ui
二,利用Openssl建立密鑰證書。
從https://www.openssl.org/下載openssl安裝包並安裝,打開命令行,輸入openssl,若是提示Openssl不是內部或外部命令,須要設置一下環境變量,把Openssl的安裝目錄加入到path環境變量。this
另外新建一個環境變量,如如下所示,名稱爲:OPENSSL_CONF,指向你安裝目錄的openssl.cfg文件,如今輸入openssl應該沒有問題了。編碼
新建一個文件夾用於放置密鑰,在該目錄打開命令行。
1,申請一個私鑰,在命令行中輸入:openssl genrsa -out private_ids.key 2048。申請一個2048位的RSA加密私鑰。目錄下將多了一個名爲private_ids.key的文件。
2,申請一個公鑰,openssl req -new -x509 -key private_ids.key -days 3650 -out public_ids.crt。其中 -key private_ids.key是指定這個公鑰的配對私鑰,就是第一步申請的私鑰。x509是X.509公鑰格式標準。
接下來會提示你輸入一些信息,用於頒發機構的信息展現,如公司,所在國家,城市等
PS E:\ssl\tch> openssl req -new -x509 -key private_ids.key -days 3650 -out public_ids.crt You are about to be asked to enter information that will be incorporated into your certificate request. What you are about to enter is what is called a Distinguished Name or a DN. There are quite a few fields but you can leave some blank For some fields there will be a default value, If you enter '.', the field will be left blank. ----- Country Name (2 letter code) [AU]:CN State or Province Name (full name) [Some-State]:GUANGDONG Locality Name (eg, city) []:DONGGUANG Organization Name (eg, company) [Internet Widgits Pty Ltd]:KINGSUN Organizational Unit Name (eg, section) []:KINGSUN-IN Common Name (e.g. server FQDN or YOUR name) []:LIUJB Email Address []:LIUJB114@163.COM PS E:\ssl\tch>
若是不想每次都輸入這些信息,可使用「-config 配置文件目錄」的方式指定配置文件,安裝後Openssl後,有一個名爲openssl.cnf的默認的配置文件在安裝目錄bin/cnf目錄中。編輯該文件,找到req_distinguished_name
[ req_distinguished_name ] countryName = Country Name (2 letter code) countryName_default = AU countryName_min = 2 countryName_max = 2 stateOrProvinceName = State or Province Name (full name) stateOrProvinceName_default = Some-State localityName = Locality Name (eg, city) 0.organizationName = Organization Name (eg, company) 0.organizationName_default = Internet Widgits Pty Ltd # we can do this but it is not needed normally :-) #1.organizationName = Second Organization Name (eg, company) #1.organizationName_default = World Wide Web Pty Ltd organizationalUnitName = Organizational Unit Name (eg, section) #organizationalUnitName_default = commonName = Common Name (e.g. server FQDN or YOUR name) commonName_max = 64 emailAddress = Email Address emailAddress_max = 64
這裏能夠指定這些參數的默認值,如指定國家默認值爲CN。把countryName_default改爲CN就好了。申請完公鑰後,目錄下將多了一個public_ids.crt的文件。
3,公鑰及私鑰的提取加密。因爲傳播安全方面的考慮,須要將公鑰及私鑰加密,微軟支持PCK12(公鑰加密技術12號標準:Public Key Cryptography Standards #12),PCK12將公鑰和私鑰合在一個PFX後綴文件並用密碼保護,如要提取公鑰和私鑰須要密碼確認。另外一種覺的公鑰私鑰提取加密方式是JKS(JAVA Key Store)用於JAVA環境的公鑰和私鑰提取。這兩種格式能夠相互轉換。
在命令行中輸入
openssl pkcs12 -export -in public_ids.crt -inkey private_ids.key -out ids.pfx
輸入密碼和確認密碼後,當前目錄會多出一個文件:ids.pfx。這就是咱們要用的密鑰證書了。
三,使用密鑰
將第二步生成ids.pfx文件複製服務器發佈目錄,若是隻是爲了測試,能夠複製到本地項目目錄。將目錄信息及證書提取密碼存入配置文件
"Certificates": { "CertPath": "Certificates/idsrv4.pfx", "Password": "123456" }
就可使用該配置信息爲開發環境加載密鑰證書了
if (Environment.IsDevelopment()) { builder.AddDeveloperSigningCredential(); } else { builder.AddSigningCredential(new X509Certificate2(Path.Combine(Environment.ContentRootPath, Configuration["Certificates:CertPath"]), Configuration["Certificates:Password"])); }
若是想調試環境也統一證書,能夠把環境判斷去掉,只用AddSigningCredential方式加載密鑰證書。