Ber*_*ani 6 authentication rest oauth-2.0 keycloak
我们正在尝试在我的一些 REST 应用程序的通信中集成(我和我的同事)Oauth2 身份验证。作为身份验证提供者和管理者,我们想使用 Keycloak。我们阅读了一些文档,我们认为我们了解它是如何工作的。现在,我们想请教您,我们设计的流认证是否遵循 Oauth2 协议的原则。我们决定使用的流程身份验证涉及令牌的生成,它们的验证是:
让我们继续描述使用 Oauth2 相互验证的两个应用程序(应用程序 A 和应用程序 B)之间的数据交换示例。上图展示了 A 应用如何查询 Keycloak 以请求令牌;随后,应用程序 A 通过输入它从 Keycloak 收到的令牌向应用程序 B 发送请求;此时,应用程序B收到令牌后,查询Keycloak并要求其验证收到的令牌;最后,应用程序 B 将收到有关令牌有效性的答复,并且根据此答复,它将能够决定是接受从应用程序 A 收到的请求还是拒绝它。
让我们看看交换的技术细节:
1 - 应用程序 A,通过身份验证要求 Keycloak 生成新令牌。
HTTP 请求的示例:
POST /auth/realms/OMS/protocol/openid-connect/token HTTP/1.1
Host: local-keycloak.it:8080
Content-Type: application/x-www-form-urlencoded
cache-control: no-cache
client_id=oms-test&client_secret=039a6b94-44a7-4dae-b8a4-e7b673eee8e5&grant_type=client_credentials&scope=openid
Run Code Online (Sandbox Code Playgroud)
发送到服务器的 HTTP 消息的正文本质上是一个巨大的查询字符串——名称/值对由与号 (&) 分隔,名称与值由等号 (=) 分隔。实际上,正文的内容类型表示为“application/x-www-form-urlencoded”。
2 - Keycloak,如果应用程序 A 认证成功,则生成令牌并将其转发给它。
HTTP 响应示例:
{
"access_token": "eyJhbGciOiJSUzI1NiIsInR5cCIgOiAiSldUIiwia2lkIiA6ICJvU2ZDYjlzSTV6eTNha1BLU2hSMFVYeXJqNjltUFhEcFdjdWM1SG1mUlFvIn0.eyJqdGkiOiJhNmEzZmQ3ZS00NDdhLTQzNTMtOWM2Yi03ZjFhN2QwZDAxYTEiLCJleHAiOjE1NTc5OTUzNTUsIm5iZiI6MCwiaWF0IjoxNTU3OTk1MDU1LCJpc3MiOiJodHRwOi8vbG9jYWxob3N0OjgwODAvYXV0aC9yZWFsbXMvT01TIiwiYXVkIjoiYWNjb3VudCIsInN1YiI6IjYwZThiNjVjLTY1OTYtNDMyYS1hNjY4LTEzOTljMTY3ZDM4NiIsInR5cCI6IkJlYXJlciIsImF6cCI6Im9tcy10ZXN0IiwiYXV0aF90aW1lIjowLCJzZXNzaW9uX3N0YXRlIjoiZWE1ZTFjNDItYjkzNS00ZGEwLTlkNjYtYTAyOWZkZjc3N2IyIiwiYWNyIjoiMSIsImFsbG93ZWQtb3JpZ2lucyI6WyJodHRwOi8vbG9jYWxob3N0OjgwODAiXSwicmVhbG1fYWNjZXNzIjp7InJvbGVzIjpbIm9mZmxpbmVfYWNjZXNzIiwidW1hX2F1dGhvcml6YXRpb24iXX0sInJlc291cmNlX2FjY2VzcyI6eyJhY2NvdW50Ijp7InJvbGVzIjpbIm1hbmFnZS1hY2NvdW50IiwibWFuYWdlLWFjY291bnQtbGlua3MiLCJ2aWV3LXByb2ZpbGUiXX19LCJzY29wZSI6Im9wZW5pZCBlbWFpbCBwcm9maWxlIiwiY2xpZW50SG9zdCI6IjEyNy4wLjAuMSIsImNsaWVudElkIjoib21zLXRlc3QiLCJlbWFpbF92ZXJpZmllZCI6ZmFsc2UsInVzZXJfbmFtZSI6InNlcnZpY2UtYWNjb3VudC1vbXMtdGVzdCIsInByZWZlcnJlZF91c2VybmFtZSI6InNlcnZpY2UtYWNjb3VudC1vbXMtdGVzdCIsImNsaWVudEFkZHJlc3MiOiIxMjcuMC4wLjEiLCJlbWFpbCI6InNlcnZpY2UtYWNjb3VudC1vbXMtdGVzdEBwbGFjZWhvbGRlci5vcmcifQ.RkQ178gLfWoA1-F7w5e4q7FXzhLhigAOPrUN1QrX3oz7PxFuqhm_GopWcX0hHNgX0uFNtSGC1iWn04H5VzcevcDK42w5gV5TWo9WJ5CJp-NRjYdsEST_PhI6KlHsXgik53qF_kCeKwB-_eal1rVdlEY7WO1kv1p8cih-bEA9NNBdA5C6_iA4IF6Jfrdp8lJ_DeRtnbXqsc1dgYdJbYru_BGiYTkolLXxIqfTOTENH64to3EAEVMQ21c_zQtmRxVOaD_fvNOZMqOmWeKk02Z6rfq2m77M6edv1LvlGAnVmx7-zRG6a6eL-t6rZiOwr3eohJ67U77ndzJKrl5J5Wuiwg",
"expires_in": 300,
"refresh_expires_in": 1800,
"refresh_token": "eyJhbGciOiJIUzI1NiIsInR5cCIgOiAiSldUIiwia2lkIiA6ICI2NzhjY2M0NC03ZTY3LTRmODAtOTk5NC1hOTA0NmI3NGY2YTgifQ.eyJqdGkiOiJiYTU3NzZjYi03Zjg1LTRhNTAtOGM5Ni1kYWQ3OTRlZGRjZWIiLCJleHAiOjE1NTc5OTY4NTUsIm5iZiI6MCwiaWF0IjoxNTU3OTk1MDU1LCJpc3MiOiJodHRwOi8vbG9jYWxob3N0OjgwODAvYXV0aC9yZWFsbXMvT01TIiwiYXVkIjoiaHR0cDovL2xvY2FsaG9zdDo4MDgwL2F1dGgvcmVhbG1zL09NUyIsInN1YiI6IjYwZThiNjVjLTY1OTYtNDMyYS1hNjY4LTEzOTljMTY3ZDM4NiIsInR5cCI6IlJlZnJlc2giLCJhenAiOiJvbXMtdGVzdCIsImF1dGhfdGltZSI6MCwic2Vzc2lvbl9zdGF0ZSI6ImVhNWUxYzQyLWI5MzUtNGRhMC05ZDY2LWEwMjlmZGY3NzdiMiIsInJlYWxtX2FjY2VzcyI6eyJyb2xlcyI6WyJvZmZsaW5lX2FjY2VzcyIsInVtYV9hdXRob3JpemF0aW9uIl19LCJyZXNvdXJjZV9hY2Nlc3MiOnsiYWNjb3VudCI6eyJyb2xlcyI6WyJtYW5hZ2UtYWNjb3VudCIsIm1hbmFnZS1hY2NvdW50LWxpbmtzIiwidmlldy1wcm9maWxlIl19fSwic2NvcGUiOiJvcGVuaWQgZW1haWwgcHJvZmlsZSJ9.BkXWMLmuf1c0OBUeg2P2262LLvTmhXg46y4-rrvebNE",
"token_type": "bearer",
"id_token": "eyJhbGciOiJSUzI1NiIsInR5cCIgOiAiSldUIiwia2lkIiA6ICJvU2ZDYjlzSTV6eTNha1BLU2hSMFVYeXJqNjltUFhEcFdjdWM1SG1mUlFvIn0.eyJqdGkiOiIyYjdjZGI2Ny1kYjM3LTQ5MTQtYWNiYi0xNmU5MDA4YzQ4N2IiLCJleHAiOjE1NTc5OTUzNTUsIm5iZiI6MCwiaWF0IjoxNTU3OTk1MDU1LCJpc3MiOiJodHRwOi8vbG9jYWxob3N0OjgwODAvYXV0aC9yZWFsbXMvT01TIiwiYXVkIjoib21zLXRlc3QiLCJzdWIiOiI2MGU4YjY1Yy02NTk2LTQzMmEtYTY2OC0xMzk5YzE2N2QzODYiLCJ0eXAiOiJJRCIsImF6cCI6Im9tcy10ZXN0IiwiYXV0aF90aW1lIjowLCJzZXNzaW9uX3N0YXRlIjoiZWE1ZTFjNDItYjkzNS00ZGEwLTlkNjYtYTAyOWZkZjc3N2IyIiwiYWNyIjoiMSIsImNsaWVudEhvc3QiOiIxMjcuMC4wLjEiLCJjbGllbnRJZCI6Im9tcy10ZXN0IiwiZW1haWxfdmVyaWZpZWQiOmZhbHNlLCJ1c2VyX25hbWUiOiJzZXJ2aWNlLWFjY291bnQtb21zLXRlc3QiLCJwcmVmZXJyZWRfdXNlcm5hbWUiOiJzZXJ2aWNlLWFjY291bnQtb21zLXRlc3QiLCJjbGllbnRBZGRyZXNzIjoiMTI3LjAuMC4xIiwiZW1haWwiOiJzZXJ2aWNlLWFjY291bnQtb21zLXRlc3RAcGxhY2Vob2xkZXIub3JnIn0.C0YkK-B4LnKH3NBCxHjuAkVZKVikh3FaUPIUpToCVFKkgefZRF7JS2yddC4ejxn4_B4y56TBMdVSXg5dEk-ghkz_f1VOR1whRY0HAC6Z5izEJBOHesASWoxJE43QJHXoDYzNWJK1S4JQ6W_BF5KobVHrXL2fmb-ypLBJCc8EAMTYEC-fpxT_T3NkDbsAjmnoCTl1YmRiDkV0sqUKerx5irIZJ3S297Z0Ub4Ahal8ObX7t3JbpJ-SBEvRvNo0PriZdk7C1DZQEhc77v2qnpeyqkwcRkAhZ0uXb5QF32J6dxhKh8-gZHYCauMdzeNmkh-962RnWXqyhGOYipLarnmzjg",
"not-before-policy": 0,
"session_state": "ea5e1c42-b935-4da0-9d66-a029fdf777b2",
"scope": "openid email profile"
}
Run Code Online (Sandbox Code Playgroud)
正如我们所见,我们获得了一个访问令牌,用作我们平台之间的身份验证和授权令牌。访问令牌的到期时间比刷新令牌快,因此可以重新生成访问令牌。
3 - 应用程序 A 使用收到的令牌 (access_token) 向应用程序 B 发送请求。
HTTP 请求的示例:
POST /omsesb/order/placeOrder HTTP/1.1
Host: application-b.it:8081
Content-Type: application/json
Authorization: Bearer eyJhbGciOiJSUzI1NiIsInR5cCIgOiAiSldUIiwia2lkIiA6ICJvU2ZDYjlzSTV6eTNha1BLU2hSMFVYeXJqNjltUFhEcFdjdWM1SG1mUlFvIn0.eyJqdGkiOiJhNmEzZmQ3ZS00NDdhLTQzNTMtOWM2Yi03ZjFhN2QwZDAxYTEiLCJleHAiOjE1NTc5OTUzNTUsIm5iZiI6MCwiaWF0IjoxNTU3OTk1MDU1LCJpc3MiOiJodHRwOi8vbG9jYWxob3N0OjgwODAvYXV0aC9yZWFsbXMvT01TIiwiYXVkIjoiYWNjb3VudCIsInN1YiI6IjYwZThiNjVjLTY1OTYtNDMyYS1hNjY4LTEzOTljMTY3ZDM4NiIsInR5cCI6IkJlYXJlciIsImF6cCI6Im9tcy10ZXN0IiwiYXV0aF90aW1lIjowLCJzZXNzaW9uX3N0YXRlIjoiZWE1ZTFjNDItYjkzNS00ZGEwLTlkNjYtYTAyOWZkZjc3N2IyIiwiYWNyIjoiMSIsImFsbG93ZWQtb3JpZ2lucyI6WyJodHRwOi8vbG9jYWxob3N0OjgwODAiXSwicmVhbG1fYWNjZXNzIjp7InJvbGVzIjpbIm9mZmxpbmVfYWNjZXNzIiwidW1hX2F1dGhvcml6YXRpb24iXX0sInJlc291cmNlX2FjY2VzcyI6eyJhY2NvdW50Ijp7InJvbGVzIjpbIm1hbmFnZS1hY2NvdW50IiwibWFuYWdlLWFjY291bnQtbGlua3MiLCJ2aWV3LXByb2ZpbGUiXX19LCJzY29wZSI6Im9wZW5pZCBlbWFpbCBwcm9maWxlIiwiY2xpZW50SG9zdCI6IjEyNy4wLjAuMSIsImNsaWVudElkIjoib21zLXRlc3QiLCJlbWFpbF92ZXJpZmllZCI6ZmFsc2UsInVzZXJfbmFtZSI6InNlcnZpY2UtYWNjb3VudC1vbXMtdGVzdCIsInByZWZlcnJlZF91c2VybmFtZSI6InNlcnZpY2UtYWNjb3VudC1vbXMtdGVzdCIsImNsaWVudEFkZHJlc3MiOiIxMjcuMC4wLjEiLCJlbWFpbCI6InNlcnZpY2UtYWNjb3VudC1vbXMtdGVzdEBwbGFjZWhvbGRlci5vcmcifQ.RkQ178gLfWoA1-F7w5e4q7FXzhLhigAOPrUN1QrX3oz7PxFuqhm_GopWcX0hHNgX0uFNtSGC1iWn04H5VzcevcDK42w5gV5TWo9WJ5CJp-NRjYdsEST_PhI6KlHsXgik53qF_kCeKwB-_eal1rVdlEY7WO1kv1p8cih-bEA9NNBdA5C6_iA4IF6Jfrdp8lJ_DeRtnbXqsc1dgYdJbYru_BGiYTkolLXxIqfTOTENH64to3EAEVMQ21c_zQtmRxVOaD_fvNOZMqOmWeKk02Z6rfq2m77M6edv1LvlGAnVmx7-zRG6a6eL-t6rZiOwr3eohJ67U77ndzJKrl5J5Wuiwg
Client-Id: oms-test
cache-control: no-cache
{
"orders":
{
"order": {
...
}
}
}
Run Code Online (Sandbox Code Playgroud)
如我们所见,“Authorization”标头包含应用程序 A 从 Keycloak 收到的访问令牌。我们添加了另一个“Client-Id”标头,其中将包含应用程序 A 向 Keycloak 请求生成令牌的用户 ID。
在此示例中,应用程序 A 要求应用程序 B 输入一个新订单,但必须首先对其进行身份验证,因此必须获得授权。
4 - 应用程序 B 向 Keycloak 提出请求,以验证它从应用程序 A 收到的访问令牌。
HTTP 请求的示例:
POST /auth/realms/OMS/protocol/openid-connect/token/introspect HTTP/1.1
Host: local-keycloak.it:8080
Content-Type: application/x-www-form-urlencoded
cache-control: no-cache
client_id=account&client_secret=d67da47e-387a-4930-a89a-eda0296c4896&token=eyJhbGciOiJSUzI1NiIsInR5cCIgOiAiSldUIiwia2lkIiA6ICJvU2ZDYjlzSTV6eTNha1BLU2hSMFVYeXJqNjltUFhEcFdjdWM1SG1mUlFvIn0.eyJqdGkiOiJhNmEzZmQ3ZS00NDdhLTQzNTMtOWM2Yi03ZjFhN2QwZDAxYTEiLCJleHAiOjE1NTc5OTUzNTUsIm5iZiI6MCwiaWF0IjoxNTU3OTk1MDU1LCJpc3MiOiJodHRwOi8vbG9jYWxob3N0OjgwODAvYXV0aC9yZWFsbXMvT01TIiwiYXVkIjoiYWNjb3VudCIsInN1YiI6IjYwZThiNjVjLTY1OTYtNDMyYS1hNjY4LTEzOTljMTY3ZDM4NiIsInR5cCI6IkJlYXJlciIsImF6cCI6Im9tcy10ZXN0IiwiYXV0aF90aW1lIjowLCJzZXNzaW9uX3N0YXRlIjoiZWE1ZTFjNDItYjkzNS00ZGEwLTlkNjYtYTAyOWZkZjc3N2IyIiwiYWNyIjoiMSIsImFsbG93ZWQtb3JpZ2lucyI6WyJodHRwOi8vbG9jYWxob3N0OjgwODAiXSwicmVhbG1fYWNjZXNzIjp7InJvbGVzIjpbIm9mZmxpbmVfYWNjZXNzIiwidW1hX2F1dGhvcml6YXRpb24iXX0sInJlc291cmNlX2FjY2VzcyI6eyJhY2NvdW50Ijp7InJvbGVzIjpbIm1hbmFnZS1hY2NvdW50IiwibWFuYWdlLWFjY291bnQtbGlua3MiLCJ2aWV3LXByb2ZpbGUiXX19LCJzY29wZSI6Im9wZW5pZCBlbWFpbCBwcm9maWxlIiwiY2xpZW50SG9zdCI6IjEyNy4wLjAuMSIsImNsaWVudElkIjoib21zLXRlc3QiLCJlbWFpbF92ZXJpZmllZCI6ZmFsc2UsInVzZXJfbmFtZSI6InNlcnZpY2UtYWNjb3VudC1vbXMtdGVzdCIsInByZWZlcnJlZF91c2VybmFtZSI6InNlcnZpY2UtYWNjb3VudC1vbXMtdGVzdCIsImNsaWVudEFkZHJlc3MiOiIxMjcuMC4wLjEiLCJlbWFpbCI6InNlcnZpY2UtYWNjb3VudC1vbXMtdGVzdEBwbGFjZWhvbGRlci5vcmcifQ.RkQ178gLfWoA1-F7w5e4q7FXzhLhigAOPrUN1QrX3oz7PxFuqhm_GopWcX0hHNgX0uFNtSGC1iWn04H5VzcevcDK42w5gV5TWo9WJ5CJp-NRjYdsEST_PhI6KlHsXgik53qF_kCeKwB-_eal1rVdlEY7WO1kv1p8cih-bEA9NNBdA5C6_iA4IF6Jfrdp8lJ_DeRtnbXqsc1dgYdJbYru_BGiYTkolLXxIqfTOTENH64to3EAEVMQ21c_zQtmRxVOaD_fvNOZMqOmWeKk02Z6rfq2m77M6edv1LvlGAnVmx7-zRG6a6eL-t6rZiOwr3eohJ67U77ndzJKrl5J5Wuiwg
Run Code Online (Sandbox Code Playgroud)
5 - 此时,Keycloak 通过将验证结果作为响应来响应。结果可能是积极的,也可能是消极的。
包含肯定验证结果的 HTTP 响应示例:
{
"jti": "26b6794d-3d83-446a-a106-10dfb14793c3",
"exp": 1557997077,
"nbf": 0,
"iat": 1557996777,
"iss": "http://local-keycloak:8080/auth/realms/OMS",
"aud": "account",
"sub": "60e8b65c-6596-432a-a668-1399c167d386",
"typ": "Bearer",
"azp": "oms-test",
"auth_time": 0,
"session_state": "88a63302-b148-42e4-81d0-5cb81c446903",
"preferred_username": "service-account-oms-test",
"email": "service-account-oms-test@placeholder.org",
"email_verified": false,
"acr": "1",
"allowed-origins": [
"http://local-keycloak:8080"
],
"realm_access": {
"roles": [
"offline_access",
"uma_authorization"
]
},
"resource_access": {
"account": {
"roles": [
"manage-account",
"manage-account-links",
"view-profile"
]
}
},
"scope": "openid email profile",
"clientHost": "application-a.it",
"clientId": "oms-test",
"user_name": "service-account-oms-test",
"clientAddress": "80.10.10.1",
"client_id": "oms-test",
"username": "service-account-oms-test",
"active": true
}
Run Code Online (Sandbox Code Playgroud)
如我们所见,验证成功(active = true):Keycloak 识别出令牌(尚未过期)并向应用程序 B 返回一组信息,通过这些信息它能够决定是否接受应用程序 A 的请求.
通过这些信息,应用程序 B 能够通过客户端的 id、IP、地址和其他信息来识别先前请求令牌的用户。
在这种情况下,为了避免可能的中间人攻击,B 应用程序可以将从应用程序 A 接收到的数据与 Auth Provider 接收到的数据进行匹配:它可以验证客户端 ID 和 IP 是否匹配。
包含否定验证结果的 HTTP 响应示例:
{
"active": false
}
Run Code Online (Sandbox Code Playgroud)
当令牌不存在、令牌已过期或请求令牌验证的应用程序使用的用户没有请求验证的必要权力时,结果是否定的。
6 - 根据从 Keycloak 收到的结果,应用程序 B 与应用程序 A 通信,无论其请求是否已被接受。
那么,在您看来,这种身份验证流程是否正确并因此尊重 Oauth2 的原则?
归档时间: |
|
查看次数: |
5194 次 |
最近记录: |