如何为 Okta 自动刷新不记名令牌
Posted
技术标签:
【中文标题】如何为 Okta 自动刷新不记名令牌【英文标题】:How to refresh Bearer token Automatically for Okta 【发布时间】:2021-04-24 00:43:43 【问题描述】:我有一个带有 Angular UI、Zuul 和一些与 Okta 登录 (OAuth) 集成的服务的应用程序(非响应式)。这工作正常,但在 jwt 令牌过期后卡住了。关于工作流程的一些细节
-
应用 URL 指向 Zuul。
Zuul 将请求重定向到 Okta。用户登录。
Okta 发回一个不记名令牌(也是一个刷新令牌)。
此不记名令牌被传递到 UI 并存储为 cookie。对于每个请求,UI 都会发送 Authorization 标头以及不记名令牌。
此过程正常运行,直到 jwt 令牌在一小时内过期,然后 Zuul 尝试将其重定向到默认登录页面,因为我们使用 okta 登录,所以该页面没有任何内容。
我的问题
-
如果需要https://dev1234.okta.com/oauth2/default,可以将登录页面重定向到哪里?
如何根据刷新令牌获取新的不记名令牌?
我能否根据刷新令牌在 Zuul 中自动获取新的不记名令牌。如果这不可能,最好的方法是什么?
这是 Zuul 的 application.yml 文件
spring:
application:
name: service-gateway
cloud:
loadbalancer:
ribbon:
enabled: false
server:
port: 8080
okta:
oauth2:
issuer: https://dev1234.okta.com/oauth2/default
client-id: <value>
client-secret: <value>
feign:
hystrix:
enabled: true
hystrix:
shareSecurityContext: true
eureka:
client:
enabled: true
fetch-registry: true
zuul:
routes:
abc-service:
path: /api/**
strip-prefix: true
service-id: ABC-SERVICE
ui:
path: /**
url: http://localhost:4200
host:
connect-timeout-millis: 10000
socket-timeout-millis: 20000
sensitive-headers:
- Cookie,Set-Cookie
gradle 文件
plugins
id 'org.springframework.boot' version '2.3.7.RELEASE'
id 'io.spring.dependency-management' version '1.0.10.RELEASE'
id 'java'
group = 'com.example'
version = '0.0.1-SNAPSHOT'
sourceCompatibility = '1.8'
configurations
developmentOnly
runtimeClasspath
extendsFrom developmentOnly
repositories
mavenCentral()
ext
set('springCloudServicesVersion', "2.3.0.RELEASE")
set('springCloudVersion', "Hoxton.SR9")
dependencies
implementation 'org.springframework.boot:spring-boot-starter-actuator'
implementation 'com.okta.spring:okta-spring-boot-starter:1.4.0'
implementation 'io.pivotal.spring.cloud:spring-cloud-services-starter-service-registry'
implementation 'org.springframework.cloud:spring-cloud-starter-netflix-eureka-client'
implementation 'org.springframework.cloud:spring-cloud-starter-netflix-hystrix'
implementation 'org.springframework.cloud:spring-cloud-starter-netflix-zuul'
implementation 'org.springframework.cloud:spring-cloud-starter-openfeign'
implementation 'io.pivotal.spring.cloud:spring-cloud-services-starter-config-client'
implementation 'org.springframework.security.oauth.boot:spring-security-oauth2-autoconfigure'
developmentOnly 'org.springframework.boot:spring-boot-devtools'
testImplementation('org.springframework.boot:spring-boot-starter-test')
exclude group: 'org.junit.vintage', module: 'junit-vintage-engine'
dependencyManagement
imports
mavenBom "io.pivotal.spring.cloud:spring-cloud-services-dependencies:$springCloudServicesVersion"
mavenBom "org.springframework.cloud:spring-cloud-dependencies:$springCloudVersion"
test
useJUnitPlatform()
Zulu WebSecurityConfigurerAdapter
package abc
@EnableDiscoveryClient
@EnableZuulProxy
@SpringBootApplication
public class ServiceGateway
private static List<String> clients = Arrays.asList("okta");
@Autowired
private ClientRegistrationRepository clientRegistrationRepository;
@Value("$okta.oauth2.client-id")
String clientId;
@Value("$okta.oauth2.client-secret")
String clientSecret;
public static void main(String[] args)
SpringApplication.run(ServiceGateway.class, args);
@Configuration
static class OktaOAuth2WebSecurityConfigurerAdapter extends WebSecurityConfigurerAdapter
@Override
protected void configure(HttpSecurity http) throws Exception
// @formatter:off
http
.authorizeRequests().anyRequest().authenticated()
.and()
.oauth2Login()
.and()
.oauth2ResourceServer().jwt();
// @formatter:on
@Bean
public FilterRegistrationBean<CorsFilter> simpleCorsFilter()
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
CorsConfiguration config = new CorsConfiguration();
config.setAllowCredentials(true);
config.setAllowedOrigins(Collections.singletonList("*"));
config.setAllowedMethods(Collections.singletonList("*"));
config.setAllowedHeaders(Collections.singletonList("*"));
source.registerCorsConfiguration("/**", config);
FilterRegistrationBean<CorsFilter> bean = new FilterRegistrationBean<>(new CorsFilter(source));
bean.setOrder(Ordered.HIGHEST_PRECEDENCE);
return bean;
@Bean
public OktaAuthenticationFilter oktaAuthFilter(OAuth2AuthorizedClientService clientService)
return new OktaAuthenticationFilter(clientService);
服务应用程序.yml
spring:
application:
name: analytics-service
server:
port: 8081
eureka:
client:
enabled: true
okta:
oauth2:
issuer: https://dev1234.okta.com/oauth2/default
client-id: <value>
client-secret: <value>
服务的配置文件
@Configuration
static class OktaOAuth2WebSecurityConfigurerAdapter extends WebSecurityConfigurerAdapter
@Override
protected void configure(HttpSecurity http) throws Exception
// @formatter:off
http
.authorizeRequests().anyRequest().authenticated()
.and()
.oauth2ResourceServer().jwt();
// @formatter:on
@Bean
protected RestTemplate restTemplate()
return new OAuth2RestTemplate(oAuthDetails());
Gradle 文件
buildscript
dependencies
classpath('gradle.plugin.com.palantir.gradle.docker:gradle-docker:0.13.0')
plugins
id 'org.springframework.boot' version '2.3.7.RELEASE'
id 'io.spring.dependency-management' version '1.0.10.RELEASE'
id 'java'
apply plugin: 'io.spring.dependency-management'
apply plugin: 'com.palantir.docker'
group = 'com.demo'
version = '0.0.1-SNAPSHOT'
sourceCompatibility = '1.8'
configurations
developmentOnly
runtimeClasspath
extendsFrom developmentOnly
compileOnly
extendsFrom annotationProcessor
repositories
mavenCentral()
maven url 'https://repo.spring.io/milestone'
ext
set('springCloudVersion', "Hoxton.SR9")
set('springCloudServicesVersion', "2.3.0.RELEASE")
dependencies
implementation 'io.pivotal.spring.cloud:spring-cloud-services-starter-config-client'
implementation 'io.pivotal.spring.cloud:spring-cloud-services-starter-service-registry'
implementation 'org.springframework.boot:spring-boot-starter-actuator'
implementation 'org.springframework.boot:spring-boot-starter-web'
implementation 'org.springframework.boot:spring-boot-starter-security'
implementation 'org.springframework.cloud:spring-cloud-starter-netflix-eureka-client'
implementation 'org.springframework.security.oauth.boot:spring-security-oauth2-autoconfigure'
implementation 'org.springframework.cloud:spring-cloud-starter-openfeign'
implementation 'com.okta.spring:okta-spring-boot-starter:1.4.0'
compileOnly 'org.projectlombok:lombok'
implementation 'com.googlecode.json-simple:json-simple:1.1.1'
annotationProcessor 'org.projectlombok:lombok'
developmentOnly 'org.springframework.boot:spring-boot-devtools'
testImplementation 'org.springframework.boot:spring-boot-starter-test'
testImplementation 'org.springframework.restdocs:spring-restdocs-mockmvc'
testImplementation 'org.mockito:mockito-core:2.7.22'
dependencyManagement
imports
mavenBom "io.pivotal.spring.cloud:spring-cloud-services-dependencies:$springCloudServicesVersion"
mavenBom "org.springframework.cloud:spring-cloud-dependencies:$springCloudVersion"
task unpack(type: Copy)
dependsOn bootJar
from(zipTree(tasks.bootJar.outputs.files.singleFile))
into("build/dependency")
docker
name "$project.group/$bootJar.baseName"
copySpec.from(tasks.unpack.outputs).into("dependency")
buildArgs(['DEPENDENCY': "dependency"])
task standardTests(type: Test)
useJUnitPlatform
更新 看起来范围“offline_access”确实有所作为。现在我收到 CORS 错误。过滤器到位后,我应该看不到这个吗?这是由于授权标头的存在吗? 此外,如果我手动刷新浏览器,则会提供一个新令牌。那么没有CORS问题
zone.js:3243 POST http://localhost:8080/api/system/summary/salesHierarchy 401
core.js:15724 ERROR
HttpErrorResponse headers: HttpHeaders, status: 401, statusText: "OK", url: "http://localhost:8080/api/system/summary/salesHierarchy", ok: false, …
:8080/verification:1 Access to XMLHttpRequest at 'https://dev-770454.okta.com/oauth2/default/v1/authorize?response_type=code&…0/login/oauth2/code/okta&nonce=4aoYCPl3OKhsOTTpCUiqayYjQXdpZLuonn6_Q6193-o' (redirected from 'http://localhost:8080/verification') from origin 'http://localhost:8080' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource.
zone.js:3243 GET https://dev-770454.okta.com/oauth2/default/v1/authorize?response_type=code&…0/login/oauth2/code/okta&nonce=4aoYCPl3OKhsOTTpCUiqayYjQXdpZLuonn6_Q6193-o net::ERR_FAILED
core.js:15724 ERROR
HttpErrorResponse headers: HttpHeaders, status: 0, statusText: "Unknown Error", url: "http://localhost:8080/verification", ok: false, …
更新1 当 JWT 令牌过期时,我看到下面的错误,这是预期的。
2021-01-31 10:38:53 [http-nio-8080-exec-9] DEBUG o.s.s.o.s.r.w.BearerTokenAuthenticationFilter - Authentication request for failed!
org.springframework.security.oauth2.server.resource.InvalidBearerTokenException: An error occurred while attempting to decode the Jwt: Jwt expired at 2021-01-31T16:35:39Z
401 被发送到 UI,UI 捕获它并重定向到 APP 中的另一个 url。这些是网关日志
2021-01-31 10:38:53 [http-nio-8080-exec-10] DEBUG o.s.s.w.s.HttpSessionRequestCache - DefaultSavedRequest added to Session: DefaultSavedRequest[http://localhost:8080/verification]
2021-01-31 10:38:53 [http-nio-8080-exec-10] DEBUG o.s.s.w.a.ExceptionTranslationFilter - Calling Authentication entry point.
org.springframework.security.web.authentication.WebAuthenticationDetails@2cd90: RemoteIpAddress: 0:0:0:0:0:0:0:1; SessionId: A55D113FD46A0031CA1FADD21C008382; Granted Authorities: ROLE_ANONYMOUS
2021-01-31 10:38:53 [http-nio-8080-exec-8] DEBUG o.s.s.access.vote.AffirmativeBased - Voter: org.springframework.security.web.access.expression.WebExpressionVoter@4180b4a8, returned: -1
2021-01-31 10:38:53 [http-nio-8080-exec-1] DEBUG o.s.security.web.FilterChainProxy - /oauth2/authorization/okta at position 1 of 17 in additional filter chain; firing Filter: 'WebAsyncManagerIntegrationFilter'
2021-01-31 10:38:53 [http-nio-8080-exec-1] DEBUG o.s.security.web.FilterChainProxy - /oauth2/authorization/okta at position 2 of 17 in additional filter chain; firing Filter: 'SecurityContextPersistenceFilter'
2021-01-31 10:38:53 [http-nio-8080-exec-1] DEBUG o.s.s.w.c.HttpSessionSecurityContextRepository - HttpSession returned null object for SPRING_SECURITY_CONTEXT
2021-01-31 10:38:53 [http-nio-8080-exec-1] DEBUG o.s.s.w.c.HttpSessionSecurityContextRepository - No SecurityContext was available from the HttpSession: org.apache.catalina.session.StandardSessionFacade@422bdd20. A new one will be created.
2021-01-31 10:38:53 [http-nio-8080-exec-1] DEBUG o.s.security.web.FilterChainProxy - /oauth2/authorization/okta at position 3 of 17 in additional filter chain; firing Filter: 'HeaderWriterFilter'
2021-01-31 10:38:53 [http-nio-8080-exec-1] DEBUG o.s.security.web.FilterChainProxy - /oauth2/authorization/okta at position 4 of 17 in additional filter chain; firing Filter: 'CorsFilter'
2021-01-31 10:38:53 [http-nio-8080-exec-8] DEBUG o.s.s.w.a.ExceptionTranslationFilter - Access is denied (user is anonymous); redirecting to authentication entry point
org.springframework.security.access.AccessDeniedException: Access is denied
at org.springframework.security.access.vote.AffirmativeBased.decide(AffirmativeBased.java:84)
at
......
o.s.s.w.a.ExceptionTranslationFilter - Calling Authentication entry point.
2021-01-31 10:38:53 [http-nio-8080-exec-8] DEBUG o.s.s.w.a.DelegatingAuthenticationEntryPoint - Trying to match using AndRequestMatcher [requestMatchers=[NegatedRequestMatcher [requestMatcher=RequestHeaderRequestMatcher [expectedHeaderName=X-Requested-With, expectedHeaderValue=XMLHttpRequest]], MediaTypeRequestMatcher [contentNegotiationStrategy=org.springframework.web.accept.ContentNegotiationManager@6f86a06a, matchingMediaTypes=[application/xhtml+xml, image/*, text/html, text/plain], useEquals=false, ignoredMediaTypes=[*/*]]]]
2021-01-31 10:38:53 [http-nio-8080-exec-1] DEBUG o.s.s.w.u.matcher.AndRequestMatcher - Trying to match using org.springframework.security.web.csrf.CsrfFilter$DefaultRequiresCsrfMatcher@3f60847a
2021-01-31 10:38:53 [http-nio-8080-exec-8] DEBUG o.s.s.w.u.matcher.AndRequestMatcher - Trying to match using NegatedRequestMatcher [requestMatcher=RequestHeaderRequestMatcher [expectedHeaderName=X-Requested-With, expectedHeaderValue=XMLHttpRequest]]
2021-01-31 10:38:53 [http-nio-8080-exec-1] DEBUG o.s.s.w.u.matcher.AndRequestMatcher - Did not match
2021-01-31 10:38:53 [http-nio-8080-exec-8] DEBUG o.s.s.w.u.m.NegatedRequestMatcher - matches = true
2021-01-31 10:38:53 [http-nio-8080-exec-1] DEBUG o.s.security.web.FilterChainProxy - /oauth2/authorization/okta at position 6 of 17 in additional filter chain; firing Filter: 'LogoutFilter'
2021-01-31 10:38:53 [http-nio-8080-exec-8] DEBUG o.s.s.w.u.matcher.AndRequestMatcher - Trying to match using MediaTypeRequestMatcher [contentNegotiationStrategy=org.springframework.web.accept.ContentNegotiationManager@6f86a06a, matchingMediaTypes=[application/xhtml+xml, image/*, text/html, text/plain], useEquals=false, ignoredMediaTypes=[*/*]]
2021-01-31 10:38:53 [http-nio-8080-exec-1] DEBUG o.s.s.w.u.m.AntPathRequestMatcher - Request 'GET /oauth2/authorization/okta' doesn't match 'POST /logout'
2021-01-31 10:38:53 [http-nio-8080-exec-1] DEBUG o.s.security.web.FilterChainProxy - /oauth2/authorization/okta at position 7 of 17 in additional filter chain; firing Filter: 'OAuth2AuthorizationRequestRedirectFilter'
2021-01-31 10:38:53 [http-nio-8080-exec-1] DEBUG o.s.s.w.u.m.AntPathRequestMatcher - Checking match of request : '/oauth2/authorization/okta'; against '/oauth2/authorization/registrationId'
2021-01-31 10:38:53 [http-nio-8080-exec-1] DEBUG o.s.s.w.u.m.AntPathRequestMatcher - Checking match of request : '/oauth2/authorization/okta'; against '/oauth2/authorization/registrationId'
2021-01-31 10:38:53 [http-nio-8080-exec-8] DEBUG o.s.s.w.u.m.MediaTypeRequestMatcher - httpRequestMediaTypes=[image/avif, image/webp, image/apng, image/svg+xml, image/*, */*;q=0.8]
2021-01-31 10:38:53 [http-nio-8080-exec-8] DEBUG o.s.s.w.u.m.MediaTypeRequestMatcher - Processing image/avif
2021-01-31 10:38:53 [http-nio-8080-exec-8] DEBUG o.s.s.w.u.m.MediaTypeRequestMatcher - application/xhtml+xml .isCompatibleWith image/avif = false
2021-01-31 10:38:53 [http-nio-8080-exec-8] DEBUG o.s.s.w.u.m.MediaTypeRequestMatcher - image/* .isCompatibleWith image/avif = true
2021-01-31 10:38:53 [http-nio-8080-exec-8] DEBUG o.s.s.w.u.matcher.AndRequestMatcher - All requestMatchers returned true
2021-01-31 10:38:53 [http-nio-8080-exec-8] DEBUG o.s.s.w.a.DelegatingAuthenticationEntryPoint - Match found! Executing org.springframework.security.web.authentication.DelegatingAuthenticationEntryPoint@1c10eb3a
2021-01-31 10:38:53 [http-nio-8080-exec-8] DEBUG o.s.s.w.a.DelegatingAuthenticationEntryPoint - Trying to match using AndRequestMatcher [requestMatchers=[NegatedRequestMatcher [requestMatcher=RequestHeaderRequestMatcher [expectedHeaderName=X-Requested-With, expectedHeaderValue=XMLHttpRequest]], NegatedRequestMatcher [requestMatcher=AndRequestMatcher [requestMatchers=[OrRequestMatcher [requestMatchers=[Ant [pattern='/login'], Ant [pattern='/favicon.ico']]], AndRequestMatcher [requestMatchers=[NegatedRequestMatcher [requestMatcher=RequestHeaderRequestMatcher [expectedHeaderName=X-Requested-With, expectedHeaderValue=XMLHttpRequest]], MediaTypeRequestMatcher [contentNegotiationStrategy=org.springframework.web.accept.ContentNegotiationManager@6f86a06a, matchingMediaTypes=[application/xhtml+xml, image/*, text/html, text/plain], useEquals=false, ignoredMediaTypes=[*/*]]]]]]]]]
2021-01-31 10:38:53 [http-nio-8080-exec-8] DEBUG o.s.s.w.u.matcher.AndRequestMatcher - Trying to match using NegatedRequestMatcher [requestMatcher=RequestHeaderRequestMatcher [expectedHeaderName=X-Requested-With, expectedHeaderValue=XMLHttpRequest]]
2021-01-31 10:38:53 [http-nio-8080-exec-8] DEBUG o.s.s.w.u.m.NegatedRequestMatcher - matches = true
2021-01-31 10:38:53 [http-nio-8080-exec-8] DEBUG o.s.s.w.u.matcher.AndRequestMatcher - Trying to match using NegatedRequestMatcher [requestMatcher=AndRequestMatcher [requestMatchers=[OrRequestMatcher [requestMatchers=[Ant [pattern='/login'], Ant [pattern='/favicon.ico']]], AndRequestMatcher [requestMatchers=[NegatedRequestMatcher [requestMatcher=RequestHeaderRequestMatcher [expectedHeaderName=X-Requested-With, expectedHeaderValue=XMLHttpRequest]], MediaTypeRequestMatcher [contentNegotiationStrategy=org.springframework.web.accept.ContentNegotiationManager@6f86a06a, matchingMediaTypes=[application/xhtml+xml, image/*, text/html, text/plain], useEquals=false, ignoredMediaTypes=[*/*]]]]]]]
2021-01-31 10:38:53 [http-nio-8080-exec-8] DEBUG o.s.s.w.u.matcher.AndRequestMatcher - Trying to match using OrRequestMatcher [requestMatchers=[Ant [pattern='/login'], Ant [pattern='/favicon.ico']]]
2021-01-31 10:38:53 [http-nio-8080-exec-8] DEBUG o.s.s.w.u.matcher.OrRequestMatcher - Trying to match using Ant [pattern='/login']
2021-01-31 10:38:53 [http-nio-8080-exec-8] DEBUG o.s.s.w.u.m.AntPathRequestMatcher - Checking match of request : '/favicon.ico'; against '/login'
2021-01-31 10:38:53 [http-nio-8080-exec-8] DEBUG o.s.s.w.u.matcher.OrRequestMatcher - Trying to match using Ant [pattern='/favicon.ico']
2021-01-31 10:38:53 [http-nio-8080-exec-8] DEBUG o.s.s.w.u.m.AntPathRequestMatcher - Checking match of request : '/favicon.ico'; against '/favicon.ico'
2021-01-31 10:38:53 [http-nio-8080-exec-8] DEBUG o.s.s.w.u.matcher.OrRequestMatcher - matched
2021-01-31 10:38:53 [http-nio-8080-exec-8] DEBUG o.s.s.w.u.matcher.AndRequestMatcher - Trying to match using AndRequestMatcher [requestMatchers=[NegatedRequestMatcher [requestMatcher=RequestHeaderRequestMatcher [expectedHeaderName=X-Requested-With, expectedHeaderValue=XMLHttpRequest]], MediaTypeRequestMatcher [contentNegotiationStrategy=org.springframework.web.accept.ContentNegotiationManager@6f86a06a, matchingMediaTypes=[application/xhtml+xml, image/*, text/html, text/plain], useEquals=false, ignoredMediaTypes=[*/*]]]]
2021-01-31 10:38:53 [http-nio-8080-exec-8] DEBUG o.s.s.w.u.matcher.AndRequestMatcher - Trying to match using NegatedRequestMatcher [requestMatcher=RequestHeaderRequestMatcher [expectedHeaderName=X-Requested-With, expectedHeaderValue=XMLHttpRequest]]
2021-01-31 10:38:53 [http-nio-8080-exec-8] DEBUG o.s.s.w.u.m.NegatedRequestMatcher - matches = true
2021-01-31 10:38:53 [http-nio-8080-exec-8] DEBUG o.s.s.w.u.matcher.AndRequestMatcher - Trying to match using MediaTypeRequestMatcher [contentNegotiationStrategy=org.springframework.web.accept.ContentNegotiationManager@6f86a06a, matchingMediaTypes=[application/xhtml+xml, image/*, text/html, text/plain], useEquals=false, ignoredMediaTypes=[*/*]]
2021-01-31 10:38:53 [http-nio-8080-exec-8] DEBUG o.s.s.w.u.m.MediaTypeRequestMatcher - httpRequestMediaTypes=[image/avif, image/webp, image/apng, image/svg+xml, image/*, */*;q=0.8]
2021-01-31 10:38:53 [http-nio-8080-exec-1] DEBUG o.s.s.web.DefaultRedirectStrategy - Redirecting to 'https://dev-770454.okta.com/oauth2/default/v1/authorize?response_type=code&client_id=0oa2amci5xaQcrWbF357&scope=openid%20profile%20email%20address%20phone%20offline_access&state=yXMfdZoYPFl3yoISRnJLftlFnXmf3AnBgnUdGk0MBAc%3D&redirect_uri=http://localhost:8080/login/oauth2/code/okta&nonce=sKf92sk_wHRT6Zq1XwEw-NdYwik-CRMgXLZa_3jfKpA'
2021-01-31 10:38:53 [http-nio-8080-exec-8] DEBUG o.s.s.w.u.m.MediaTypeRequestMatcher - Processing image/avif
2021-01-31 10:38:53 [http-nio-8080-exec-8] DEBUG o.s.s.w.u.m.MediaTypeRequestMatcher - application/xhtml+xml .isCompatibleWith image/avif = false
2021-01-31 10:38:53 [http-nio-8080-exec-1] DEBUG o.s.s.w.h.writers.HstsHeaderWriter - Not injecting HSTS header since it did not match the requestMatcher org.springframework.security.web.header.writers.HstsHeaderWriter$SecureRequestMatcher@61505c39
2021-01-31 10:38:53 [http-nio-8080-exec-8] DEBUG o.s.s.w.u.m.MediaTypeRequestMatcher - image/* .isCompatibleWith image/avif = true
2021-01-31 10:38:53 [http-nio-8080-exec-8] DEBUG o.s.s.w.u.matcher.AndRequestMatcher - All requestMatchers returned true
2021-01-31 10:38:53 [http-nio-8080-exec-8] DEBUG o.s.s.w.u.matcher.AndRequestMatcher - All requestMatchers returned true
2021-01-31 10:38:53 [http-nio-8080-exec-8] DEBUG o.s.s.w.u.m.NegatedRequestMatcher - matches = false
2021-01-31 10:38:53 [http-nio-8080-exec-1] DEBUG o.s.s.w.c.HttpSessionSecurityContextRepository - SecurityContext is empty or contents are anonymous - context will not be stored in HttpSession.
2021-01-31 10:38:53 [http-nio-8080-exec-8] DEBUG o.s.s.w.u.matcher.AndRequestMatcher - Did not match
2021-01-31 10:38:53 [http-nio-8080-exec-8] DEBUG o.s.s.w.a.DelegatingAuthenticationEntryPoint - No match found. Using default entry point org.springframework.security.web.authentication.LoginUrlAuthenticationEntryPoint@693f1240
2021-01-31 10:38:53 [http-nio-8080-exec-1] DEBUG o.s.s.w.c.SecurityContextPersistenceFilter - SecurityContextHolder now cleared, as request processing completed
2021-01-31 10:38:53 [http-nio-8080-exec-8] DEBUG o.s.s.web.DefaultRedirectStrategy - Redirecting to 'http://localhost:8080/login'
2021-01-31 10:38:53 [http-nio-8080-exec-8] DEBUG o.s.s.w.h.writers.HstsHeaderWriter - Not injecting HSTS header since it did not match the requestMatcher org.springframework.security.web.header.writers.HstsHeaderWriter$SecureRequestMatcher@61505c39
2021-01-31 10:38:53 [http-nio-8080-exec-8] DEBUG o.s.s.w.c.HttpSessionSecurityContextRepository - SecurityContext is empty or contents are anonymous - context will not be stored in HttpSession.
2021-01-31 10:38:53 [http-nio-8080-exec-8] DEBUG o.s.s.w.c.SecurityContextPersistenceFilter - SecurityContextHolder now cleared, as request processing completed
2021-01-31 10:38:53 [http-nio-8080-exec-6] DEBUG o.s.security.web.FilterChainProxy - /login at position 1 of 17 in additional filter chain; firing Filter: 'WebAsyncManagerIntegrationFilter'
2021-01-31 10:38:53 [http-nio-8080-exec-6] DEBUG o.s.security.web.FilterChainProxy - /login at position 2 of 17 in additional filter chain; firing Filter: 'SecurityContextPersistenceFilter'
2021-01-31 10:38:53 [http-nio-8080-exec-6] DEBUG o.s.s.w.c.HttpSessionSecurityContextRepository - HttpSession returned null object for SPRING_SECURITY_CONTEXT
2021-01-31 10:38:53 [http-nio-8080-exec-6] DEBUG o.s.s.w.c.HttpSessionSecurityContextRepository - No SecurityContext was available from the HttpSession: org.apache.catalina.session.StandardSessionFacade@422bdd20. A new one will be created.
2021-01-31 10:38:53 [http-nio-8080-exec-6] DEBUG o.s.security.web.FilterChainProxy - /login at position 3 of 17 in additional filter chain; firing Filter: 'HeaderWriterFilter'
2021-01-31 10:38:53 [http-nio-8080-exec-6] DEBUG o.s.security.web.FilterChainProxy - /login at position 4 of 17 in additional filter chain; firing Filter: 'CorsFilter'
2021-01-31 10:38:53 [http-nio-8080-exec-6] TRACE o.s.c.n.zuul.web.ZuulHandlerMapping - Mapped to HandlerExecutionChain with [org.springframework.cloud.netflix.zuul.web.ZuulController@3ce8f88f] and 1 interceptors
2021-01-31 10:38:53 [http-nio-8080-exec-6] DEBUG o.s.security.web.FilterChainProxy - /login at position 5 of 17 in additional filter chain; firing Filter: 'CsrfFilter'
2021-01-31 10:38:53 [http-nio-8080-exec-6] DEBUG o.s.s.w.u.matcher.AndRequestMatcher - Trying to match using org.springframework.security.web.csrf.CsrfFilter$DefaultRequiresCsrfMatcher@3f60847a
2021-01-31 10:38:53 [http-nio-8080-exec-6] DEBUG o.s.s.w.u.matcher.AndRequestMatcher - Did not match
2021-01-31 10:38:53 [http-nio-8080-exec-6] DEBUG o.s.security.web.FilterChainProxy - /login at position 6 of 17 in additional filter chain; firing Filter: 'LogoutFilter'
2021-01-31 10:38:53 [http-nio-8080-exec-6] DEBUG o.s.s.w.u.m.AntPathRequestMatcher - Request 'GET /login' doesn't match 'POST /logout'
2021-01-31 10:38:53 [http-nio-8080-exec-6] DEBUG o.s.security.web.FilterChainProxy - /login at position 7 of 17 in additional filter chain; firing Filter: 'OAuth2AuthorizationRequestRedirectFilter'
2021-01-31 10:38:53 [http-nio-8080-exec-6] DEBUG o.s.s.w.u.m.AntPathRequestMatcher - Checking match of request : '/login'; against '/oauth2/authorization/registrationId'
2021-01-31 10:38:53 [http-nio-8080-exec-6] DEBUG o.s.security.web.FilterChainProxy - /login at position 8 of 17 in additional filter chain; firing Filter: 'OAuth2LoginAuthenticationFilter'
2021-01-31 10:38:53 [http-nio-8080-exec-6] DEBUG o.s.s.w.u.m.AntPathRequestMatcher - Checking match of request : '/login'; against '/login/oauth2/code/*'
2021-01-31 10:38:53 [http-nio-8080-exec-6] DEBUG o.s.security.web.FilterChainProxy - /login at position 9 of 17 in additional filter chain; firing Filter: 'DefaultLoginPageGeneratingFilter'
2021-01-31 10:38:53 [http-nio-8080-exec-6] DEBUG o.s.s.w.h.writers.HstsHeaderWriter - Not injecting HSTS header since it did not match the requestMatcher org.springframework.security.web.header.writers.HstsHeaderWriter$SecureRequestMatcher@61505c39
在浏览器控制台上我看到了错误
Access to XMLHttpRequest at 'https://dev-770454.okta.com/oauth2/default/v1/authorize?response_type=code&client_id=0oa2amci5xaQcrWbF357&scope=openid%20profile%20email%20address%20phone%20offline_access&state=yXMfdZoYPFl3yoISRnJLftlFnXmf3AnBgnUdGk0MBAc%3D&redirect_uri=http://localhost:8080/login/oauth2/code/okta&nonce=sKf92sk_wHRT6Zq1XwEw-NdYwik-CRMgXLZa_3jfKpA' (redirected from 'http://localhost:8080/verification') from origin 'http://localhost:8080' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource.
此 CORS 错误是否应该由网关上定义的过滤器处理,或者是否未应用 CORS 过滤器?让我感到困惑的是,如果我转到浏览器并单击刷新按钮,它就可以正常工作。
【问题讨论】:
【参考方案1】:来自Spring Security's documentation:
OAuth2RefreshToken 可以选择在授权码和密码授权类型的访问令牌响应中返回。如果
OAuth2AuthorizedClient.getRefreshToken()
可用且OAuth2AuthorizedClient.getAccessToken()
已过期,则RefreshTokenOAuth2AuthorizedClientProvider
会自动刷新。
检查 Okta 应用程序中的刷新令牌框不足以获取刷新令牌。您还需要传入offline_access
范围,否则不会返回。
我建议您升级到 Okta Spring Boot starter 2.0.0 并使用以下范围属性:
okta.oauth2.scopes=openid, email, profile, offline_access
【讨论】:
我在 OAuth2AuthorizedClient 的令牌中都有。 offline_access 的范围是缺少的。让我试试看。 现在我遇到了 CORS 问题,CORS 过滤器不应该处理它吗? Okta 或 API 出现 CORS 错误?您能否添加错误/更新您的原始问题? CORS 错误似乎来自网关。我在 Okta 中看不到错误日志。已更新 update1 中的日志 如果 CORS 错误来自 Okta,您需要在 API > Trusted Origins 的 Okta 开发人员仪表板中添加http://localhost:8080
。如果它来自您的网关,则需要为 Spring Security 配置 CORS。 ***.com/a/60962180/65681【参考方案2】:
如果你有刷新令牌,你可以send it to the /token endpoint to get a new access token。您只想决定是抢先获取新令牌(基于它何时到期)还是重新获取(如果现有令牌停止工作,则请求新的访问令牌)。
【讨论】:
我确实编写了一个 zuul 过滤器来执行此操作,并且能够获取新令牌。在将令牌发送到 UI 并将其存储在 cookie 中之后。当使用新令牌发出新请求时,错误。 2021-01-28 11:45:43 [http-nio-8080-exec-1] DEBUG o.s.s.w.a.ExceptionTranslationFilter - 访问被拒绝(用户是匿名的);重定向到身份验证入口点 org.springframework.security.access.AccessDeniedException:访问被拒绝以上是关于如何为 Okta 自动刷新不记名令牌的主要内容,如果未能解决你的问题,请参考以下文章
在 asp.net vnext 上使用不记名令牌身份验证刷新令牌