IdentityServer4筆記整理(更新中)

原文: IdentityServer4筆記整理(更新中)

博客與筆記沒法實時同步, 筆記最新連接

OAuth 2.0

定義:OAuth 2.0是一個開放受權標準:容許資源全部者(用戶)受權第三方應用訪問該用戶在某服務上的特定私有資源,但不提供帳號密碼給第三方應用。
安全提示:受權碼和全部令牌必須經過Tsl加密傳輸。進入OAuth 2.0官網html

OAuth 2.0協議流程圖

     +--------+                               +---------------+
     |        |--(A)- Authorization Request ->|   Resource    |
     |        |                               |     Owner     |
     |        |<-(B)-- Authorization Grant ---|               |
     |        |                               +---------------+
     |        |
     |        |                               +---------------+
     |        |--(C)-- Authorization Grant -->| Authorization |
     | Client |                               |     Server    |
     |        |<-(D)----- Access Token -------|               |
     |        |                               +---------------+
     |        |
     |        |                               +---------------+
     |        |--(E)----- Access Token ------>|    Resource   |
     |        |                               |     Server    |
     |        |<-(F)--- Protected Resource ---|               |
     +--------+                               +---------------+
                         (OAuth 2.0協議流程)
    (A)客戶端發起受權請求,客戶端能夠向資源全部者直接發起受權請求,建議的作法是將受權服務器做爲中間人,客戶端向受權服務器發起受權請求
    (B)客戶端收到受權憑證(和具體的受權類型有關)
    (C)客戶端經過受權憑證向受權服務器請求訪問令牌
    (D)受權服務器驗證受權憑證和客戶端,若是經過驗證,返回給客戶端訪問令牌
    (E)客戶端經過訪問令牌向資源服務器發出訪問請求
    (F)資源服務器驗證訪問令牌有效後,返回請求的資源

受權碼模式

受權碼模式:code的生命週期必須短暫、或者只能單次使用,若是code被屢次使用,受權服務器必須使該code生成的全部令牌失效。訪問令牌由client後端保存。前端

     +----------+
     | Resource |
     |   Owner  |
     |          |
     +----------+
          ^
          |
         (B)
     +----|-----+          Client Identifier      +---------------+
     |         -+----(A)-- & Redirection URI ---->|               |
     |  User-   |                                 | Authorization |
     |  Agent  -+----(B)-- User authenticates --->|     Server    |
     |          |                                 |               |
     |         -+----(C)-- Authorization Code ---<|               |
     +-|----|---+                                 +---------------+
       |    |                                         ^      v
      (A)  (C)                                        |      |
       |    |                                         |      |
       ^    v                                         |      |
     +---------+                                      |      |
     |         |>---(D)-- Authorization Code ---------'      |
     |  Client |          & Redirection URI                  |
     |         |                                             |
     |         |<---(E)----- Access Token -------------------'
     +---------+       (w/ Optional Refresh Token)
    (A)客戶端引導用戶代理(瀏覽器)到達受權終結點,並攜帶參數:response_type(code)、client_id、redirect_uri、scope、state
    (B)受權服務器經過用戶代理(瀏覽器)驗證資源全部者,並肯定資源全部者是否給予客戶端受權
    (C)驗證資源全部者成功,而且容許受權,受權服務器將用戶代理(瀏覽器)重定向到redirect_uri,並返回code和受權請求的state
    (D)客戶端向受權服務器令牌終結點請求令牌,攜帶參數:grant_type、code、redirect_uri、client_id、secret(可選)
    (E)受權服務器驗證code、client_id、secret是否有效,並驗證redirect_uri是否與步驟C中一致,若是驗證成功,攜帶Access Token將用戶代理(瀏覽器)重定向到redirect_uri

簡化模式

