Spring OpenID Connect 请求过程


Spring OpenID Connect 请求过程。

三部分:

启动客户端

客户端启动时,会获取授权服务器配置:

  1. 客户端请求授权服务器,获取 OpenID Connect 配置信息:

    GET /.well-known/openid-configuration HTTP/1.1
    Accept: application/json, application/*+json
    Host: auth-server:9000
  2. 授权服务器响应客户端,返回 OpenID Connect 配置:

    // HTTP/1.1 200
    // Content-Type: application/json
    
    {
      "issuer": "http://auth-server:9000",
      "authorization_endpoint": "http://auth-server:9000/oauth2/authorize",
      "token_endpoint": "http://auth-server:9000/oauth2/token",
      "token_endpoint_auth_methods_supported": [
        "client_secret_basic",
        "client_secret_post"
      ],
      "jwks_uri": "http://auth-server:9000/oauth2/jwks",
      "response_types_supported": [
        "code"
      ],
      "grant_types_supported": [
        "authorization_code",
        "client_credentials",
        "refresh_token"
      ],
      "subject_types_supported": [
        "public"
      ],
      "id_token_signing_alg_values_supported": [
        "RS256"
      ],
      "scopes_supported": [
        "openid"
      ]
    }

启动资源服务器

客户端启动时,会获取授权服务器配置:

  1. 资源服务器请求授权服务器,获取 OpenID Connect 配置信息:

    GET /.well-known/openid-configuration HTTP/1.1
    Accept: application/json, application/*+json
    Host: auth-server:9000
  2. 授权服务器响应资源服务器,返回 OpenID Content 配置:

    // HTTP/1.1 200
    // Content-Type: application/json
    
    {
      "issuer": "http://auth-server:9000",
      "authorization_endpoint": "http://auth-server:9000/oauth2/authorize",
      "token_endpoint": "http://auth-server:9000/oauth2/token",
      "token_endpoint_auth_methods_supported": [
        "client_secret_basic",
        "client_secret_post"
      ],
      "jwks_uri": "http://auth-server:9000/oauth2/jwks",
      "response_types_supported": [
        "code"
      ],
      "grant_types_supported": [
        "authorization_code",
        "client_credentials",
        "refresh_token"
      ],
      "subject_types_supported": [
        "public"
      ],
      "id_token_signing_alg_values_supported": [
        "RS256"
      ],
      "scopes_supported": [
        "openid"
      ]
    }
  3. 资源服务器请求授权服务器,获取 jwk(JSON Web Key):

    GET /oauth2/jwks HTTP/1.1
    Host: auth-server:9000
  4. 授权服务器响应资源服务器,返回 jwk 信息:

    // HTTP/1.1 200
    // Content-Type: application/json;charset=ISO-8859-1
    
    {
      "keys": [
        {
          "kty": "RSA",
          "e": "AQAB",
          "kid": "34714270-1e78-444a-9eca-4bc33523f5e2",
          "n": "0eiWxWDlrl2WuMp6fJiWDZiwaDKio38U1_yWWI-3yPw3nNL41xTLwxb0dNQ5LGkJhuZfdz4QFQlDnH7vGxJp2VH2H1HgmwuTcN4kIExVxP9Br1e93DIruWCnTXD_CP4S-SQ39_JtsvEpJ5VO4we2KmaN9TX0RUpUlGW5kQyDbpltKo-CwUR9rGfzgR0AxEQ1MWyGaWHyJ-KH3pmQbCRzqkU00zFa1W0NHiXSGzbTmoTuLUlS11EUz8RpK-fVTPdEE2QknLkj25PfmeLFTa6Ql6MNBUWCIQ0B8x4thOHJacs3GgkOs3DZandIUEzr71oRXWPnZqe3JYBIyNUfgVdSZw"
        }
      ]
    }
    • kty (key type) Key 类型为 RSA

    • e (exponent) 指数 Base64urlUInt 编码。65537(0x10001) 分成每八位一组 [1,0,1],再进行 base64url 编码 Base64.urlsafe_encode64("\x01\x00\x01")

    • kid Key id

    • n (modulus) 模

授权过程

第一步:浏览器 → 客户端

  1. 浏览器请求客户端

    GET / HTTP/1.1
    Host: 127.0.0.1:8080
  2. 客户端响应浏览器。当前未授权,要求浏览器重定向到客户端授权端点:

    HTTP/1.1 302
    Set-Cookie: JSESSIONID=397EF385FF26BB3E552A048CB1DCB04E; Path=/; HttpOnly
    Location: http://127.0.0.1:8080/oauth2/authorization/messaging-client-oidc

第二步:浏览器 → 客户端

  1. 浏览器访问客户端授权端点:

    GET /oauth2/authorization/messaging-client-oidc HTTP/1.1
    Host: 127.0.0.1:8080
    Cookie: JSESSIONID=397EF385FF26BB3E552A048CB1DCB04E
  2. 客户端响应浏览器,要求浏览器携带参数重定向到授权服务器:

    HTTP/1.1 302
    Location: http://auth-server:9000/oauth2/authorize
      ?response_type=code
      &client_id=messaging-client
      &scope=openid
      &state=IkcKi7_mUAE3cecByi6irNz9_Vnn0tKt9XgkflNOrN4%3D
      &redirect_uri=http://127.0.0.1:8080/login/oauth2/code/messaging-client-oidc
      &nonce=23Bmm-8v6xnn2QI2DL9FEfxBQPpaFlfMo8obYcMrSxk
    • response_typecode 授权码模式

    • client_id 当前 client 的 id

    • scopeopenid,身份授权

    • state 状态码,用于跨站保护,防止暴力搜索客户端有效的授权码

    • redirect_uri 重定向 URI

    • nonce 随机数,防止重放攻击

第三步:浏览器 → 授权服务器

  1. 浏览器携带参数访问授权服务器

    GET /oauth2/authorize
      ?response_type=code
      &client_id=messaging-client
      &scope=openid
      &state=IkcKi7_mUAE3cecByi6irNz9_Vnn0tKt9XgkflNOrN4%3D
      &redirect_uri=http://127.0.0.1:8080/login/oauth2/code/messaging-client-oidc
      &nonce=23Bmm-8v6xnn2QI2DL9FEfxBQPpaFlfMo8obYcMrSxk HTTP/1.1
    Host: auth-server:9000
    User-Agent: Mozilla/5.0
    Cookie: JSESSIONID=39A32337C6E044BA18F7E3E7B670CD2D
  2. 授权通过后,授权服务器响应浏览器,要求浏览器携带授权码和状态码重定向到客户端:

    HTTP/1.1 302
    Location: http://127.0.0.1:8080/login/oauth2/code/messaging-client-oidc
      ?code=ywHSK_g_PqqRqKLQh0UKogrQrrmUJFlLz5zDHeeWFJ5KrBv5QhLiqONhPKGzbSMeWWQt7bCf-yj9uvzibyu0rVwvQR_s4k-VzDIBwD5PwOTu3d8jLehxS1_L2vlRrWgu
      &state=IkcKi7_mUAE3cecByi6irNz9_Vnn0tKt9XgkflNOrN4%3D
    • code 授权码

    • state 状态码,原样返回

第四步:浏览器 → 客户端 → 授权服务器

  1. 浏览器携带授权码和状态码请求客户端

    GET /login/oauth2/code/messaging-client-oidc
      ?code=ywHSK_g_PqqRqKLQh0UKogrQrrmUJFlLz5zDHeeWFJ5KrBv5QhLiqONhPKGzbSMeWWQt7bCf-yj9uvzibyu0rVwvQR_s4k-VzDIBwD5PwOTu3d8jLehxS1_L2vlRrWgu
      &state=IkcKi7_mUAE3cecByi6irNz9_Vnn0tKt9XgkflNOrN4%3D HTTP/1.1
    Host: 127.0.0.1:8080
    Cookie: JSESSIONID=397EF385FF26BB3E552A048CB1DCB04E
  2. 客户端使用授权码请求授权服务器

    POST /oauth2/token HTTP/1.1
    Accept: application/json;charset=UTF-8
    Content-Type: application/x-www-form-urlencoded;charset=UTF-8
    Authorization: Basic bWVzc2FnaW5nLWNsaWVudDpzZWNyZXQ=
    User-Agent: Java/11.0.13
    Host: auth-server:9000
    
    grant_type=authorization_code
    &code=ywHSK_g_PqqRqKLQh0UKogrQrrmUJFlLz5zDHeeWFJ5KrBv5QhLiqONhPKGzbSMeWWQt7bCf-yj9uvzibyu0rVwvQR_s4k-VzDIBwD5PwOTu3d8jLehxS1_L2vlRrWgu
    &redirect_uri=http%3A%2F%2F127.0.0.1%3A8080%2Flogin%2Foauth2%2Fcode%2Fmessaging-client-oidc
    • Authorizationbase64(client-id:client-secret) 用于客户端的授权

    • grant_type authorization_code 授权码模式

    • code 授权码

    • redirect_uri 仅用于验证,要求与注册的客户端重定向 URI 一致

  3. 授权服务器响应客户端,返回访问令牌:

    // HTTP/1.1 200
    // Set-Cookie: JSESSIONID=F9937A6ECF3F2E6EE885C81265A92754; Path=/; HttpOnly
    
    {
      "access_token": "eyJraWQiOiI5OTQyMTFiYi05YzIzLTQyY2MtYThlYy1jMjI0YzE5NGE4ZWUiLCJhbGciOiJSUzI1NiJ9.eyJzdWIiOiJ1c2VyIiwiYXVkIjoibWVzc2FnaW5nLWNsaWVudCIsIm5iZiI6MTYzNjg4MTExNCwic2NvcGUiOlsib3BlbmlkIl0sImlzcyI6Imh0dHA6XC9cL2F1dGgtc2VydmVyOjkwMDAiLCJleHAiOjE2MzY4ODE0MTQsImlhdCI6MTYzNjg4MTExNH0.tSgV4Ng2e07f3DnMd3SOEflyS57JtpssFb0_0kWn1ZxBHSp0hU6dninjQgJ2w0lrHmD10K32THqPR7WcFfjvb1tWFKFaLRUGyuuBTnjnc_dMaoJqfdbtwZriW_-gHOs_vLAKo6QbXM9d9FnQ2ugLtzYiBru2ls1qjN6BWBeHaQv04lr-XaPHFL01Sm92mURg0XaxzQ0sjjWLZUjWtnSYjCojXLdA9Z_wlA97xWhZCpdWR33pv3ACosxDyc3ZL69Rs1Jbrcyi1HcN8G8-RUpLoBJJTOGKZ0HI1AV3YVlpxqG07z6gxXV2Iqp4v-d1KYdkQvgoxDTfRgu-CUmAeGVfgQ",
      "refresh_token": "TRkqpUbOm7cGH23VTxBq1eaOXyz9089pNbhVspuMQIZb8_byYgzr6Amc8HZK_PsFkpgJ9MseyMfO45vWDjq0ciTFIovQZ4MvjQDWHXfmKot7f6MN0xtA7rDkbEd6pjTA",
      "scope": "openid",
      "id_token": "eyJraWQiOiI5OTQyMTFiYi05YzIzLTQyY2MtYThlYy1jMjI0YzE5NGE4ZWUiLCJhbGciOiJSUzI1NiJ9.eyJzdWIiOiJ1c2VyIiwiYXVkIjoibWVzc2FnaW5nLWNsaWVudCIsImF6cCI6Im1lc3NhZ2luZy1jbGllbnQiLCJpc3MiOiJodHRwOlwvXC9hdXRoLXNlcnZlcjo5MDAwIiwiZXhwIjoxNjM2ODgyOTE0LCJpYXQiOjE2MzY4ODExMTQsIm5vbmNlIjoiMjNCbW0tOHY2eG5uMlFJMkRMOUZFZnhCUVBwYUZsZk1vOG9iWWNNclN4ayJ9.AmaVU49JU1ajktaRmcNXZqN7UhhyDVhAd7tIDF-WvzUjgQTSsEqe117hiAXI-ST-7mkdmVQoI5YBkm90FwEUgA_Me4d4TUl8eX5IWLoV9kJLGgYaD7_fCV4pjI9mBcBvy8tTj5ro-PGB82X7Cx-CQeD8dcGvw9WPujdES7fPEV4ZUFguEnUx4TAPJDWgbaQ4vcE8EYxhWj3feGJ_QysQZ0gOIiZGjq6rrOTB27Dm-0UX_bPbkE5y3V2nHDI1t-iqIrvwlFUO927-ULH0nDSJf6RcMFKlb6aJV4GaF5hR0g8AP88cxgspRjp1RjkUSGIQ1sm_vHV-wM1vdicQMkP9gg",
      "token_type": "Bearer",
      "expires_in": 299
    }
    • access_token 访问令牌, JWT 格式

    • refresh_token 刷新令牌

    • scope openid

    • id_token 包含身份授权信息,JWT 格式

    • token_type 令牌类型

    • expires_in 过期时间 299 秒后过期

  4. 授权通过后,客户端响应浏览器,要求浏览器重定向

    HTTP/1.1 302
    Set-Cookie: JSESSIONID=47DFC20A3B3D54C4C6F4B5F1287EF663; Path=/; HttpOnly
    Location: http://127.0.0.1:8080/
  5. 浏览器请求客户端

    GET / HTTP/1.1
    Host: 127.0.0.1:8080
    Cookie: JSESSIONID=47DFC20A3B3D54C4C6F4B5F1287EF663
  6. 客户端响应

    HTTP/1.1 200
    
    Hello, user

请求资源

  1. 客户端请求资源服务器

    GET /messages HTTP/1.1
    Authorization: Bearer eyJraWQiOiIzNDcxNDI3MC0xZTc4LTQ0NGEtOWVjYS00YmMzMzUyM2Y1ZTIiLCJhbGciOiJSUzI1NiJ9.eyJzdWIiOiJ1c2VyIiwiYXVkIjoibWVzc2FnaW5nLWNsaWVudCIsIm5iZiI6MTYzNzE1NTg2MSwic2NvcGUiOlsib3BlbmlkIl0sImlzcyI6Imh0dHA6XC9cL2F1dGgtc2VydmVyOjkwMDAiLCJleHAiOjE2MzcxNTYxNjEsImlhdCI6MTYzNzE1NTg2MX0.PfpiwdStUcuKdB5kAChWAzWaoSV_vmBaQyjUATsi-LPSZRAUu7vOVED5LrtLqHqqyfgM_GIR61RxCxwt3u3zGfEzhmqSIcMQRs-yZUc977zBPBZsT9zM0Wff1cP-tX7yhWRC8lBhcLHyYrDLXhTteg788WBXNBwXOrvUjTm9icSU_2rvm9YkQkxbfaxKrtxZ1sMMcFIMZlIpn2hjA5irYaLqoVnf4d_RlM5_H73kzt3VC12DUyulA4jCkqxqdyfdddmO6F8HrKKbMaDqLOmJfcztBsPG4HRappqKniFmSQevSUMj_cIUxS5HgQJE2Zi_2wHCG4jPpRXa1SR_LBhCRQ
    Host: 127.0.0.1:8090
    • Authorization 格式为 Bearer TOKEN

  2. 资源服务器请求授权服务器,获取 jwk:

    GET /oauth2/jwks HTTP/1.1
    Accept: application/json, application/jwk-set+json
    Host: auth-server:9000
  3. 授权服务器响应资源服务器 jwk 信息:

    // HTTP/1.1 200
    
    {
      "keys": [
        {
          "kty":"RSA",
          "e":"AQAB",
          "kid":"34714270-1e78-444a-9eca-4bc33523f5e2",
          "n":"0eiWxWDlrl2WuMp6fJiWDZiwaDKio38U1_yWWI-3yPw3nNL41xTLwxb0dNQ5LGkJhuZfdz4QFQlDnH7vGxJp2VH2H1HgmwuTcN4kIExVxP9Br1e93DIruWCnTXD_CP4S-SQ39_JtsvEpJ5VO4we2KmaN9TX0RUpUlGW5kQyDbpltKo-CwUR9rGfzgR0AxEQ1MWyGaWHyJ-KH3pmQbCRzqkU00zFa1W0NHiXSGzbTmoTuLUlS11EUz8RpK-fVTPdEE2QknLkj25PfmeLFTa6Ql6MNBUWCIQ0B8x4thOHJacs3GgkOs3DZandIUEzr71oRXWPnZqe3JYBIyNUfgVdSZw"
        }
      ]
    }
  4. 授权通过后,资源服务器响应客户端

    HTTP/1.1 200
    
    ["Message 1","Message 2","Message 3"]