[英]How to verify that oAuth2 access_token is used by same client to whom it was issued in Spring security?
[英]OAuth2 authorization code flow: spring-security does not accept the issued access_token
我正在學習 OAuth2 授權代碼流程。
Authorization Server
(AS),它是 OpenAM 7.1。Client
是一個簡單的 Spring-Boot web 應用程序,帶有 static HTML 頁面,我使用 Spring-Security 來保護 HTML 頁面並控制 Oauth2 流程。 我認為我的授權服務器配置是正確的,因為當我模擬與 CURL 的通信時,AS 在最后生成access_token
。但不知何故 Spring-Security 不想接受已頒發和驗證的訪問令牌。 所以我認為我的 Spring-Security 配置不正確。
我嘗試以多種不同方式配置 Spring-Security,但不幸的是,它們都不起作用。 也許我需要用 Spring-Security 實現我用 CURL 執行的步驟,但也許我只是錯過了配置行。
這是我的 CURL 鏈的最后一步,其中 AS 給我訪問令牌(將授權代碼交換為訪問令牌):
url="$authServerHost/openam/oauth2/realms/root/access_token"
curl \
--silent \
--dump-header - \
--insecur \
--request POST \
--data "grant_type=authorization_code" \
--data "code=$authorizationCode" \
--data "client_id=$clientId" \
--data "client_secret=$clientSecret" \
--data "redirect_uri=$redirectUri" \
"$url"
-------- response ---------
HTTP/1.1 200
X-Frame-Options: SAMEORIGIN
X-Content-Type-Options: nosniff
Cache-Control: no-store
Pragma: no-cache
Content-Type: application/json;charset=UTF-8
Content-Length: 157
Date: Wed, 29 Sep 2021 17:57:30 GMT
{
"access_token":"2SiD3moh2iql5j3ocdPOR-W4QRE",
"refresh_token":"zWSG-fi1J9hUrY0Tw6GHeXnndgM",
"scope":"public_profile",
"token_type":"Bearer",
"expires_in":3599
}
這是令牌的探測(驗證和檢索有關令牌的信息):
url="$authServerHost/openam/oauth2/tokeninfo"
curl \
--silent \
--dump-header - \
--insecur \
--request GET \
--header "Authorization: Bearer $accessToken" \
"$url"
-------- response ---------
HTTP/1.1 200
X-Frame-Options: SAMEORIGIN
X-Content-Type-Options: nosniff
Cache-Control: no-store
Pragma: no-cache
Content-Type: application/json;charset=UTF-8
Content-Length: 326
Date: Wed, 29 Sep 2021 17:57:30 GMT
{
"access_token":"2SiD3moh2iql5j3ocdPOR-W4QRE",
"grant_type":"authorization_code",
"auth_level":0,
"auditTrackingId":"45f24ab1-f9a4-43df-bb17-4b4d6c0ffee4-112239",
"scope":["public_profile"],
"public_profile":"",
"realm":"/",
"token_type":"Bearer",
"expires_in":3599,
"authGrantId":"2tg__erKRo_utv4Py_TOt1NOtDo",
"client_id":"hello-web"
}
然后我嘗試使用此 CURL 獲取受保護的內容,但 Spring-Security 再次將我重定向到 Spring 安全提供商選擇頁面:
url="https://web.example.com:8444/user.html"
curl \
--silent \
--insecur \
--dump-header - \
--request GET \
--header "Authorization: Bearer $accessToken" \
"$url"
-------- response ---------
HTTP/1.1 302
Cache-Control: private
X-Content-Type-Options: nosniff
X-XSS-Protection: 1; mode=block
Strict-Transport-Security: max-age=31536000 ; includeSubDomains
X-Frame-Options: DENY
Location: https://web.example.com:8444/oauth2/authorization/openam
Content-Length: 0
Date: Wed, 29 Sep 2021 18:18:40 GMT
如您所見,我的網絡應用程序 Spring-Security 不接受有效的承載令牌並將請求重定向到授權服務器,盡管我提供了令牌。
這是我的 Spring-Security 配置:
spring:
security:
oauth2:
client:
registration:
openam:
client-id: hello-web
client-secret: client-secret
authorization-grant-type: authorization_code
redirect-uri: https://web.example.com:8444/user.html
scope: public_profile
provider:
openam:
token-uri: https://openam.example.com:8443/openam/oauth2/access_token
authorization-uri: https://openam.example.com:8443/openam/oauth2/authorize
我使用的 Spring-Security 配置:
@EnableWebSecurity
public class OAuth2SecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests(authorizeRequests -> authorizeRequests
.antMatchers("/").permitAll()
.anyRequest().authenticated()
)
.oauth2Login(withDefaults());
}
}
我錯過了什么? 你能指導我正確的方向嗎?
----> 附加信息 <----
當我在web瀏覽器中打開受保護頁面https://web.example.com:8444/user.html
時,然后
我認為發生這種情況是因為 Spring 只是不想接受頒發的訪問令牌。
Spring 日志:
open http://web.example.com:8081/user.html
o.s.security.web.FilterChainProxy : Securing GET /user.html
s.s.w.c.SecurityContextPersistenceFilter : Set SecurityContextHolder to empty SecurityContext
o.s.s.w.a.AnonymousAuthenticationFilter : Set SecurityContextHolder to anonymous SecurityContext
o.s.s.w.a.i.FilterSecurityInterceptor : Failed to authorize filter invocation [GET /user.html] with attributes [authenticated]
o.s.s.w.s.HttpSessionRequestCache : Saved request https://web.example.com:8444/user.html to session
s.w.a.DelegatingAuthenticationEntryPoint : Trying to match using And [Not [RequestHeaderRequestMatcher [expectedHeaderName=X-Requested-With, expectedHeaderValue=XMLHttpRequest]], Not [And [Or [Ant [pattern='/login'], Ant [pattern='/favicon.ico']], And [Not [RequestHeaderRequestMatcher [expectedHeaderName=X-Requested-With, expectedHeaderValue=XMLHttpRequest]], MediaTypeRequestMatcher [contentNegotiationStrategy=org.springframework.web.accept.ContentNegotiationManager@6f2273f8, matchingMediaTypes=[application/xhtml+xml, image/*, text/html, text/plain], useEquals=false, ignoredMediaTypes=[*/*]]]]]]
s.w.a.DelegatingAuthenticationEntryPoint : Match found! Executing org.springframework.security.web.authentication.LoginUrlAuthenticationEntryPoint@23fec83b
o.s.s.web.DefaultRedirectStrategy : Redirecting to https://web.example.com:8444/oauth2/authorization/openam
w.c.HttpSessionSecurityContextRepository : Did not store empty SecurityContext
w.c.HttpSessionSecurityContextRepository : Did not store empty SecurityContext
s.s.w.c.SecurityContextPersistenceFilter : Cleared SecurityContextHolder to complete request
o.s.security.web.FilterChainProxy : Securing GET /oauth2/authorization/openam
s.s.w.c.SecurityContextPersistenceFilter : Set SecurityContextHolder to empty SecurityContext
o.s.s.web.DefaultRedirectStrategy : Redirecting to https://openam.example.com:8443/openam/oauth2/authorize?response_type=code&client_id=example-web&scope=public_profile&state=HYbQUtdrCuQ5dKUtGI6bBoBbLvScCoELGcundKpNGoI%3D&redirect_uri=https://web.example.com:8444/user.html
w.c.HttpSessionSecurityContextRepository : Did not store empty SecurityContext
w.c.HttpSessionSecurityContextRepository : Did not store empty SecurityContext
s.s.w.c.SecurityContextPersistenceFilter : Cleared SecurityContextHolder to complete request
then the Authorization Server's login page appears
then I allow access to the "public_profile" scope
then this happens on the Spring side:
o.s.security.web.FilterChainProxy : Securing GET /user.html?code=1aC6OC44B03k37pACmmD8n-Ol38&iss=https%3A%2F%2Fopenam.example.com%3A8443%2Fopenam%2Foauth2&state=HYbQUtdrCuQ5dKUtGI6bBoBbLvScCoELGcundKpNGoI%3D&client_id=example-web
s.s.w.c.SecurityContextPersistenceFilter : Set SecurityContextHolder to empty SecurityContext
o.s.s.w.a.AnonymousAuthenticationFilter : Set SecurityContextHolder to anonymous SecurityContext
o.s.s.w.a.i.FilterSecurityInterceptor : Failed to authorize filter invocation [GET /user.html?code=1aC6OC44B03k37pACmmD8n-Ol38&iss=https%3A%2F%2Fopenam.example.com%3A8443%2Fopenam%2Foauth2&state=HYbQUtdrCuQ5dKUtGI6bBoBbLvScCoELGcundKpNGoI%3D&client_id=example-web] with attributes [authenticated]
o.s.s.w.s.HttpSessionRequestCache : Saved request https://web.example.com:8444/user.html?code=1aC6OC44B03k37pACmmD8n-Ol38&iss=https%3A%2F%2Fopenam.example.com%3A8443%2Fopenam%2Foauth2&state=HYbQUtdrCuQ5dKUtGI6bBoBbLvScCoELGcundKpNGoI%3D&client_id=example-web to session
s.w.a.DelegatingAuthenticationEntryPoint : Trying to match using And [Not [RequestHeaderRequestMatcher [expectedHeaderName=X-Requested-With, expectedHeaderValue=XMLHttpRequest]], Not [And [Or [Ant [pattern='/login'], Ant [pattern='/favicon.ico']], And [Not [RequestHeaderRequestMatcher [expectedHeaderName=X-Requested-With, expectedHeaderValue=XMLHttpRequest]], MediaTypeRequestMatcher [contentNegotiationStrategy=org.springframework.web.accept.ContentNegotiationManager@6f2273f8, matchingMediaTypes=[application/xhtml+xml, image/*, text/html, text/plain], useEquals=false, ignoredMediaTypes=[*/*]]]]]]
s.w.a.DelegatingAuthenticationEntryPoint : Match found! Executing org.springframework.security.web.authentication.LoginUrlAuthenticationEntryPoint@23fec83b
o.s.s.web.DefaultRedirectStrategy : Redirecting to https://web.example.com:8444/oauth2/authorization/openam
w.c.HttpSessionSecurityContextRepository : Did not store empty SecurityContext
w.c.HttpSessionSecurityContextRepository : Did not store empty SecurityContext
s.s.w.c.SecurityContextPersistenceFilter : Cleared SecurityContextHolder to complete request
o.s.security.web.FilterChainProxy : Securing GET /oauth2/authorization/openam
s.s.w.c.SecurityContextPersistenceFilter : Set SecurityContextHolder to empty SecurityContext
o.s.s.web.DefaultRedirectStrategy : Redirecting to https://openam.example.com:8443/openam/oauth2/authorize?response_type=code&client_id=example-web&scope=public_profile&state=SRHzhN7krlfUhJ50m9lsvaWgLUHglgMOA0wMZHrAmYo%3D&redirect_uri=https://web.example.com:8444/user.html
w.c.HttpSessionSecurityContextRepository : Did not store empty SecurityContext
w.c.HttpSessionSecurityContextRepository : Did not store empty SecurityContext
s.s.w.c.SecurityContextPersistenceFilter : Cleared SecurityContextHolder to complete request
我注意到您共享的代碼中存在兩個問題。
首先是您可能混淆了 OAuth 2.0 資源服務器和 OAuth 2.0 客戶端。
在 web.example.com:8444 上運行的應用程序配置為 OAuth 2.0 客戶端。
但是,您正在向 web.example.com:8444 發出請求,提供不記名令牌並請求資源。
客戶端不會驗證不記名令牌。 在這種情況下,您似乎將應用程序視為資源服務器。
如果您要創建資源服務器應用程序,可以在 Spring 安全參考中查看完整文檔。
第二個問題是您在瀏覽器中訪問客戶端時描述的行為。
這里的問題是自定義redirect-uri: https://web.example.com:8444/user.html
。
執行此操作時,您將覆蓋默認重定向 URI,即/login/oauth2/callback/{registrationId}
。
這個 URI 很特殊,因為它提示OAuth2LoginAuthenticationFilter
處理請求,嘗試對用戶進行身份驗證並創建OAuth2AuthenticationToken
。
當您自定義重定向 URI 時,不會調用OAuth2LoginAuthenticationFilter
並且應用程序不知道用戶是否已通過身份驗證。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.