簡體   English   中英

OAuth2授權碼流程:spring-security不接受下發的access_token

[英]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時,然后

  1. 我被正確重定向到授權服務器登錄頁面。
  2. 然后我登錄。
  3. 然后同意批准表格出現在我授予訪問“public_profile”scope的地方
  4. 然后 Spring 再次將我重定向到登錄頁面(第 2 步)。

我認為發生這種情況是因為 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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM