Spring Security OAuth 2 - 授权服务器从 0.1.0 更新到 0.1.1 / 0.1.2 使示例项目不起作用
Posted
技术标签:
【中文标题】Spring Security OAuth 2 - 授权服务器从 0.1.0 更新到 0.1.1 / 0.1.2 使示例项目不起作用【英文标题】:Spring Security OAuth 2 - Authorization Server update from 0.1.0 to 0.1.1 / 0.1.2 makes example projects not work 【发布时间】:2021-10-12 00:39:01 【问题描述】:我想使用新的Spring Security Authorization Server
为我的网络服务实现OAuth2
。
在https://www.baeldung.com/spring-security-oauth-auth-server举个例子,分离
授权服务器 资源服务器 客户代码可以在https://github.com/Baeldung/spring-security-oauth/tree/master/oauth-authorization-server找到
这三个 Maven 项目在给定版本中运行,当 Web 浏览器中的 Client 访问 http://localhost:8080/articles 时输出正确
["Article 1","Article 2","Article 3"]
我尝试将Authorization Server
项目更新为0.1.1
,但是虽然它编译并启动,但当客户端访问http://localhost:8080/articles时我得到
Whitelabel Error Page
This application has no explicit mapping for /error, so you are seeing this as a fallback.
Sat Aug 07 15:57:26 CEST 2021
There was an unexpected error (type=None, status=999).
我认为这是因为我还必须将所有三个项目中的其他版本更新为 Spring Boot 2.5.3
和 OpenJDK 16
,但同样的错误。
我更新到0.1.2
并将日志级别更改为DEBUG
,这出现在授权服务器项目启动时:
...
2021-08-09 17:54:45.876 DEBUG 16256 --- [ main] o.s.b.f.s.DefaultListableBeanFactory : Creating shared instance of singleton bean 'org.springframework.boot.autoconfigure.web.servlet.ServletWebServerFactoryConfiguration$EmbeddedTomcat'
2021-08-09 17:54:46.015 DEBUG 16256 --- [ main] o.a.catalina.core.AprLifecycleListener : The Apache Tomcat Native library could not be found using names [tcnative-1, libtcnative-1] on the java.library.path [/usr/java/packages/lib:/usr/lib64:/lib64:/lib:/usr/lib]. The errors reported were [Can't load library: /home/myself/PROJECTs/SPRING/spring-authorization-server/bin/libtcnative-1.so, Can't load library: /home/myself/PROJECTs/SPRING/spring-authorization-server/bin/liblibtcnative-1.so, no tcnative-1 in java.library.path: /usr/java/packages/lib:/usr/lib64:/lib64:/lib:/usr/lib, no libtcnative-1 in java.library.path: /usr/java/packages/lib:/usr/lib64:/lib64:/lib:/usr/lib]
org.apache.tomcat.jni.LibraryNotFoundError: Can't load library: /home/myself/PROJECTs/SPRING/spring-authorization-server/bin/libtcnative-1.so, Can't load library: /home/myself/PROJECTs/SPRING/spring-authorization-server/bin/liblibtcnative-1.so, no tcnative-1 in java.library.path: /usr/java/packages/lib:/usr/lib64:/lib64:/lib:/usr/lib, no libtcnative-1 in java.library.path: /usr/java/packages/lib:/usr/lib64:/lib64:/lib:/usr/lib
at org.apache.tomcat.jni.Library.<init>(Library.java:101) ~[tomcat-embed-core-9.0.50.jar:9.0.50]
at org.apache.tomcat.jni.Library.initialize(Library.java:211) ~[tomcat-embed-core-9.0.50.jar:9.0.50]
at org.apache.catalina.core.AprLifecycleListener.init(AprLifecycleListener.java:192) ~[tomcat-embed-core-9.0.50.jar:9.0.50]
at org.apache.catalina.core.AprLifecycleListener.isAprAvailable(AprLifecycleListener.java:101) ~[tomcat-embed-core-9.0.50.jar:9.0.50]
at org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory.getDefaultLifecycleListeners(TomcatServletWebServerFactory.java:173) ~[spring-boot-2.5.3.jar:2.5.3]
at org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory.<init>(TomcatServletWebServerFactory.java:120) ~[spring-boot-2.5.3.jar:2.5.3]
at org.springframework.boot.autoconfigure.web.servlet.ServletWebServerFactoryConfiguration$EmbeddedTomcat.tomcatServletWebServerFactory(ServletWebServerFactoryConfiguration.java:76) ~[spring-boot-autoconfigure-2.5.3.jar:2.5.3]
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:na]
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:78) ~[na:na]
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:na]
at java.base/java.lang.reflect.Method.invoke(Method.java:567) ~[na:na]
at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:154) ~[spring-beans-5.3.9.jar:5.3.9]
at org.springframework.beans.factory.support.ConstructorResolver.instantiate(ConstructorResolver.java:653) ~[spring-beans-5.3.9.jar:5.3.9]
at org.springframework.beans.factory.support.ConstructorResolver.instantiateUsingFactoryMethod(ConstructorResolver.java:638) ~[spring-beans-5.3.9.jar:5.3.9]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateUsingFactoryMethod(AbstractAutowireCapableBeanFactory.java:1334) ~[spring-beans-5.3.9.jar:5.3.9]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1177) ~[spring-beans-5.3.9.jar:5.3.9]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:564) ~[spring-beans-5.3.9.jar:5.3.9]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:524) ~[spring-beans-5.3.9.jar:5.3.9]
at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:335) ~[spring-beans-5.3.9.jar:5.3.9]
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234) ~[spring-beans-5.3.9.jar:5.3.9]
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:333) ~[spring-beans-5.3.9.jar:5.3.9]
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:213) ~[spring-beans-5.3.9.jar:5.3.9]
at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.getWebServerFactory(ServletWebServerApplicationContext.java:217) ~[spring-boot-2.5.3.jar:2.5.3]
at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.createWebServer(ServletWebServerApplicationContext.java:180) ~[spring-boot-2.5.3.jar:2.5.3]
at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.onRefresh(ServletWebServerApplicationContext.java:160) ~[spring-boot-2.5.3.jar:2.5.3]
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:577) ~[spring-context-5.3.9.jar:5.3.9]
at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.refresh(ServletWebServerApplicationContext.java:145) ~[spring-boot-2.5.3.jar:2.5.3]
at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:754) ~[spring-boot-2.5.3.jar:2.5.3]
at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:434) ~[spring-boot-2.5.3.jar:2.5.3]
at org.springframework.boot.SpringApplication.run(SpringApplication.java:338) ~[spring-boot-2.5.3.jar:2.5.3]
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1343) ~[spring-boot-2.5.3.jar:2.5.3]
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1332) ~[spring-boot-2.5.3.jar:2.5.3]
at com.baeldung.OAuth2AuthorizationServerApplication.main(OAuth2AuthorizationServerApplication.java:10) ~[classes/:na]
...
0.1.1
似乎也发生了同样的情况
我的 pom.xml
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.baeldung</groupId>
<artifactId>spring-authorization-server</artifactId>
<version>0.1.0-SNAPSHOT</version>
<packaging>jar</packaging>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.5.3</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.security.experimental</groupId>
<artifactId>spring-security-oauth2-authorization-server</artifactId>
<version>0.1.2</version>
</dependency>
</dependencies>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<java.version>16</java.version>
</properties>
</project>
仅更改 pom.xml 中的 Authorization Server 版本,0.1.0 或 0.1.1 或 0.1.2 都会提供相同的异常。
Baeldung 的示例项目仅使用 0.1.0 运行(从 localhost:8080/articles 传递文章),但使用 0.1.1 和 0.1.2 我得到了描述的 Whitelable 错误页面。
【问题讨论】:
0.1.2 可用,但同样的错误。 【参考方案1】:首先,我建议您查看samples in the spring-authorization-server project 本身(例如,请参阅this line),这将确保您跟上项目中发生的快速变化,因为网络上的那些教程将往往很快就会过时。
其次,我认为调试中的第二个错误与此问题无关,因此这似乎是本地设置问题,但我不是 100% 确定。
第三,第一个错误发生在较新版本的 SAS 上,原因是#243。更改包括合并来自 OAuth 2.1, Section 9.7.1 的建议,其中指出:
虽然使用 localhost 重定向 URI(即, "http://localhost:port/path") 功能类似于回送 IP 10.3.3 节中描述的重定向,“localhost”的使用不是 推荐的。使用环回 IP 文字指定重定向 URI 而不是“localhost”避免无意中在网络上监听 环回接口以外的接口。也少了 容易受到客户端防火墙和错误配置的主机名的影响 用户设备上的分辨率。
仅当重定向 URI 的主机为 localhost
时,才会在重定向回客户端应用程序时显示此错误。如果您在授权服务器中启用跟踪日志记录(例如logging.level.org.springframework.security=trace
),您将看到成功的身份验证,然后重定向到错误页面,如下所示:
...
2021-08-10 11:10:41.596 DEBUG 90071 --- [io-9000-exec-10] w.a.UsernamePasswordAuthenticationFilter : Set SecurityContextHolder to UsernamePasswordAuthenticationToken [Principal=org.springframework.security.core.userdetails.User [Username=user, Password=[PROTECTED], Enabled=true, AccountNonExpired=true, credentialsNonExpired=true, AccountNonLocked=true, Granted Authorities=[ROLE_PILOT]], Credentials=[PROTECTED], Authenticated=true, Details=WebAuthenticationDetails [RemoteIpAddress=127.0.0.1, SessionId=3786957448CCBB82DAE6AB29DBCA5D2C], Granted Authorities=[ROLE_USER]]
2021-08-10 11:10:41.596 DEBUG 90071 --- [io-9000-exec-10] o.s.s.web.DefaultRedirectStrategy : Redirecting to http://auth-server:9000/error?response_type=code&client_id=messaging-client&scope=openid&state=Vg-fUjLSdOjAG_4Y9LcjcxxYTGhd33Trbaclp92XoDQ%3D&redirect_uri=http://localhost:8080/login/oauth2/code/messaging-client&nonce=s8hJD_zDopreLImNeRwQ3fslL4yFNySjbt6MiYK1mPw
...
这告诉我在流程的早期发生了一些事情,而我们此时只是遇到了症状。如果您在登录之前在日志中往上看,您会看到如下内容:
...
2021-08-10 11:10:37.444 TRACE 90071 --- [nio-9000-exec-8] o.s.security.web.FilterChainProxy : Invoking OAuth2AuthorizationEndpointFilter (6/24)
2021-08-10 11:10:37.444 TRACE 90071 --- [nio-9000-exec-8] o.s.s.authentication.ProviderManager : Authenticating request with OAuth2AuthorizationCodeRequestAuthenticationProvider (1/10)
2021-08-10 11:10:37.445 TRACE 90071 --- [nio-9000-exec-8] o.s.s.w.header.writers.HstsHeaderWriter : Not injecting HSTS header since it did not match request to [Is Secure]
2021-08-10 11:10:37.445 DEBUG 90071 --- [nio-9000-exec-8] w.c.HttpSessionSecurityContextRepository : Did not store empty SecurityContext
2021-08-10 11:10:37.445 DEBUG 90071 --- [nio-9000-exec-8] w.c.HttpSessionSecurityContextRepository : Did not store empty SecurityContext
2021-08-10 11:10:37.445 DEBUG 90071 --- [nio-9000-exec-8] s.s.w.c.SecurityContextPersistenceFilter : Cleared SecurityContextHolder to complete request
2021-08-10 11:10:37.447 TRACE 90071 --- [nio-9000-exec-8] o.s.security.web.FilterChainProxy : Trying to match request against DefaultSecurityFilterChain [RequestMatcher=org.springframework.security.config.annotation.web.configurers.oauth2.server.authorization.OAuth2AuthorizationServerConfigurer$$Lambda$603/0x000000080041a040@4dd90166, Filters=[org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter@52227eb2, org.springframework.security.web.context.SecurityContextPersistenceFilter@21263314, org.springframework.security.web.header.HeaderWriterFilter@4d84049a, org.springframework.security.web.csrf.CsrfFilter@1d8b0500, org.springframework.security.web.authentication.logout.LogoutFilter@6413d7e7, org.springframework.security.oauth2.server.authorization.web.OAuth2AuthorizationEndpointFilter@32d5279, org.springframework.security.oauth2.server.authorization.oidc.web.OidcProviderConfigurationEndpointFilter@fe87ddd, org.springframework.security.oauth2.server.authorization.web.OAuth2AuthorizationServerMetadataEndpointFilter@448b808a, org.springframework.security.oauth2.server.authorization.web.NimbusJwkSetEndpointFilter@ebda593, org.springframework.security.oauth2.server.authorization.web.OAuth2ClientAuthenticationFilter@22d322f5, org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter@4337afd, org.springframework.security.web.authentication.ui.DefaultLoginPageGeneratingFilter@d16be4f, org.springframework.security.web.authentication.ui.DefaultLogoutPageGeneratingFilter@5ad1904f, org.springframework.security.oauth2.server.resource.web.BearerTokenAuthenticationFilter@60e06f7d, org.springframework.security.web.savedrequest.RequestCacheAwareFilter@4a92c6a9, org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter@64c781a9, org.springframework.security.web.authentication.AnonymousAuthenticationFilter@a146b11, org.springframework.security.web.session.SessionManagementFilter@642857e0, org.springframework.security.web.access.ExceptionTranslationFilter@30c3ae63, org.springframework.security.web.access.intercept.FilterSecurityInterceptor@550e9be6, org.springframework.security.oauth2.server.authorization.web.OAuth2TokenEndpointFilter@32ec9c90, org.springframework.security.oauth2.server.authorization.web.OAuth2TokenIntrospectionEndpointFilter@456bcb74, org.springframework.security.oauth2.server.authorization.web.OAuth2TokenRevocationEndpointFilter@3b332962, org.springframework.security.oauth2.server.authorization.oidc.web.OidcClientRegistrationEndpointFilter@58a2d9f9]] (1/2)
2021-08-10 11:10:37.447 TRACE 90071 --- [nio-9000-exec-8] o.s.security.web.FilterChainProxy : Trying to match request against DefaultSecurityFilterChain [RequestMatcher=any request, Filters=[org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter@1b01a0d, org.springframework.security.web.context.SecurityContextPersistenceFilter@91f565d, org.springframework.security.web.header.HeaderWriterFilter@67b355c8, org.springframework.security.web.csrf.CsrfFilter@79f90a3a, org.springframework.security.web.authentication.logout.LogoutFilter@414f87a9, org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter@6e31d989, org.springframework.security.web.authentication.ui.DefaultLoginPageGeneratingFilter@1ddc6db2, org.springframework.security.web.authentication.ui.DefaultLogoutPageGeneratingFilter@2ed71727, org.springframework.security.web.savedrequest.RequestCacheAwareFilter@46e3559f, org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter@3b83459e, org.springframework.security.web.authentication.AnonymousAuthenticationFilter@5261ec9, org.springframework.security.web.session.SessionManagementFilter@388623ad, org.springframework.security.web.access.ExceptionTranslationFilter@22bdb1d0, org.springframework.security.web.access.intercept.FilterSecurityInterceptor@416d56f2]] (2/2)
2021-08-10 11:10:37.447 DEBUG 90071 --- [nio-9000-exec-8] o.s.security.web.FilterChainProxy : Securing GET /error?response_type=code&client_id=messaging-client&scope=openid&state=Vg-fUjLSdOjAG_4Y9LcjcxxYTGhd33Trbaclp92XoDQ%3D&redirect_uri=http://localhost:8080/login/oauth2/code/messaging-client&nonce=s8hJD_zDopreLImNeRwQ3fslL4yFNySjbt6MiYK1mPw
...
所以错误实际上发生在OAuth2AuthorizationEndpointFilter
,并且错误重定向在身份验证后被保存为目标URL,然后我们被重定向到/login
,并且在身份验证后重定向回/error
,这会产生一个whitelabel错误页面。
短期解决办法是确保您的客户端应用程序使用127.0.0.1
,而不是localhost
,包括更改授权服务器中的重定向URI(参见示例)。但是,如果您忘记并在http://localhost:8080
启动浏览器,您仍然会收到此错误。您现在可以使用客户端应用程序中的过滤器来解决这个问题,如下所示:
/**
* This filter ensures that the loopback IP <code>127.0.0.1</code> is used to access the
* application so that the sample works correctly, due to the fact that redirect URIs with
* "localhost" are rejected by the Spring Authorization Server, because the OAuth 2.1
* draft specification states:
*
* <pre>
* While redirect URIs using localhost (i.e.,
* "http://localhost:port/path") function similarly to loopback IP
* redirects described in Section 10.3.3, the use of "localhost" is NOT
* RECOMMENDED.
* </pre>
*
* @see <a href=
* "https://datatracker.ietf.org/doc/html/draft-ietf-oauth-v2-1-01#section-9.7.1">Loopback Redirect
* Considerations in Native Apps</a>
*/
@Component
@Order(Ordered.HIGHEST_PRECEDENCE)
public class LoopbackIpRedirectFilter extends OncePerRequestFilter
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
throws ServletException, IOException
if (request.getServerName().equals("localhost"))
UriComponents uri = UriComponentsBuilder.fromHttpRequest(new ServletServerHttpRequest(request))
.host("127.0.0.1").build();
response.sendRedirect(uri.toUriString());
return;
filterChain.doFilter(request, response);
我鼓励您open an issue 请求改进处理此错误的方式。如果您有兴趣,我们很乐意与您讨论并让您参与该项目以帮助解决此问题。
【讨论】:
史蒂夫,感谢您的努力。我不明白你所说的一切,但我在 3 个 Baeldung 项目中到处都用“127.0.0.1”替换了“localhost”,它的表现甚至更糟。我没有得到登录页面了。 希望 Baeldung 团队检查并更新他们的样本。同时我尝试了官方样品。 如果您觉得它对您有帮助,请接受此答案 @Toerktumlare 你没看我的评论吗?它没有帮助。而且我不会继续尝试 Baeldung 项目,直到他们自己检查出了什么问题。 我不能相信在我的情况下没有解决问题的答案。如何接受我无法批准的答案?我按照他的建议尝试了官方样品。【参考方案2】:我也遇到了同样的问题。经过四到五天的努力,我找到了解决方案。在所有示例中 issuer-uri 是 http://auth-server:9000
我刚刚在 etc/hosts 文件中添加了以下条目
127.0.0.1 身份验证服务器
解决了问题
【讨论】:
我想使用IP地址,而不是'auth-server'之类的东西,也就是说我不想修改主机文件。我现在无法跟进此事,因为我必须决定使用 Keycloak 的中间解决方案,但以后可能会重新使用 Spring Security Auth Server。以上是关于Spring Security OAuth 2 - 授权服务器从 0.1.0 更新到 0.1.1 / 0.1.2 使示例项目不起作用的主要内容,如果未能解决你的问题,请参考以下文章
spring-security-oauth2中的HttpSecurity配置问题
spring-security-oauth2 - 从资源服务器检查ClientDetails
社交登录,spring-security-oauth2 和 spring-security-jwt?
如何处理 spring-security-oauth2 的版本升级?