要點:不支持刷新令牌,訪問令牌編碼在Url中,因此會有暴露的風險(在Oauth2.0官網中已經不推薦使用)web

     +----------+
     | Resource |
     |  Owner   |
     |          |
     +----------+
          ^
          |
         (B)
     +----|-----+          Client Identifier     +---------------+
     |         -+----(A)-- & Redirection URI --->|               |
     |  User-   |                                | Authorization |
     |  Agent  -|----(B)-- User authenticates -->|     Server    |
     |          |                                |               |
     |          |<---(C)--- Redirection URI ----<|               |
     |          |          with Access Token     +---------------+
     |          |            in Fragment
     |          |                                +---------------+
     |          |----(D)--- Redirection URI ---->|   Web-Hosted  |
     |          |          without Fragment      |     Client    |
     |          |                                |    Resource   |
     |     (F)  |<---(E)------- Script ---------<|               |
     |          |                                +---------------+
     +-|--------+
       |    |
      (A)  (G) Access Token
       |    |
       ^    v
     +---------+
     |         |
     |  Client |
     |         |
     +---------+
    (A)客戶端引導用戶代理(瀏覽器)到達受權終結點,並攜帶參數:response_type(token)、client_id、redirect_uri、scope、state
    (B)受權服務器經過用戶代理(瀏覽器)驗證資源全部者,並肯定資源全部者是否給予客戶端受權
    (C)驗證資源全部者成功,而且容許受權,受權服務器將用戶代理(瀏覽器)重定向到redirect_uri,redirect_uri的URL 錨點(fragment)部分包括了響應參數(以#hash值的方式追加):access_token、token_type、expires_in、scope、state
    (D)用戶代理(瀏覽器)向redirect_uri發出請求,但不包括URL 錨點,用戶代理在本地保存了fragment。
    (E)redirect_uri的服務器返回頁面給瀏覽器,該頁面須要包含解碼fragment的腳本。
    (F)瀏覽器接收到頁面後,執行腳本,將C中的響應參數解碼出來
    (G)用戶代理(瀏覽器)將響應參數傳遞給客戶端

OpenID Connect(OIDC)

定義:它在OAuth2上構建了一個身份層,是一個基於OAuth2協議的身份認證標準協議算法

image

OIDC協議流程圖

+--------+                                   +--------+
|        |                                   |        |
|        |---------(1) AuthN Request-------->|        |
|        |                                   |        |
|        |  +--------+                       |        |
|        |  |        |                       |        |
|        |  |  End-  |<--(2) AuthN & AuthZ-->|        |
|        |  |  User  |                       |        |
|   RP   |  |        |                       |   OP   |
|        |  +--------+                       |        |
|        |                                   |        |
|        |<--------(3) AuthN Response--------|        |
|        |                                   |        |
|        |---------(4) UserInfo Request----->|        |
|        |                                   |        |
|        |<--------(5) UserInfo Response-----|        |
|        |                                   |        |
+--------+                                   +--------+
EU:End User:一我的類用戶。
RP:Relying Party ,用來代指OAuth2中的受信任的客戶端,身份認證和受權信息的消費方;
OP:OpenID Provider,有能力提供EU認證的服務(好比OAuth2中的受權服務),用來爲RP提供EU的身份認證信息;
ID Token:JWT格式的數據,包含EU身份認證的信息。
UserInfo Endpoint:用戶信息接口(受OAuth2保護),當RP使用Access Token訪問時,返回受權用戶的信息,此接口必須使用HTTPS。
    (1).RP發送一個認證請求給OP;
    (2).OP對EU進行身份認證,而後提供受權;
    (3).OP把ID Token和Access Token(須要的話)返回給RP;
    (4).RP使用Access Token發送一個請求到UserInfo EndPoint;
    (5).UserInfo EndPoint返回EU的Claims。

OIDC在OAuth之上的擴展

  • [ ] Scope:openid(用來區分這是一個OIDC的Authentication請求,而不是OAuth2的Authorization請求)
  • [ ] response_type:id_token,在implicit模式下請求id_token
  • [ ] id_token:身份令牌,是一個受權服務器提供的包含用戶信息(由一組Cliams構成以及其餘輔助的Cliams)的JWT格式的數據結構
  • [ ] UserInfo Endpoint:經過id_token從用戶信息終結點得到一組EU相關的Claims,好比能夠將Claims從token移除,避免token過大,只保留sub,經過UserInfo Endpoint查詢Claims
"response_type"參數值 OIDC受權類型
code Authorization Code Flow
id_token token Implicit Flow
code id_token Hybrid Flow
  • Authorization Code Flow:從受權終結點返回code,從令牌終結點返回token
  • Implicit Flow:從受權終結點返回全部token
  • Hybrid Flow:id_token返回給前端,access_token在後端保存(access_token的安全性要求比id_token)高

JSON Web Token

定義:JWT是一個定義一種緊湊的,自包含的而且提供防篡改機制的傳遞數據的方式的標準協議json

JWT格式

JWT由3部分構成:header.payload.signature
在IdSrv中,payload中的鍵值對根據token類型和受權流程的不一樣有所區別
header:
{
  "alg": "RS256",//簽名算法
  "kid": "9dcf733a1192a6da053e64c6ee22ff87",
  "typ": "JWT"//token類型
}
payload://須要傳遞的數據
{
  "nbf": 1556591630,//該jwt在此以前無效
  "exp": 1556595230,//該jwt在此以後無效
  "iss": "http://localhost:7102",//jwt頒發者
  "iat": 1516239022,//jwt頒發時間
  "aud": "http://localhost:7102/resources",//jwt接收者
  "client_id": "jsImplicit",
  "sub": "SubjectId",//用戶惟一id
  "auth_time": 1556591629,//受權時間
  "idp": "local",//identityProvider
  "name": "Username",
  "scope": [
    "openid",
    "profile"
  ],
  "amr": [
    "pwd"//authenticationMethod
  ]
}
signature://token生成方使用私匙生成token,token消費方使用用公匙驗證token是否被修改過
RSASHA256(
  base64UrlEncode(header) + "." +base64UrlEncode(payload),Public Key,Private Key
  )
expires_in="exp"-"nbf"

IdentityServer4

客戶端憑證模式

不支持刷新令牌、沒法訪問用戶資源scope(openid、profile、email等)後端

Request:
    POST /connect/token HTTP/1.1  #請求方式只能爲post
    Host: idsrv-server.com
    Content-type: application/x-www-form-urlencoded #參數只能放在body裏面
    body:
    {
        grant_type:client_credentials
        client_id:ClientCredentials
        client_secret:iwiaXNzIjoibnVsbCIsImF1ZCI6WyJudWxsL3Jlc291cmNlcyIsIm9yZGVycyJdLCJjbGllbnRfaWQiOiJDb
        scope:orders openid(可選,默認請求全部scope)
    }
Response:
    HTTP/1.1 200 OK
    Content-Type: application/json
    Cache-Control: no-store
    Pragma: no-cache
     
    {
      "access_token":"MTQ0NjJkZmQ5OTM2NDE1ZTZjNGZmZjI3",
      "token_type":"bearer",
      "expires_in":3600
    }

資源全部者密碼模式

用於同一組織下受權瀏覽器

#請求token
Request:
    POST /connect/token HTTP/1.1
    Host: idsrv-server.com
    Content-type: application/x-www-form-urlencoded
    body:
    {
        grant_type:password
        username:dd
        password:dd
        client_id:eshopOnVue
        scope:orders(可選參數)
    }

#請求刷新令牌:原刷新令牌失效、以前頒發的access_token不受影響(須要實現手動失效)
Request:
    POST /connect/token HTTP/1.1
    Host: idsrv-server.com
    Content-type: application/x-www-form-urlencoded
    body:
    {
        grant_type:refresh_token
        refresh_token:e4364377ec69c8d5c06a49d7b74efbd2a29015ac37e9ede8e17597d348931d32
        client_id:eshopOnVue
    }
Respose:
{
    "id_token": "eyJhbGciO.iJSUzI1NiI.sImtpZCw",
    "access_token": "eyJhb.GciOiJSUz.I1NiIsIm",
    "expires_in": 3600,
    "token_type": "Bearer",
    "refresh_token": "60e7dda6e30473ce6dc0a1656b38c174a74ef73310d"
}
#經過access_token請求用戶終結點(須要scope:profile):/connect/userinfo

簡化模式

第三方向受權終結點請求受權,受權成功後,經過Url錨點(#)將access_token、id_token傳給redirecturl安全

受權碼模式

流程分析服務器

1 IdentityServer服務端啓用服務
2 MVC項目配置OIDC保護控制器,並設置clent_id等
3 webApi項目配置Bearer認證保護Apicookie

1.訪問受IdentityServer OIDC保護的MVC控制器
2.自動重定向到IdentityServer的/connect/authorize,並附帶clint信息

IdSrv受權碼模式:
Js客戶端mgr.signinRedirect()
1.向IdSrv服務器請求/.well-known/openid-configuration 獲取IdSrv數據
2.向/connect/authorize發起受權請求,攜帶如下參數
client_id: js
redirect_uri:登陸成功後跳轉的地址
response_type: code
scope:請求的資源權限
state: 2dd196cd7a68402199534d6123791e64
code_challenge: 23kG8msCLc2oHDnTALRTGElqmNAaTADOwUmLMnENFTE
code_challenge_method: S256
3.1.若是驗證client信息正確,且攜帶了idsrv.session和idsrv兩個cookie,並已經受權,則跳轉到redirect_uri,並攜帶如下參數給前端頁面:
code:受權碼
scope:請求的資源權限
state: a656e5bb62024ee48d8267127e46fa68
session_state: YjwA6dW7trE2II5E0ao6h0y2ty4PoiFrV4qZN0XVjvI.46fe4aa153c9d5480e0f61406e35e5ff
3.1.一、在redirect_uri頁面,經過Oidc.UserManager({ response_mode: "query" }).signinRedirectCallback(),經過受權碼向/connect/token請求token,攜帶如下參數
client_id: js
code: 725ca140eb5afdbc8f37cda96eeb53550aa4502de462c77d0618eed2353422d4
redirect_uri: http://localhost:5003/callback.html
code_verifier: a6ff87be469a4171bf1bfd43e5310468bf1d196d337244e2a829b0e94fe476bb9fdad37d300048e692c2fe58c734b0b6
grant_type: authorization_code
3.1.2將code、token寫入cookie保存,不然下次經過idsrv.session和idsrv兩個cookie申請新的受權碼,同時再次跳轉到初始請求頁面
3.2.若是驗證client信息,但未受權,則跳轉到/Account/Login並攜帶一個ReturnUrl參數
該參數爲/connect/authorize/callback並附帶步驟2的全部參數。該參數須要保存並在登陸成功後,跳轉到該頁面
3.3輸入帳號密碼,進入自定義驗證Api中
3.4驗證成功,經過HttpContext.SignInAsync方法爲用戶頒發加密的用戶憑證,將idsrv.session和idsrv兩個cookie寫入請求頭
3.5.在自定義Api中跳轉到ReturnUrl
3.6.1若是未配置受權頁面,IdSrv服務端將/connect/authorize/callback重定向到redirect_uri,並攜帶受權碼等參數,重複3.1.1
3.6.2若是配置了受權頁面,IdSrv服務端將/connect/authorize/callback重定向到受權頁面

登出操做:
Js客戶端mgr.signoutRedirect()
1.向IdSrv請求/connect/endsession 並攜帶如下兩個參數
id_token_hint:
post_logout_redirect_uri: 登出回調地址
2.重定向到/Account/Logout 並攜帶生成的logoutId參數
3.在Logout裏清除await HttpContext.SignOutAsync() 並跳轉到post_logout_redirect_uri
相關文章
相關標籤/搜索