[英]OAuth2 flow for Gateway + Backend Service
我目前正在使用 Spring-Boot-Web 结合 OAuth2 在 AWS 上使用 Amazon-Cognito 构建一个 Web 应用程序。
在“我的数据中心”中,我运行了 2 个应用程序:
网关应用程序可从 Internet 访问。 它服务于前端(html、css、js),包含一些显示逻辑,也许还有一些每个人都可以访问的 API。 它是“授权代码授予”-OAuth 2.0 流程的发起者(如果用户尚未登录,它会将用户重定向到 Amazon-Cognito)。
后端应用程序只能由网关应用程序访问。 它无法从外部访问。 在后端应用程序中,我想从 Amazon-Cognito 检索用户详细信息(姓名、电子邮件)。
我在 Amazon-Cognito 中为 Gateway-Application 注册了一个客户端。 网关应用程序启动“授权代码授予”流程,并可以从 Amazon-Cognito 访问用户信息。
我将网关应用程序配置为将 OAuth2-Authorization-Details 与我的所有 HTTP 请求一起传递给后端应用程序。 Backend-Application 可以成功检查用户是否通过身份验证。
spring:
security:
oauth2:
client:
registration:
cognito:
client-name: frontend-local
client-id: #######
client-secret: #########
scope: openid,backend/read,backend/write
redirect-uri: http://localhost:8080/login/oauth2/code/cognito
provider:
cognito:
issuer-uri: https://cognito-idp.eu-central-1.amazonaws.com/<my-aws-pool-id>
user-name-attribute: cognito:username
package io.share.frontend.configuration;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
@Configuration
@EnableWebSecurity
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.csrf()
.and()
.authorizeRequests().antMatchers("/", "/webjars/**").permitAll().anyRequest().authenticated()
.and()
.oauth2Login()
.and()
.logout().logoutSuccessUrl("/");
}
}
package io.share.frontend.configuration;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.oauth2.client.OAuth2AuthorizedClientManager;
import org.springframework.security.oauth2.client.OAuth2AuthorizedClientProvider;
import org.springframework.security.oauth2.client.OAuth2AuthorizedClientProviderBuilder;
import org.springframework.security.oauth2.client.registration.ClientRegistrationRepository;
import org.springframework.security.oauth2.client.web.DefaultOAuth2AuthorizedClientManager;
import org.springframework.security.oauth2.client.web.OAuth2AuthorizedClientRepository;
import org.springframework.security.oauth2.client.web.reactive.function.client.ServletOAuth2AuthorizedClientExchangeFilterFunction;
import org.springframework.web.reactive.function.client.WebClient;
@Configuration
public class OAuth2WebClientConfiguration {
@Bean
public OAuth2AuthorizedClientManager authorizedClientManager(ClientRegistrationRepository clientRegistrationRepository, OAuth2AuthorizedClientRepository authorizedClientRepository) {
OAuth2AuthorizedClientProvider authorizedClientProvider =
OAuth2AuthorizedClientProviderBuilder.builder()
.clientCredentials()
.build();
DefaultOAuth2AuthorizedClientManager authorizedClientManager =
new DefaultOAuth2AuthorizedClientManager(
clientRegistrationRepository, authorizedClientRepository);
authorizedClientManager.setAuthorizedClientProvider(authorizedClientProvider);
return authorizedClientManager;
}
@Bean
WebClient webClient(OAuth2AuthorizedClientManager authorizedClientManager) {
ServletOAuth2AuthorizedClientExchangeFilterFunction oauth2Client =
new ServletOAuth2AuthorizedClientExchangeFilterFunction(authorizedClientManager);
oauth2Client.setDefaultClientRegistrationId("cognito");
return WebClient.builder()
.apply(oauth2Client.oauth2Configuration())
.build();
}
}
server:
port: 8081
spring:
security:
oauth2:
resourceserver:
jwt:
issuer-uri: https://cognito-idp.eu-central-1.amazonaws.com/<my-aws-pool-id>
package io.share.backend.configuration;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
@Configuration
@EnableWebSecurity
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests().anyRequest().hasAuthority("SCOPE_backend/read")
.and()
.oauth2ResourceServer().jwt();
}
}
在我的Backend-Application中,我希望能够从 Amazon-Cognito 访问用户信息。 目前,我的后端应用程序中有以下基本 RestController:
package io.share.backend.web;
import org.springframework.security.core.annotation.AuthenticationPrincipal;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import java.security.Principal;
@RestController
public class ObjectResource {
@GetMapping("/username")
public String greeting(@AuthenticationPrincipal Principal user) {
return user.getName();// this currently returns some UUID-Like string, I want to be able to access the username and E-Mail here, just like I can in the Gateway
}
}
但我希望能够在后端访问真实的用户名和电子邮件。
我是否必须在 Amazon-Cognito 中为后端创建一个新客户端? 还是我必须为网关和后端配置相同的客户端 ID 和客户端密码?
我必须在我的应用程序(网关和后端)中进行哪些额外的 Spring-Configurations 才能使其工作?
我正在使用 spring-boot 2.3.6.RELEASE
好问题,您在 API 中遇到了以下常见的 OAuth 问题:
设计模式
您可以使用一种设计模式,或从中借鉴想法,我的博客文章总结了这种行为。 这个想法是首先定义一个声明主体,然后在运行时使用来自多个源的声明填充它。 在您的情况下,一个来源将是 Cognito 用户信息端点。
工作代码
您可以运行我的Sample Spring Boot API ,它也使用 AWS Cognito,密钥 class 是Authorizer 。 在某些设置中,您可能可以获得 API 网关来为您完成其中的一些工作:
优点和缺点
此模式将为您提供可扩展的声明,但也会为您的 API 增加一些复杂性,因为您需要覆盖 API 技术堆栈的默认 OAuth 行为。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.