java Sping Boot -支持多个颁发者URI

fdx2calv  于 2023-02-18  发布在  Java
关注(0)|答案(2)|浏览(154)

你好,我一直在网上搜索,但收效甚微,我希望有人在这里SO可能能够帮助。
目前,我的Sping Boot API(版本2.5.4)接受Auth 0提供的JWT。现在,我已经在那里创建了第二个租户,我正在努力理解如何支持两个或更多的issuer-uri。
以下是我目前的做法:

@Configuration
@EnableWebSecurity(debug = false)
@EnableGlobalMethodSecurity(
        securedEnabled = true,
        jsr250Enabled = true,
        prePostEnabled = true
)
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Value("${auth0.audience}")
    private String audience;

    @Value("${spring.security.oauth2.resourceserver.jwt.issuer-uri}")
    private String issuer;

    @Bean
    CorsConfigurationSource corsConfigurationSource() {
        CorsConfiguration configuration = new CorsConfiguration();
        configuration.setAllowedOrigins(Arrays.asList("http://localhost:3010"));
        configuration.setAllowedMethods(Arrays.asList("GET", "POST"));
        configuration.setAllowCredentials(true);
        configuration.addAllowedHeader("Authorization");
        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
        source.registerCorsConfiguration("/**", configuration);
        return source;
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {

        http
                .cors()
                .and()
                .sessionManagement()
                .sessionCreationPolicy(SessionCreationPolicy.STATELESS)
                .and()
                .headers().referrerPolicy(ReferrerPolicyHeaderWriter.ReferrerPolicy.SAME_ORIGIN)
                .and()
                .xssProtection()
                .and()
                .contentSecurityPolicy("script-src 'self'").and()
                .and()
                .csrf()
                .disable()
                .formLogin()
                .disable()
                .httpBasic()
                .disable()
                .exceptionHandling()
                .authenticationEntryPoint(new RestAuthenticationEntryPoint())
                .and()
                .authorizeRequests()
                .antMatchers("/api/v1/user/profile/**").permitAll()
                .antMatchers("/user/profile/**").permitAll()
                .antMatchers("/swagger-resources/**").permitAll()        
                .anyRequest()
                .authenticated()
                .and()
                .oauth2ResourceServer().jwt();
    }

    @Override
    public void configure(WebSecurity web) throws Exception {
        web.ignoring().antMatchers("/health", "/health/**");
    }

    @Bean
    JwtDecoder jwtDecoder() {
        /*
        By default, Spring Security does not validate the "aud" claim of the token, to ensure that this token is
        indeed intended for our app. Adding our own validator is easy to do:
        */

        NimbusJwtDecoder jwtDecoder = (NimbusJwtDecoder)
                JwtDecoders.fromOidcIssuerLocation(issuer);

        OAuth2TokenValidator<Jwt> audienceValidator = new AudienceValidator(audience);
        OAuth2TokenValidator<Jwt> withIssuer = JwtValidators.createDefaultWithIssuer(issuer);
        OAuth2TokenValidator<Jwt> withAudience = new DelegatingOAuth2TokenValidator<>(withIssuer, audienceValidator);

        jwtDecoder.setJwtValidator(withAudience);

        return jwtDecoder;
    }
}

有没有人能解释一下,我可以用Node将issuer-uri设置为String数组,并且它可以开箱即用。希望Spring中也有类似的东西?
编辑:在需要的情况下,这里是我的版本构建文件:

plugins {
    id "org.springframework.boot" version "2.5.4"
    id 'io.spring.dependency-management' version '1.0.11.RELEASE'
    id 'java'
    id "com.github.davidmc24.gradle.plugin.avro" version "1.2.0"
    id "idea"
    id 'com.google.cloud.tools.jib' version '3.0.0'
}

apply plugin: 'idea'

group 'org.example'
version '1.0'

java {
    sourceCompatibility = JavaVersion.VERSION_14
    targetCompatibility = JavaVersion.VERSION_14
}

jib.from.image = 'openjdk:15-jdk-buster'
jib.to.image = 'gcr.io/thefullstack/tfs-project-service'

ext {
    avroVersion = "1.10.1"
}

repositories {
    mavenCentral()
    jcenter()
    maven {
        url "https://packages.confluent.io/maven/"
    }
}

avro {
    createSetters = true
    fieldVisibility = "PRIVATE"
}

