IdentityServer4(六)授权码流程原理之SPA
在【One by One系列】IdentityServer4(四)授權(quán)碼流程中提過(guò)一句:
“為了安全,IdentityServer4是帶有PKCE支持的授權(quán)碼模式
”我們來(lái)回顧一下授權(quán)碼流程
(A)用戶訪問(wèn)客戶端,后者將前者導(dǎo)向認(rèn)證服務(wù)器。
(B)用戶選擇是否給予客戶端授權(quán)。
(C)假設(shè)用戶給予授權(quán),認(rèn)證服務(wù)器將用戶導(dǎo)向客戶端事先指定的"重定向URI"(redirection URI),同時(shí)附上一個(gè)授權(quán)碼。
(D)客戶端收到授權(quán)碼,附上早先的"重定向URI",向認(rèn)證服務(wù)器申請(qǐng)令牌。這一步是在客戶端的后臺(tái)的服務(wù)器上完成的,對(duì)用戶不可見。
(E)認(rèn)證服務(wù)器核對(duì)了授權(quán)碼和重定向URI,確認(rèn)無(wú)誤后,向客戶端發(fā)送訪問(wèn)令牌(access token)和更新令牌(refresh token)。
--摘自阮一峰老師-理解OAuth 2.0,自認(rèn)為阮老師這塊已經(jīng)寫比較清晰了,正所謂”眼前有景道不得,崔顥題詩(shī)在上頭“。
1.什么是PKCE
PKCE,全稱Proof Key for Code Exchange,上篇講到SPA,這是一種沒有后端服務(wù)器的原生客戶端,代碼都在用戶本地設(shè)備上運(yùn)行,比如SPA在用戶瀏覽器上運(yùn)行,Win/Mac客戶端,iOS/Android APP,如果讓這些原生客戶端安全地存放密鑰(client secret)并不現(xiàn)實(shí),且容易被破解。
Implicit Flow:我們沒有介紹Implicit Flow,官方最新文檔也沒有,現(xiàn)在來(lái)看,可能就是因?yàn)榘踩脑颉ccess Token會(huì)直接被傳遞給Redirect URL,容易被截取Access-Token
Authorization Code Flow:Redirect URL只會(huì)接收一個(gè)授權(quán)碼,且授權(quán)碼必須要和Client ID,Client Secret一同使用才能獲取Access Token。然而原生客戶端無(wú)法安全保存Client Secret,第三方惡意應(yīng)用可以破解Client Secret,并按上述方法截取Authorization Code,同樣不建議使用。
PKCE,旨在提高移動(dòng)設(shè)備上授權(quán)代碼流程執(zhí)行過(guò)程中的安全性。有關(guān)該功能的定義,參閱RFC7636,微軟翻譯為保護(hù)授權(quán)碼授權(quán)。實(shí)質(zhì)是通過(guò)密碼學(xué)技術(shù)手段,確保惡意第三方即使截獲到授權(quán)碼(Authorization Code)或者其他密鑰,也無(wú)法向認(rèn)證服務(wù)器交換獲取Access Token。
PKCE要求所有客戶端必須需要實(shí)現(xiàn)的內(nèi)容:
隨機(jī)生成一串字符串,并用URL-Safe的Base64編碼處理,結(jié)果為:code_verifier
將code_verifier通過(guò)SHA256哈希加密,并用URL-Safe的Base64編碼處理,結(jié)果為:code_challenge
2.PKCE授權(quán)碼流程
那么PKCE支持的授權(quán)碼流程就發(fā)生了變化,具體流程如下:
(A)客戶端除了response_type,Scope等標(biāo)準(zhǔn)參數(shù),還必須帶上,code_challenge與code_challenge_method,發(fā)起對(duì)服務(wù)器的/authorize端點(diǎn)請(qǐng)求
(B)服務(wù)器對(duì)/authorize除了執(zhí)行標(biāo)準(zhǔn)的OAuth請(qǐng)求驗(yàn)證,還會(huì)檢查code_challenge與code_challenge_method是否存在,并存儲(chǔ)
(C)服務(wù)器返回Authorization Code
(D)客戶端拿到Authorization Code,就用Authorization Code和code_verifier向服務(wù)端的/token端點(diǎn)發(fā)起請(qǐng)求,獲取Access-token
(E)服務(wù)端對(duì)/token端點(diǎn),除了執(zhí)行標(biāo)準(zhǔn)的OAuth驗(yàn)證外,還會(huì)使用客戶端傳過(guò)來(lái)的code_verifier和服務(wù)端存儲(chǔ)的code_challenge_method來(lái)生成自己的code_challenge
(F)服務(wù)端會(huì)將生成code_challenge與初始請(qǐng)求/authorize端點(diǎn)的code_challenge(并根據(jù)Authorization Code存儲(chǔ)在服務(wù)端)兩相比較
匹配,頒發(fā)access-token
不匹配,拒絕該請(qǐng)求
流程圖
“注意點(diǎn):
上圖的t(code_verifier)指的就是code_challenge
code_verifier是一個(gè)加密字符串,其所具有的熵必須要足夠大,使攻擊者無(wú)法預(yù)測(cè)或猜到其值
任何截獲到的中間方,并不能由code_challenge破解出code_verifier,這里只有客戶端知道這兩個(gè)值。所以截獲到code_challenge和Authorization Code,也換不來(lái)想要的token,換來(lái)的只有拒絕。總而言之,這樣降低惡意使用Authorization Code與Access-token的行為的風(fēng)險(xiǎn)。
3.查看IdentityServer4授權(quán)碼流程
知曉了PKCE的男人,現(xiàn)在想對(duì)IdentityServer4授權(quán)碼流程有一個(gè)更詳細(xì)了了解,以及對(duì)PKCE的驗(yàn)證,我們使用WireShark對(duì)整個(gè)請(qǐng)求進(jìn)行抓包。
“由于fiddler智能抓包一些瀏覽器請(qǐng)求,對(duì)于整個(gè)過(guò)程中的一些后臺(tái)請(qǐng)求,并不能捕獲,所以我們選擇WireShark這個(gè)工具。也不能通過(guò)瀏覽器開發(fā)者模式,由于授權(quán)重定向的過(guò)程太快,好多請(qǐng)求都看不清。
”3.1 運(yùn)行IdentityServer
cd .\IdentityServer\ dotnet run3.2 運(yùn)行wireshark
打開軟件,選擇-adapter for loopback traffic capture開始抓包
3.2 運(yùn)行JavaScript客戶端
cd .\JavaScript\ dotnet run3.2 操作
按照上一篇文章操作,登錄,注銷
3.3 停止wireshark的捕獲
停止捕獲,通過(guò)自帶的列表過(guò)濾報(bào)文,如下圖
這就是整個(gè)授權(quán)登錄,然后注銷登錄過(guò)程中,發(fā)生的http請(qǐng)求。
4.詳解IdentityServer4授權(quán)碼流程(SPA)
4.1 請(qǐng)求IdentityServer4的配置端點(diǎn)-獲取authorize端點(diǎn)
請(qǐng)求
... GET /.well-known/openid-configuration HTTP/1.1\r\n Host: localhost:5001\r\n ...響應(yīng)
200 OK Date: Sun, 12 Jul 2020 17:38:32 GMT Content-Type: application/json; charset=UTF-8 {"issuer":"http://localhost:5001","jwks_uri":"http://localhost:5001/.well-known/openid-configuration/jwks","authorization_endpoint":"http://localhost:5001/connect/authorize","token_endpoint":"http://localhost:5001/connect/token","userinfo_endpoint":"http://localhost:5001/connect/userinfo","end_session_endpoint":"http://localhost:5001/connect/endsession","check_session_iframe":"http://localhost:5001/connect/checksession","revocation_endpoint":"http://localhost:5001/connect/revocation","introspection_endpoint":"http://localhost:5001/connect/introspect","device_authorization_endpoint":"http://localhost:5001/connect/deviceauthorization","frontchannel_logout_supported":true,"frontchannel_logout_session_supported":true,"backchannel_logout_supported":true,"backchannel_logout_session_supported":true,"scopes_supported":["openid","profile","api1","offline_access"],"claims_supported":["sub","name","family_name","given_name","middle_name","nickname","preferred_username","profile","picture","website","gender","birthdate","zoneinfo","locale","updated_at"],"grant_types_supported":["authorization_code","client_credentials","refresh_token","implicit","password","urn:ietf:params:oauth:grant-type:device_code"],"response_types_supported":["code","token","id_token","id_token token","code id_token","code token","code id_token token"],"response_modes_supported":["form_post","query","fragment"],"token_endpoint_auth_methods_supported":["client_secret_basic","client_secret_post"],"id_token_signing_alg_values_supported":["RS256"],"subject_types_supported":["public"],"code_challenge_methods_supported":["plain","S256"],"request_parameter_supported":true}這里主要是獲取授權(quán)端點(diǎn),由oidc-client.js內(nèi)部觸發(fā)。
4.2 請(qǐng)求authorize端點(diǎn)
請(qǐng)求
GET /connect/authorize?client_id=js&redirect_uri=http%3A%2F%2Flocalhost%3A6003%2Fcallback.html&response_type=code&scope=openid%20profile%20api1&state=e9292cf7e4d04c03bf3fc7fe230f0378&code_challenge=kz0v3GRm8yFhmjoOYBWX2pg68N5waBd0hFVvbvuIT9E&code_challenge_method=S256&response_mode=query HTTP/1.1 Host: localhost:5001響應(yīng)
Status Code: 302 Location: http://localhost:5001/Account/Login?ReturnUrl=%2Fconnect%2Fauthorize%2Fcallback%3Fclient_id%3Djs%26redirect_uri%3Dhttp%253A%252F%252Flocalhost%253A6003%252Fcallback.html%26response_type%3Dcode%26scope%3Dopenid%2520profile%2520api1%26state%3De9292cf7e4d04c03bf3fc7fe230f0378%26code_challenge%3Dkz0v3GRm8yFhmjoOYBWX2pg68N5waBd0hFVvbvuIT9E%26code_challenge_method%3DS256%26response_mode%3Dquery請(qǐng)求授權(quán)端點(diǎn),帶上了response_type,scope,profile,code_challenge,code_challenge_method,響應(yīng)302重定向,
4.3 跳轉(zhuǎn)登錄頁(yè)
請(qǐng)求
GET /Account/Login?ReturnUrl=%2Fconnect%2Fauthorize%2Fcallback%3Fclient_id%3Djs%26redirect_uri%3Dhttp%253A%252F%252Flocalhost%253A6003%252Fcallback.html%26response_type%3Dcode%26scope%3Dopenid%2520profile%2520api1%26state%3De9292cf7e4d04c03bf3fc7fe230f0378%26code_challenge%3Dkz0v3GRm8yFhmjoOYBWX2pg68N5waBd0hFVvbvuIT9E%26code_challenge_method%3DS256%26response_mode%3Dquery HTTP/1.1 Host: localhost:5001響應(yīng)
Status Code: 200 HTTP/1.1 200 OK <!DOCTYPE html> <html lang="en"> </html>重定向至登錄頁(yè),響應(yīng)登錄頁(yè)html
4.4 登錄操作
請(qǐng)求
POST /Account/Login?ReturnUrl=%2Fconnect%2Fauthorize%2Fcallback%3Fclient_id%3Djs%26redirect_uri%3Dhttp%253A%252F%252Flocalhost%253A6003%252Fcallback.html%26response_type%3Dcode%26scope%3Dopenid%2520profile%2520api1%26state%3De9292cf7e4d04c POST /Account/Login?ReturnUrl=%2Fconnect%2Fauthorize%2Fcallback%3Fclient_id%3Djs%26redirect_uri%3Dhttp%253A%252F%252Flocalhost%253A6003%252Fcallback.html%26response_type%3Dcode%26scope%3Dopenid%2520profile%2520api1%26state%3De9292cf7e4d04c03bf3fc7fe230f0378%26code_challenge%3Dkz0v3GRm8yFhmjoOYBWX2pg68N5waBd0hFVvbvuIT9E%26code_challenge_method%3DS256%26response_mode%3Dquery HTTP/1.1 Host: localhost:5001 Content-Type: application/x-www-form-urlencoded ReturnUrl=%2Fconnect%2Fauthorize%2Fcallback%3Fclient_id%3Djs%26redirect_uri%3Dhttp%253A%252F%252Flocalhost%253A6003%252Fcallback.html%26response_type%3Dcode%26scope%3Dopenid%2520profile%2520api1%26state%3De9292cf7e4d04c03bf3fc7fe230f0378%26code_challenge%3Dkz0v3GRm8yFhmjoOYBWX2pg68N5waBd0hFVvbvuIT9E%26code_challenge_method%3DS256%26response_mode%3Dquery&Username=admin&Password=admin123456%21&button=login&__RequestVerificationToken=CfDJ8EX5EDLzf1lFsdLD-61W3Pr-hyJIt5MjRQdemuM-9ab4QyRWG2omEwKHp0SZhc2a_ZjsoJEzge4QvrP_zVvkfQHq5bAki5KFTo1upo251HiQvnsFMp4ptx0KnmoHxBbIjDhBQ2VRh4fQCyJJiM791Nk&RememberLogin=false響應(yīng)
Status Code: 302 Location: /connect/authorize/callback?client_id=js&redirect_uri=http%3A%2F%2Flocalhost%3A6003%2Fcallback.html&response_type=code&scope=openid%20profile%20api1&state=e9292cf7e4d04c03bf3fc7fe230f0378&code_challenge=kz0v3GRm8yFhm Set-Cookie: idsrv.session=3CEABBB62BE1F6DDD7B793A8F5BF1803; path=/; samesite=none\r\n登錄操作,在原有的參數(shù)基礎(chǔ)上,增加Username,Password,Post提交,響應(yīng)302重定向,并Set-Cookie
4.5 驗(yàn)證授權(quán),回調(diào)返回授權(quán)碼
請(qǐng)求
GET /connect/authorize/callback?client_id=js&redirect_uri=http%3A%2F%2Flocalhost%3A6003%2Fcallback.html&response_type=code&scope=openid%20profile%20api1&state=e9292cf7e4d04c03bf3fc7fe230f0378&code_challenge=kz0v3GRm8yFhmjoOYBWX2pg68N5waBd0 Host: localhost:5001\r\n Cookie:Cookie pair: idsrv.session=3CEABBB62BE1F6DDD7B793A8F5BF1803響應(yīng)
Status Code: 302 Location: http://localhost:6003/callback.html?code=4E902EE0335BDED6D89E3775C836D3BC42848124BD1B0FCFA688CB91731C2DD5&scope=openid%20profile%20api1&state=e9292cf7e4d04c03bf3fc7fe230f0378&session_state=MP5-ftEtQxdTRi7Pw1a6HnU-dit Set-Cookie: idsrv=CfDJ8EX5EDLzf1lFsdLD-61W3PpyiWLfH7YweLeh_CTmjIJRzGGwIfhBAMhZaVaL24gZ5erWj5v38WA2DjcIqPPnSphi70aR_HZ9qnShmYfKkzrSmGTptJSESS6tanbw2RggxRPraoLf6PbthzsNJ3QZqZpB9AWJRxVvKtmq7-YFC-Kv11KHE_UHPBM3Hkpmulb35BqJ2wTumJwo8HdcJJdCPnzY0UqWCkv9wyUhQ2djvAzNceJKFiigwFsGWubmVuCse5hvp_QYLmwRdsobPP-0gSk7GnvCd6-r3ybcxYdvy2m_2XjpG1V3h34zefvLDw4sLeofllFJ5L4PUVhnqCd7DyKGb_xMAjHXvDiKgR32eCX9EZ8k1WsZsbH0NsX0xEKOlRboNNWM6mw_LXD3b_hZhDR00UbAmfjXapU6Sjss65HIPJXMhJ9HrVUleoNeFVUW-I61kd-FjXal9UxxOjv_cc5sYeIGxTnNkfT1Nc4wqQaip8ulkK0O2xYJWjPMeR-VA6rdwsvOa_iAq9fqY5KF2t4AzSoOMb62O2nwzqZZU1lpHxB5x86D0EjRUVnoR9CLfQ; path=/; samesite=none; httponly驗(yàn)證用戶名、密碼,服務(wù)端cookie已設(shè)置,驗(yàn)證成功,再次響應(yīng)302,重定向客戶端頁(yè)面callback.html,并Set-Cookie
4.6 請(qǐng)求IdentityServer4的配置端點(diǎn)-獲取token端點(diǎn)
請(qǐng)求
GET /.well-known/openid-configuration HTTP/1.1 Host: localhost:5001 Sec-Fetch-Mode: cors Referer: http://localhost:6003/callback.html?code=4E902EE0335BDED6D89E3775C836D3BC42848124BD1B0FCFA688CB91731C2DD5&scope=openid%20profile%20api1&state=e9292cf7e4d04c03bf3fc7fe230f0378&session_state=MP5-ftEtQxdTRi7Pw1a6HnU-ditlWq7kYgZrgydLbAQ.C34DCC1705940F3F7C5D34685AB51C9F響應(yīng)
200 OK Date: Sun, 12 Jul 2020 17:38:32 GMT Content-Type: application/json; charset=UTF-8 {"issuer":"http://localhost:5001","jwks_uri":"http://localhost:5001/.well-known/openid-configuration/jwks","authorization_endpoint":"http://localhost:5001/connect/authorize","token_endpoint":"http://localhost:5001/connect/token","userinfo_endpoint":"http://localhost:5001/connect/userinfo","end_session_endpoint":"http://localhost:5001/connect/endsession","check_session_iframe":"http://localhost:5001/connect/checksession","revocation_endpoint":"http://localhost:5001/connect/revocation","introspection_endpoint":"http://localhost:5001/connect/introspect","device_authorization_endpoint":"http://localhost:5001/connect/deviceauthorization","frontchannel_logout_supported":true,"frontchannel_logout_session_supported":true,"backchannel_logout_supported":true,"backchannel_logout_session_supported":true,"scopes_supported":["openid","profile","api1","offline_access"],"claims_supported":["sub","name","family_name","given_name","middle_name","nickname","preferred_username","profile","picture","website","gender","birthdate","zoneinfo","locale","updated_at"],"grant_types_supported":["authorization_code","client_credentials","refresh_token","implicit","password","urn:ietf:params:oauth:grant-type:device_code"],"response_types_supported":["code","token","id_token","id_token token","code id_token","code token","code id_token token"],"response_modes_supported":["form_post","query","fragment"],"token_endpoint_auth_methods_supported":["client_secret_basic","client_secret_post"],"id_token_signing_alg_values_supported":["RS256"],"subject_types_supported":["public"],"code_challenge_methods_supported":["plain","S256"],"request_parameter_supported":true}獲取token端點(diǎn)值
4.7 請(qǐng)求token端點(diǎn)
請(qǐng)求
POST /connect/token HTTP/1.1 Host: localhost:5001 Content-Type: application/x-www-form-urlencoded Sec-Fetch-Mode: cors Referer: http://localhost:6003/callback.html?code=4E902EE0335BDED6D89E3775C836D3BC42848124BD1B0FCFA688CB91731C2DD5&scope=openid%20profile%20api1&state=e9292cf7e4d04c03bf3fc7fe230f0378&session_state=MP5-ftEtQxdTRi7Pw1a6HnU-ditlWq7kYgZrgydLbAQ.C34DCC1705940F3F7C5D34685AB51C9F Accept-Encoding: gzip, deflate, br Accept-Language: en,zh-CN;q=0.9,zh;q=0.8client_id=js&code=4E902EE0335BDED6D89E3775C836D3BC42848124BD1B0FCFA688CB91731C2DD5&redirect_uri=http%3A%2F%2Flocalhost%3A6003%2Fcallback.html&code_verifier=e661671994bd4eb89bb9e4da214e34f0970c24c9a36e41fe9e05aec433c604c2f721da29216345b0898445e5e105c86f&grant_type=authorization_code響應(yīng)
Status Code: 200 {"id_token": "eyJhbGciOiJSUzI1NiIsImtpZCI6Ijc2OEFDMTBCNEEzNzI4RTIwNjQ0MDU4QjZFREY1MDUxIiwidHlwIjoiSldUIn0.eyJuYmYiOjE1OTQ1NzU1MTIsImV4cCI6MTU5NDU3NTgxMiwiaXNzIjoiaHR0cDovL2xvY2FsaG9zdDo1MDAxIiwiYXVkIjoianMiLCJpYXQiOjE1OTQ1NzU1MTIsImF0X2hhc2giOiJhaU9rX05xeDh0OERXeTc5cFo3WFhBIiwic19oYXNoIjoiWkllczRfaldVMEFBaTI0ZUY4Yjg1dyIsInNpZCI6IjNDRUFCQkI2MkJFMUY2REREN0I3OTNBOEY1QkYxODAzIiwic3ViIjoiMSIsImF1dGhfdGltZSI6MTU5NDU3NTUxMiwiaWRwIjoibG9jYWwiLCJhbXIiOlsicHdkIl19.VmdopUrWH4rcrJp3nXcE-LLNodowQh6n0-HjN_aZZNOj1xPECwG_g0-nY9N9q-jNeapkIrWk2U2Y9liUXuBAOLHhT0Txou4dNhAdMIvYJ8SKRSgh06SEbpGT_hDtN345YZd9IJSjGWo3q_B04p03pw6S92tQp6ae74v1mMAgCskVnKth0SWpPqUPSuZjSdlcuzhA7OvXlz3wmeGJPu5c0jC1BBzrrM1_WmFvUCmwCo9q3Z0MLcz6eq1JZafhSkkRSAgTJdWIdrq6w7Yj1DInETebOhJrt3Yl7jGVAjJqK1WMnJym3J4n9d5GYfv9wA4eu3GgKvG_rax1GjgtV3zR0g","access_token": "eyJhbGciOiJSUzI1NiIsImtpZCI6Ijc2OEFDMTBCNEEzNzI4RTIwNjQ0MDU4QjZFREY1MDUxIiwidHlwIjoiYXQrand0In0.eyJuYmYiOjE1OTQ1NzU1MTIsImV4cCI6MTU5NDU3OTExMiwiaXNzIjoiaHR0cDovL2xvY2FsaG9zdDo1MDAxIiwiY2xpZW50X2lkIjoianMiLCJzdWIiOiIxIiwiYXV0aF90aW1lIjoxNTk0NTc1NTEyLCJpZHAiOiJsb2NhbCIsImp0aSI6IkU3OTdDOTI0QUJFOTI1QTQ3N0Y1NDVCQUVFRkRGMUE3Iiwic2lkIjoiM0NFQUJCQjYyQkUxRjZEREQ3Qjc5M0E4RjVCRjE4MDMiLCJpYXQiOjE1OTQ1NzU1MTIsInNjb3BlIjpbIm9wZW5pZCIsInByb2ZpbGUiLCJhcGkxIl0sImFtciI6WyJwd2QiXX0.Cl4u3bU9bm0mG9qjn52WwstbPmuhBetKkEIRgVENIU_4hurJ8fRPiNc3zzl0tzgIw0_yvHy8eyA6EyVfSMyQZ77ao0TjEkBcTu62H7eKTHWrdKyp0eEhcxRiVvAYAQcFP2NPva8z0zZiVUUnE0q6-WiE7P_hDF8Ljs6AyYAS4khWX9iG-WoSlqDlalOo7ohU7gGleIpnlH5LUvQpkDVHbOzCNviJH6r4VbqT7llnIDNNjMwy9cwh3TJcYNsFZjTL3jsQtmbNv9ajmNBZKhWvGSRN_6ywgbPcL54FEqVTe3hfwdcSjHCSV2Owzcu6at8UplAm-Kd0T09ay6ChXWz67g","expires_in": 3600,"token_type": "Bearer","scope": "openid profile api1" }以code,scope,client_id,code_verifier,grant_type等必要參數(shù)作為post參數(shù)請(qǐng)求token端點(diǎn),返回id_token、access_token、expires_in、scope等.
4.8 請(qǐng)求userinfo端點(diǎn)
預(yù)檢請(qǐng)求
OPTIONS /connect/userinfo HTTP/1.1 Host: localhost:5001 Referer: http://localhost:6003/callback.html?code=4E902EE0335BDED6D89E3775C836D3BC42848124BD1B0FCFA688CB91731C2DD5&scope=openid%20profile%20api1&state=e9292cf7e4d04c03bf3fc7fe230f0378&session_state=MP5-ftEtQxdTRi7Pw1a6HnU-ditlWq7kYgZrgydLbAQ.C34DCC1705940F3F7C5D34685AB51C9F響應(yīng)
Status Code: 204 Access-Control-Allow-Headers: authorization\r\n Access-Control-Allow-Methods: GET\r\n Access-Control-Allow-Origin: http://localhost:6003\r\n正式請(qǐng)求
Host: localhost:5001 Authorization: Bearer eyJhbGciOiJSUzI1NiIsImtpZCI6Ijc2OEFDMTBCNEEzNzI4RTIwNjQ0MDU4QjZFREY1MDUxIiwidHlwIjoiYXQrand0In0.eyJuYmYiOjE1OTQ1NzU1MTIsImV4cCI6MTU5NDU3OTExMiwiaXNzIjoiaHR0cDovL2xvY2FsaG9zdDo1MDAxIiwiY2xpZW50X2lkIjoianMiLCJzdWIiOiIxIiwiYXV0aF90aW1lIjoxNTk0NTc1NTEyLCJpZHAiOiJsb2NhbCIsImp0aSI6IkU3OTdDOTI0QUJFOTI1QTQ3N0Y1NDVCQUVFRkRGMUE3Iiwic2lkIjoiM0NFQUJCQjYyQkUxRjZEREQ3Qjc5M0E4RjVCRjE4MDMiLCJpYXQiOjE1OTQ1NzU1MTIsInNjb3BlIjpbIm9wZW5pZCIsInByb2ZpbGUiLCJhcGkxIl0sImFtciI6WyJwd2QiXX0.Cl4u3bU9bm0mG9qjn52WwstbPmuhBetKkEIRgVENIU_4hurJ8fRPiNc3zzl0tzgIw0_yvHy8eyA6EyVfSMyQZ77ao0TjEkBcTu62H7eKTHWrdKyp0eEhcxRiVvAYAQcFP2NPva8z0zZiVUUnE0q6-WiE7P_hDF8Ljs6AyYAS4khWX9iG-WoSlqDlalOo7ohU7gGleIpnlH5LUvQpkDVHbOzCNviJH6r4VbqT7llnIDNNjMwy9cwh3TJcYNsFZjTL3jsQtmbNv9ajmNBZKhWvGSRN_6ywgbPcL54FEqVTe3hfwdcSjHCSV2Owzcu6at8UplAm-Kd0T09ay6ChXWz67g Referer: http://localhost:6003/callback.html?code=4E902EE0335BDED6D89E3775C836D3BC42848124BD1B0FCFA688CB91731C2DD5&scope=openid%20profile%20api1&state=e9292cf7e4d04c03bf3fc7fe230f0378&session_state=MP5-ftEtQxdTRi7Pw1a6HnU-ditlWq7kYgZrgydLbAQ.C34DCC1705940F3F7C5D34685AB51C9F Accept-Encoding: gzip, deflate, br Accept-Language: en,zh-CN;q=0.9,zh;q=0.8響應(yīng)
Status Code: 200 {"name": "RandyField","given_name": "Randy","family_name": ["Field","Randy"],"website": "http://www.randyfield.cn","sub": "1" }4.9 請(qǐng)求checksession端點(diǎn)
請(qǐng)求
GET /connect/checksession HTTP/1.1 Host: localhost:5001 Cookie: .AspNetCore.Antiforgery.oLdxsluyV7s=CfDJ8EX5EDLzf1lFsdLD-61W3PplD2jEFwzyz4r_NCYMSVOLnWqf5HrxwUtY6ouOI2VHKD9vJdF48KUqkNQeTHXe3hrm8uf1GL_v1917E6-Km7WF3V06G4cBHNvrlJQuQF7k__7FPhPVySgmKgwqfAPky8w; idsrv.session=3CEABBB62BE1F6DDD7B793A8F5BF1803; idsrv=CfDJ8EX5EDLzf1lFsdLD-61W3PpyiWLfH7YweLeh_CTmjIJRzGGwIfhBAMhZaVaL24gZ5erWj5v38WA2DjcIqPPnSphi70aR_HZ9qnShmYfKkzrSmGTptJSESS6tanbw2RggxRPraoLf6PbthzsNJ3QZqZpB9AWJRxVvKtmq7-YFC-Kv11KHE_UHPBM3Hkpmulb35BqJ2wTumJwo8HdcJJdCPnzY0UqWCkv9wyUhQ2djvAzNceJKFiigwFsGWubmVuCse5hvp_QYLmwRdsobPP-0gSk7GnvCd6-r3ybcxYdvy2m_2XjpG1V3h34zefvLDw4sLeofllFJ5L4PUVhnqCd7DyKGb_xMAjHXvDiKgR32eCX9EZ8k1WsZsbH0NsX0xEKOlRboNNWM6mw_LXD3b_hZhDR00UbAmfjXapU6Sjss65HIPJXMhJ9HrVUleoNeFVUW-I61kd-FjXal9UxxOjv_cc5sYeIGxTnNkfT1Nc4wqQaip8ulkK0O2xYJWjPMeR-VA6rdwsvOa_iAq9fqY5KF2t4AzSoOMb62O2nwzqZZU1lpHxB5x86D0EjRUVnoR9CLfQ響應(yīng)
Status Code: 200 Content-Type: text/html; charset=UTF-8<!DOCTYPE html> <!--Copyright (c) Brock Allen & Dominick Baier. All rights reserved.--> <!--Licensed under the Apache License, Version 2.0. See LICENSE in the project root for license information.--> <html> <head> <meta http-equiv='X-UA-Compatible' content='IE=edge' /> <title>Check Session IFrame</title> </head> <body> </body> </html>之后又請(qǐng)求了一次/.well-known/openid-configuration,/connect/checksession
第一次與第二次/connect/checksession幾乎一樣的請(qǐng)求與響應(yīng),唯一的差別
Referer不同
第一次:http://localhost:6003/callback.html?code=4E902EE0335BDED6D89E3775C836D3BC42848124BD1B0FCFA688CB91731C2DD5&scope=openid%20profile%20api1&state=e9292cf7e4d04c03bf3fc7fe230f0378&session_state=MP5-ftEtQxdTRi7Pw1a6HnU-ditlWq7kYgZrgydLbAQ.C34DCC1705940F3F7C5D34685AB51C9F
第二次:http://localhost:6003/index.html
從結(jié)果推導(dǎo)過(guò)程,第一次,是回調(diào)頁(yè)面callback.html,請(qǐng)求了/connect/checksession,獲取了一個(gè)iframe的html,callback.html中window.location = "index.html";由會(huì)重定向到index.html,可以推導(dǎo)出,這里是幫index.html請(qǐng)求渲染內(nèi)容,因?yàn)閕ndex中有一個(gè)隱藏的iframe,如圖
兩次checksession之間還有一次/.well-known/openid-configuration請(qǐng)求,這次Referer已經(jīng)是index.html,說(shuō)明已經(jīng)發(fā)生重定向了,重定向之后,由于document中有這個(gè)iframe,自然就會(huì)再發(fā)起一次請(qǐng)求,所以這兩次的Referer參數(shù)不一樣。
4.10 注銷登錄操作
①.請(qǐng)求endsession端點(diǎn)
請(qǐng)求
GET /connect/endsession?id_token_hint=eyJhbGciOiJSUzI1NiIsImtpZCI6Ijc2OEFDMTBCNEEzNzI4RTIwNjQ0MDU4QjZFREY1MDUxIiwidHlwIjoiSldUIn0.eyJuYmYiOjE1OTQ1NzU1MTIsImV4cCI6MTU5NDU3NTgxMiwiaXNzIjoiaHR0cDovL2xvY2FsaG9zdDo1MDAxIiwiYXVkIjoianMiLCJpYXQiOjE1OTQ1NzU1MTIsImF0X2hhc2giOiJhaU9rX05xeDh0OERXeTc5cFo3WFhBIiwic19oYXNoIjoiWkllczRfaldVMEFBaTI0ZUY4Yjg1dyIsInNpZCI6IjNDRUFCQkI2MkJFMUY2REREN0I3OTNBOEY1QkYxODAzIiwic3ViIjoiMSIsImF1dGhfdGltZSI6MTU5NDU3NTUxMiwiaWRwIjoibG9jYWwiLCJhbXIiOlsicHdkIl19.VmdopUrWH4rcrJp3nXcE-LLNodowQh6n0-HjN_aZZNOj1xPECwG_g0-nY9N9q-jNeapkIrWk2U2Y9liUXuBAOLHhT0Txou4dNhAdMIvYJ8SKRSgh06SEbpGT_hDtN345YZd9IJSjGWo3q_B04p03pw6S92tQp6ae74v1mMAgCskVnKth0SWpPqUPSuZjSdlcuzhA7OvXlz3wmeGJPu5c0jC1BBzrrM1_WmFvUCmwCo9q3Z0MLcz6eq1JZafhSkkRSAgTJdWIdrq6w7Yj1DInETebOhJrt3Yl7jGVAjJqK1WMnJym3J4n9d5GYfv9wA4eu3GgKvG_rax1GjgtV3zR0g&post_logout_redirect_uri=http%3A%2F%2Flocalhost%3A6003%2Findex.html Host: localhost:5001 Connection: keep-alive Cookie: .AspNetCore.Antiforgery.oLdxsluyV7s=CfDJ8EX5EDLzf1lFsdLD-61W3PplD2jEFwzyz4r_NCYMSVOLnWqf5HrxwUtY6ouOI2VHKD9vJdF48KUqkNQeTHXe3hrm8uf1GL_v1917E6-Km7WF3V06G4cBHNvrlJQuQF7k__7FPhPVySgmKgwqfAPky8w; idsrv.session=3CEABBB62BE1F6DDD7B793A8F5BF1803; idsrv=CfDJ8EX5EDLzf1lFsdLD-61W3PpyiWLfH7YweLeh_CTmjIJRzGGwIfhBAMhZaVaL24gZ5erWj5v38WA2DjcIqPPnSphi70aR_HZ9qnShmYfKkzrSmGTptJSESS6tanbw2RggxRPraoLf6PbthzsNJ3QZqZpB9AWJRxVvKtmq7-YFC-Kv11KHE_UHPBM3Hkpmulb35BqJ2wTumJwo8HdcJJdCPnzY0UqWCkv9wyUhQ2djvAzNceJKFiigwFsGWubmVuCse5hvp_QYLmwRdsobPP-0gSk7GnvCd6-r3ybcxYdvy2m_2XjpG1V3h34zefvLDw4sLeofllFJ5L4PUVhnqCd7DyKGb_xMAjHXvDiKgR32eCX9EZ8k1WsZsbH0NsX0xEKOlRboNNWM6mw_LXD3b_hZhDR00UbAmfjXapU6Sjss65HIPJXMhJ9HrVUleoNeFVUW-I61kd-FjXal9UxxOjv_cc5sYeIGxTnNkfT1Nc4wqQaip8ulkK0O2xYJWjPMeR-VA6rdwsvOa_iAq9fqY5KF2t4AzSoOMb62O2nwzqZZU1lpHxB5x86D0EjRUVnoR9CLfQ響應(yīng)
Status Code: 302 Location: http://localhost:5001/Account/Logout?logoutId=CfDJ8EX5EDLzf1lFsdLD-61W3Pq-tO1b1UEAB4vvmYhY4sokyl8em0HlVYGX9otqLmnglBnG6V_RukkVflCbku5Elb72VsJkntUDrh6G1AP1ctnkCWhiuN9lIBouTf9swekyYrj8H0Q-5iHISwsYmXz00kEPqWR1-7-DoXbv2g3Dxtt3fPxVN5WmFd0-I7zuLoyPrpiqz62TYGUNygB1qOt0BXsvwVLWyl_amuMVbqUgJkvkbS4049YYVK7W0fl55L66mDnBEF5ktdixHE9ld3_dso-4FL8ppa-wdUq9Wy6JPo5p1S4BIf_LCfX0Cp4eDVow5sgVtpPfbamRX-pRHco_-H8jifrDg5xVmxupY6NAMgzK8Sbn6lZhW_KjkkpTyWRiE7kfc_uaYAeykfDGqvmAfGq7-9suIwGd3vvJw2-pn6aVuzTH4o3SycophXWv-5BUYQ請(qǐng)求服務(wù)端endsession端點(diǎn),傳遞參數(shù)id-token,響應(yīng)302重定向注銷登錄頁(yè)面。
②.請(qǐng)求Logout頁(yè)面
請(qǐng)求
GET /Account/Logout?logoutId=CfDJ8EX5EDLzf1lFsdLD-61W3Pq-tO1b1UEAB4vvmYhY4sokyl8em0HlVYGX9otqLmnglBnG6V_RukkVflCbku5Elb72VsJkntUDrh6G1AP1ctnkCWhiuN9lIBouTf9swekyYrj8H0Q-5iHISwsYmXz00kEPqWR1-7-DoXbv2g3Dxtt3fPxVN5WmFd0-I7zuLoyPrpiqz62TYGUNygB1qOt0BXsvwVLWyl_amuMVbqUgJkvkbS4049YYVK7W0fl55L66mDnBEF5ktdixHE9ld3_dso-4FL8ppa-wdUq9Wy6JPo5p1S4BIf_LCfX0Cp4eDVow5sgVtpPfbamRX-pRHco_-H8jifrDg5xVmxupY6NAMgzK8Sbn6lZhW_KjkkpTyWRiE7kfc_uaYAeykfDGqvmAfGq7-9suIwGd3vvJw2-pn6aVuzTH4o3SycophXWv-5BUYQ HTTP/1.1 Host: localhost:5001 Cookie: .AspNetCore.Antiforgery.oLdxsluyV7s=CfDJ8EX5EDLzf1lFsdLD-61W3PplD2jEFwzyz4r_NCYMSVOLnWqf5HrxwUtY6ouOI2VHKD9vJdF48KUqkNQeTHXe3hrm8uf1GL_v1917E6-Km7WF3V06G4cBHNvrlJQuQF7k__7FPhPVySgmKgwqfAPky8w; idsrv.session=3CEABBB62BE1F6DDD7B793A8F5BF1803; idsrv=CfDJ8EX5EDLzf1lFsdLD-61W3PpyiWLfH7YweLeh_CTmjIJRzGGwIfhBAMhZaVaL24gZ5erWj5v38WA2DjcIqPPnSphi70aR_HZ9qnShmYfKkzrSmGTptJSESS6tanbw2RggxRPraoLf6PbthzsNJ3QZqZpB9AWJRxVvKtmq7-YFC-Kv11KHE_UHPBM3Hkpmulb35BqJ2wTumJwo8HdcJJdCPnzY0UqWCkv9wyUhQ2djvAzNceJKFiigwFsGWubmVuCse5hvp_QYLmwRdsobPP-0gSk7GnvCd6-r3ybcxYdvy2m_2XjpG1V3h34zefvLDw4sLeofllFJ5L4PUVhnqCd7DyKGb_xMAjHXvDiKgR32eCX9EZ8k1WsZsbH0NsX0xEKOlRboNNWM6mw_LXD3b_hZhDR00UbAmfjXapU6Sjss65HIPJXMhJ9HrVUleoNeFVUW-I61kd-FjXal9UxxOjv_cc5sYeIGxTnNkfT1Nc4wqQaip8ulkK0O2xYJWjPMeR-VA6rdwsvOa_iAq9fqY5KF2t4AzSoOMb62O2nwzqZZU1lpHxB5x86D0EjRUVnoR9CLfQ響應(yīng)
Status Code: 200 Content-Type: text/html; charset=utf-8 Expires: Thu, 01 Jan 1970 00:00:00 GMT Set-Cookie: idsrv.session=.; expires=Fri, 12 Jul 2019 17:38:40 GMT; path=/; samesite=none Set-Cookie: idsrv=; expires=Thu, 01 Jan 1970 00:00:00 GMT; path=/; samesite=none; httponly <!DOCTYPE html> <html lang="en"> <head><meta charset="utf-8" /><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width, initial-scale=1.0, shrink-to-fit=no" /><title>IdentityServer4</title> <link rel="icon" type="image/x-icon" href="/favicon.ico" /><link rel="shortcut icon" type="image/x-icon" href="/favicon.ico" /><link rel="stylesheet" href="/lib/bootstrap/dist/css/bootstrap.min.css" /><link rel="stylesheet" href="/css/site.css" /> </head> <body> <div class="nav-page"><nav class="navbar navbar-expand-lg navbar-dark bg-dark"><a href="/" class="navbar-brand"><img src="/icon.png" class="icon-banner">IdentityServer4</a> </nav> </div><div class="container body-container"> <div class="logged-out-page"><h1>Logout<small>You are now logged out</small></h1><div>Click <a class="PostLogoutRedirectUri" href="http://localhost:6003/index.html">here</a> to return to the<span>JavaScript Client</span> application.</div><iframe width="0" height="0" class="signout" src="http://localhost:5001/connect/endsession/callback?endSessionId=CfDJ8EX5EDLzf1lFsdLD-61W3Ppjdh7zkU7fvaRvtKK_djZ_wTALkKC4YyDjpZmbnIsfrQa2BTfaRz1AkiCNlJLVYT2mUZA0Os9WyOBB1QDhYOjscWlomm6RWpUDy4L8tjr1mTdkH0T5IXOUsF7wcRrP-6ssERsPyswxqg9bFwkjuYlZnQYZOFSdFwGV8T3uru7BVhP8HywA6JeyYdUC-CQl_02vdiN3h5_bfxcP6sSbuu0kq8Dvs1GRXZT2B813Wy7DI_fmnWwyMiy2isjdpZjxx2E"></iframe> </div></div><script src="/lib/jquery/dist/jquery.slim.min.js"></script><script src="/lib/bootstrap/dist/js/bootstrap.bundle.min.js"></script> </body> </html>重定向至Logout頁(yè)面,并通過(guò)Set-Cookie把IndentityServer-localhost:5001的cookie置為空,且響應(yīng)一段包含隱藏src="http://localhost:5001/connect/endsession/callback"的iframe的html
③.觸發(fā)endsession回調(diào)
請(qǐng)求
GET /connect/endsession/callback?endSessionId=CfDJ8EX5EDLzf1lFsdLD-61W3Ppjdh7zkU7fvaRvtKK_djZ_wTALkKC4YyDjpZmbnIsfrQa2BTfaRz1AkiCNlJLVYT2mUZA0Os9WyOBB1QDhYOjscWlomm6RWpUDy4L8tjr1mTdkH0T5IXOUsF7wcRrP-6ssERsPyswxqg9bFwkjuYlZnQYZOFSdFwGV8T3uru7BVhP8HywA6JeyYdUC-CQl_02vdiN3h5_bfxcP6sSbuu0kq8Dvs1GRXZT2B813Wy7DI_fmnWwyMiy2isjdpZjxx2E HTTP/1.1 Host: localhost:5001 Sec-Fetch-Dest: iframe Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed- Cookie: .AspNetCore.Antiforgery.oLdxsluyV7s=CfDJ8EX5EDLzf1lFsdLD-61W3PplD2jEFwzyz4r_NCYMSVOLnWqf5HrxwUtY6ouOI2VHKD9vJdF48KUqkNQeTHXe3hrm8uf1GL_v1917E6-Km7WF3V06G4cBHNvrlJQuQF7k__7FPhPVySgmKgwqfAPky8w響應(yīng)
Status Code: 200 Date: Sun, 12 Jul 2020 17:38:39 GMT Content-Type: text/html; charset=UTF-8 Server: Kestrel Cache-Control: no-store, no-cache, max-age=0 Pragma: no-cache Transfer-Encoding: chunked Content-Security-Policy: default-src 'none'; style-src 'sha256-u+OupXgfekP+x/f6rMdoEAspPCYUtca912isERnoEjY=' X-Content-Security-Policy: default-src 'none'; style-src 'sha256-u+OupXgfekP+x/f6rMdoEAspPCYUtca912isERnoEjY=' <!DOCTYPE html><html><style>iframe{display:none;width:0;height:0;}</style><body></body></html>觸發(fā)回調(diào),cookie已置為空
5.總結(jié)
這里面確實(shí)是PKCE的授權(quán)碼模式,其次整個(gè)客戶端(SPA)與服務(wù)端交互過(guò)程有很多騷操作,比如在html里面返回一段隱藏的iframe,從而觸發(fā)回調(diào)。下一篇,我們將會(huì)繼續(xù)討論在MVC應(yīng)用中的IdentityServer4授權(quán)碼流程,同樣是PKCE,但是同樣具有一些奇技淫巧的騷操作,待你我共賞。
“對(duì)了,有個(gè)小貼士,網(wǎng)易有道詞典跟WireShark有沖突,打開就是未響應(yīng),使用時(shí),關(guān)閉有道詞典即可,這個(gè)坑簡(jiǎn)直了,真是王大錘的萬(wàn)萬(wàn)沒想到。
”參考鏈接
https://www.ruanyifeng.com/blog/2014/05/oauth_2_0.html
https://www.zhihu.com/question/31896659
https://tonyxu.io/zh/posts/2018/oauth2-pkce-flow/
https://www.cnblogs.com/hubwang2020/p/12671712.html
長(zhǎng)按二維碼關(guān)注點(diǎn)外賣,先領(lǐng)券總結(jié)
以上是生活随笔為你收集整理的IdentityServer4(六)授权码流程原理之SPA的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 在 “相对” 高薪面前,任何的喊冤叫屈都
- 下一篇: 使用 gRPCurl 调试.NET 5的