将 Spring Boot oAuth2 应用程序作为资源服务器运行并提供 Web 内容
Posted
技术标签:
【中文标题】将 Spring Boot oAuth2 应用程序作为资源服务器运行并提供 Web 内容【英文标题】:Run a Spring Boot oAuth2 application as resource server AND serving web content 【发布时间】:2018-10-23 04:07:29 【问题描述】:我正在使用 Spring Boot 1.5.13 以及 Spring Security 4.2.6 和 Spring Security oAuth2 2.0.15。
我想为我们的 Spring Boot 应用程序找到一个最佳实践设置,这些应用程序提供混合的内容集:一个 REST API,以及一些为开发人员提供便利的“登陆页面”的网页,上面有一些链接,还有 Swagger基于 API 的文档,也是网页内容。
我的配置允许我使用适当的授权代码流运行应用程序,因此我可以通过浏览器访问所有 Web 内容并通过配置的 IdP(在我的情况下为 PingFederate)进行身份验证,另外我可以从在浏览器中,即直接或使用 REST 客户端,例如使用 RESTClient。
这是我的安全配置:
@Slf4j
@Configuration
@EnableWebSecurity
@EnableOAuth2Sso // this annotation must stay here!
public class SecurityConfig extends WebSecurityConfigurerAdapter
@Override
protected void configure(HttpSecurity http) throws Exception
http.authorizeRequests()
.antMatchers("/login**", "/webjars/**", "/css/**").permitAll()
.antMatchers("/cfhealth").permitAll()
.antMatchers("/").permitAll()
.antMatchers("/protected", "/api/**").authenticated();
@Bean
public RequestContextListener requestContextListener()
return new RequestContextListener();
以及 oAuth2 配置:
@Configuration
@Slf4j
public class OAuth2Config extends ResourceServerConfigurerAdapter
@Value("$pingfederate.pk-uri")
String pingFederatePublicKeyUri;
@Autowired
PingFederateKeyUtils pingFederateKeyUtils;
@Override
public void configure(ResourceServerSecurityConfigurer config)
config.tokenServices(tokenServices());
@Bean
public TokenStore tokenStore()
return new JwtTokenStore(accessTokenConverter());
@Bean
public JwtAccessTokenConverter accessTokenConverter()
JwtAccessTokenConverter converter = new JwtAccessTokenConverter();
String certificate = pingFederateKeyUtils.getKeyFromServer(pingFederatePublicKeyUri);
String publicKey = pingFederateKeyUtils.extractPublicKey(certificate);
converter.setVerifier(pingFederateKeyUtils.createSignatureVerifier(publicKey));
return converter;
@Bean
@Primary
public DefaultTokenServices tokenServices()
DefaultTokenServices defaultTokenServices = new DefaultTokenServices();
defaultTokenServices.setTokenStore(tokenStore());
return defaultTokenServices;
但是当我想以编程方式/在浏览器外部调用 REST API 时,标题中带有不记名令牌,例如使用 curl,授权代码流启动并重定向到本地登录端点。我想要的是 API 调用接受承载令牌进行身份验证,而不创建会话,并且浏览器中的所有 Web 内容/mvc 调用都建立会话。
curl -i -H "Accept: application/json" -H "Authorization: Bearer $TOKEN" -X GET http://localhost:8080/authdemo/api/hello
在上面的SecurityConfig类中添加@EnableResourceServer注解(并在应用程序属性文件中添加security.oauth2.resource.filter-order=3,我可以使curl命令工作,但随后授权代码流被破坏,对于我的应用程序中的所有 URL,我在浏览器中得到以下输出:
<oauth>
<error_description>
Full authentication is required to access this resource
</error_description>
<error>unauthorized</error>
</oauth>
现在有没有办法让这个场景很好地工作?如果是,那会是什么样子?还是只有更高版本的Spring Boot+Security+oAuth2才支持?
Spring Boot with Security OAuth2 - how to use resource server with web login form?的问题很相似
【问题讨论】:
【参考方案1】:我找到了解决方案:它需要多个 HttpSecurity 配置。我通过阅读 Matt Raible 在https://developer.okta.com/blog/2018/02/13/secure-spring-microservices-with-oauth 撰写的精彩文章发现了这一点,他向我介绍了 requestMatchers(.) 的概念。这就是我最终实现它的方式:
@Configuration
@EnableResourceServer
@EnableWebSecurity(debug = true)
@EnableOAuth2Sso
public class ResourceServerConfig extends ResourceServerConfigurerAdapter
@Bean
public RequestContextListener requestContextListener()
return new RequestContextListener();
@Override
public void configure(HttpSecurity http) throws Exception
http
.requestMatcher(new RequestHeaderRequestMatcher("Authorization"))
.authorizeRequests().anyRequest().fullyAuthenticated();
这样我就可以使用浏览器访问服务,从而产生授权代码流。但是访问 API(或者实际上是服务的任何部分)会导致对所提供的 Bearer 令牌的验证。
为了说明在这种情况下如何排除/公开某些端点,下面是我如何配置执行器端点和我自己添加的一个非常简单的“ping”端点:
@Configuration
@Order(1)
public class ActuatorSecurity extends WebSecurityConfigurerAdapter
@Override
protected void configure(HttpSecurity http) throws Exception
http.requestMatcher(new OrRequestMatcher(EndpointRequest.to("health", "info"),
new AntPathRequestMatcher("/cfhealth"))).authorizeRequests().anyRequest().permitAll();
还有我对 /cfhealth 端点的实现:
@Controller
@Slf4j
public class MainController
@GetMapping(value = "/cfhealth")
@ResponseBody
public String cfhealth()
return "ok";
如果这是 Spring Security 配置的最佳实践方式或者是否有更好的方法,我很高兴向其他人学习。在过去的几周里,我在这个主题上花费了相当长的时间,掌握基本的 Spring Security 概念需要相当多的努力。
【讨论】:
我也在努力让同一个应用程序作为资源服务器和 SSO 客户端工作。为什么你的ResourceServerConfig
类用EnableOAuth2Sso
注释? Oauth2 客户端部分没有单独的配置吗?以上是关于将 Spring Boot oAuth2 应用程序作为资源服务器运行并提供 Web 内容的主要内容,如果未能解决你的问题,请参考以下文章
Spring Boot OAuth2 将内部用户与 Facebook/Google 登录链接
带有 Spring Boot 的 OAuth2 SSO 没有授权屏幕
将 Spring Boot oAuth2 应用程序作为资源服务器运行并提供 Web 内容