dependencies {
    implementation('org.springframework.boot:spring-boot-starter-data-elasticsearch')
    implementation group: 'org.springframework.boot', name: 'spring-boot-starter-data-mongodb'
    implementation group: 'org.springframework.data', name: 'spring-data-elasticsearch'
    implementation group: 'org.springframework.boot', name: 'spring-boot-starter-security'
    implementation group: 'org.springframework.security', name: 'spring-security-oauth2-client'
    implementation group: 'org.springframework.boot', name: 'spring-boot-starter-validation'
    implementation group: 'org.springframework.boot', name: 'spring-boot-starter-oauth2-resource-server'
    implementation group: 'org.springframework.boot', name: 'spring-boot-starter-cache'
    implementation("org.springframework.boot:spring-boot-starter-actuator")
    implementation group: 'org.springframework.integration', name: 'spring-integration-core', version: '5.5.3'

//    implementation group: 'org.springframework.cloud', name: 'spring-cloud-gcp-starter-logging'
    implementation group: 'org.springframework.cloud', name: 'spring-cloud-gcp-starter-logging', version: '1.2.8.RELEASE'
    implementation("org.springframework.cloud:spring-cloud-gcp-starter-pubsub:1.2.5.RELEASE")
    implementation("org.springframework.integration:spring-integration-core")

    implementation group: 'com.amazonaws', name: 'aws-java-sdk', version: '1.11.860'
    implementation group: 'com.mashape.unirest', name: 'unirest-java', version: '1.4.9'

    implementation group: 'javax.validation', name: 'validation-api', version: '2.0.1.Final'
    implementation group: 'com.fasterxml.jackson.datatype', name: 'jackson-datatype-jsr310', version: '2.12.3'
    implementation group: 'com.fasterxml.jackson.core', name: 'jackson-core', version: '2.12.3'
    implementation group: 'io.jsonwebtoken', name: 'jjwt', version: '0.9.1'
    implementation group: 'org.openapitools', name: 'jackson-databind-nullable', version: '0.2.1'

    implementation group: 'commons-io', name: 'commons-io', version: '2.6'
    implementation group: 'org.apache.commons', name: 'commons-collections4', version: '4.4'
    implementation group: 'org.apache.commons', name: 'commons-lang3', version: '3.11'

    implementation group: 'com.auth0', name: 'java-jwt', version: '3.12.0'
    implementation "org.apache.avro:avro:1.10.1"
    implementation "org.apache.avro:avro:${avroVersion}"

    implementation 'org.projectlombok:lombok:1.18.20'
    annotationProcessor 'org.projectlombok:lombok:1.18.20'

    implementation 'com.amazonaws:aws-java-sdk-s3'
    implementation 'org.springframework.boot:spring-boot-starter-web'

    testImplementation group: 'junit', name: 'junit', version: '4.12'
    testImplementation 'org.projectlombok:lombok:1.18.20'
    testAnnotationProcessor 'org.projectlombok:lombok:1.18.20'

    testImplementation('org.springframework.boot:spring-boot-starter-test') {
        exclude group: 'org.junit.vintage', module: 'junit-vintage-engine'
    }
}
wz1wpwve

wz1wpwve1#

我在这个问题上挣扎了一段时间。
下面的代码可以处理多个问题(用户池),它是一个 spring.security.oauth2.resourceserver.jwt.issuer-uri 属性的替代方法
请查看SpringSecurity配置的代码:

@Component
@ConfigurationProperties(prefix = "config")
class JWTIssuersProps {
    private List<String> issuers;

    // getter and setter
    public List<String> getIssuers() {
        return issuers;
    }

    public void setIssuers(List<String> issuers) {
        this.issuers = issuers;
    }
}

@Configuration
public class JWTCustomSecurityConfiguration extends WebSecurityConfigurerAdapter {

    @Autowired
    private JWTIssuersProps props;

    Map<String, AuthenticationManager> authenticationManagers = new HashMap<>();

    JwtIssuerAuthenticationManagerResolver authenticationManagerResolver =
            new JwtIssuerAuthenticationManagerResolver(authenticationManagers::get);

    @Override
    protected void configure(HttpSecurity http) throws Exception {

        List<String> propsIssuers = props.getIssuers();
        propsIssuers.forEach(issuer -> addManager(authenticationManagers, issuer));

        http.
                // CORS configuration
                cors().configurationSource(request -> {
                    var cors = new CorsConfiguration();
                    cors.setAllowedOrigins(List.of("http://localhost:3000"));
                    cors.setAllowedMethods(List.of("GET", "POST", "PUT", "DELETE", "OPTIONS"));
                    cors.setAllowedHeaders(List.of("*"));
                    return cors;
                })

                .and()
                .authorizeRequests()
                .antMatchers("/actuator/**").permitAll()
                .and()
                .oauth2ResourceServer(oauth2ResourceServer -> {
                    oauth2ResourceServer.authenticationManagerResolver(this.authenticationManagerResolver);
                });
    }

    public void addManager(Map<String, AuthenticationManager> authenticationManagers, String issuer) {
        JwtDecoder jwtDecoder = JwtDecoders.fromOidcIssuerLocation(issuer);

        JwtAuthenticationProvider authenticationProvider = new JwtAuthenticationProvider(jwtDecoder);
        authenticationProvider.setJwtAuthenticationConverter(new MyJwtAuthenticationConverter());
        authenticationManagers.put(issuer, authenticationProvider::authenticate);
    }

    static class MyJwtAuthenticationConverter extends JwtAuthenticationConverter {
        @Override
        protected Collection<GrantedAuthority> extractAuthorities(final Jwt jwt) {
            List<String> groups = jwt.getClaim("cognito:groups");

            System.out.println("User groups list.size =" + groups.size());
            System.out.println("User groups:");
            groups.forEach(System.out::println);

            List<GrantedAuthority> authorities = new ArrayList<>();
            for (String role : groups) {
                authorities.add(new SimpleGrantedAuthority(role));
            }
            return authorities;
        }
    }
}

它需要应用程序.yaml文件:

config:
  issuers:
  - https://cognito-idp.ca-central-1.amazonaws.com/<pool-ID-1>
  - https://cognito-idp.ca-central-1.amazonaws.com/<pool-ID-2>

我也有CORS配置在那里。并阅读亚马逊认知组。
您可以在这里找到完整的项目源代码:https://github.com/grenader/spring-security-cognito-oauth2-jwt/tree/java

2skhul33

2skhul332#

还不能发表评论,所以这样评论。
上面的解决方案由伊戈尔是正确的和工作!
需要注意的是,您可能希望将JwtIssuerAuthenticationManagerResolver实现为@Bean。这样做将禁用Spring Boot UserDetailsServiceAutoConfiguration自动配置,在本例中我们不希望出现这种情况(但也有其他方法可以实现)。

相关问题