我目前正在使用springbootweb和oauth2在aws上使用amazoncognito构建一个web应用程序。
我的目标设置如下所示:
在“我的数据中心”中,我运行了两个应用程序:
网关应用程序
后端应用程序
网关应用程序可以从internet访问。它服务于前端(html、css、js),包含一些显示逻辑,也许还有一些api,每个人都可以访问。它是“授权码授予”OAuth2.0流的发起程序(如果用户还没有登录,它会将用户重定向到AmazonCognito)。
后端应用程序只能由网关应用程序访问。不能从外面接近。在后端应用程序中,我想从amazoncognito检索用户详细信息(姓名、电子邮件)。
我现在要做的是:
我在amazoncognito中为网关应用程序注册了一个客户机。网关应用程序启动“授权码授予”流,并可以从amazoncognito访问用户信息。
我将网关应用程序配置为将oauth2授权详细信息与所有http请求一起传递给后端应用程序。后端应用程序可以成功地检查用户是否经过身份验证。
网关应用程序配置
应用程序.yml
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
安全配置.java
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("/");
}
}
OAuth2WebClient配置.java
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();
}
}
后端应用程序配置
应用程序.yml
server:
port: 8081
spring:
security:
oauth2:
resourceserver:
jwt:
issuer-uri: https://cognito-idp.eu-central-1.amazonaws.com/<my-aws-pool-id>
安全配置.java
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();
}
}
我想干什么
在我的后端应用程序中,我希望能够从amazoncognito访问用户信息。目前,我的后端应用程序中有以下基本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
}
}
但我希望能够访问真正的用户名和电子邮件在后端。
我的问题
我必须在amazoncognito中为后端创建一个新的客户机吗?或者我必须为网关和后端配置相同的客户端id和客户端密码吗?
我必须在我的应用程序(网关和后端)中进行哪些额外的spring配置才能使其工作?
我用的是Spring Boot 2.3.6.RELEASE
1条答案
按热度按时间6mzjoqzu1#
问得好,您在使用API时遇到了以下常见的oauth问题:
cognito访问令牌包含很少的用户信息,这是一个很好的实践——它们不可定制,只包含一个主题声明
spring只想从jwt创建一个authenticatedprincipal,但是您的api还希望向authenticatedprincipal添加其他声明
设计模式
有一个设计模式,你可以使用,或借鉴的想法,我的博客文章总结了行为。其思想是首先定义一个声明主体,然后在运行时用来自多个源的声明填充它。在您的例子中,一个源将是cognito用户信息端点。
工作代码
您可以运行我的示例springbootapi,它也使用awscognito,关键类是authorizer。在某些设置中,您可以使用api网关来为您完成以下工作:
如何运行api
spring boot oauth与自定义声明集成
利弊
此模式将为您提供可扩展的声明,但也会给api增加一些复杂性,因为您需要覆盖api技术堆栈的默认oauth行为。