You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

为Spring Boot REST API配置AAD与AWS Cognito多认证授权

问题描述

我现有一个Spring Boot REST API,当前配置包含两类路由:

  • 未授权路由
  • 通过AAD/Entra的Bearer令牌授权的路由

当前的configure方法配置如下:

@Override
protected void configure(HttpSecurity http) throws Exception {
        super.configure(http);
        http.csrf().disable();
        http.authorizeRequests(requests -> requests
                .antMatchers(HttpMethod.OPTIONS, "/**/**").permitAll()
                .antMatchers("/api/protected/**").fullyAuthenticated()
                .anyRequest().permitAll()
        );
}

该配置类继承自AadResourceServerWebSecurityConfigurerAdapter。

通过此配置,我们可以像这样保护路由:

@PreAuthorize("hasAuthority('APPROLE_AppName.RoleName')")
@GetMapping(value = "/some-method", produces = MediaType.APPLICATION_JSON_VALUE)
public ResponseEntity<List<String>> getStrings() {
    return ResponseEntity.ok(...);
}

现在API需要扩展,允许由AWS Cognito管理的新用户访问授权端点。请问如何配置WebSecurityConfigurerAdapter,使某些路径无需授权、部分通过AAD保护、部分通过AWS Cognito保护?

我遇到的主要问题是AadResourceServerWebSecurityConfigurerAdapter配置的JWT验证仅适用于微软颁发的Bearer令牌。

理想情况下,我希望实现如下配置:

@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter { 

    @Configuration
    @Order(1)
    public static class AzureAdSecurityConfig extends AadResourceServerWebSecurityConfigurerAdapter {

        @Override
        protected void configure(HttpSecurity http) throws Exception {
            http.authorizeRequests(requests -> requests
                    .antMatchers("/api/aad/**").fullyAuthenticated()
            );
            http.oauth2ResourceServer().jwt([使用AAD JWT验证]);
        }

    }

    @Configuration
    @Order(2)
    public static class AwsCognitoSecurityConfig extends WebSecurityConfigurerAdapter {

        @Override
        protected void configure(HttpSecurity http) throws Exception {
            http.authorizeRequests(requests -> requests
                    .antMatchers("/api/cognito/**").fullyAuthenticated()
            );
            http.oauth2ResourceServer().jwt([使用AWS Cognito JWT验证]);
        }
    }

    @Configuration
    @Order(3)
    public static class DefaultSecurityConfig extends WebSecurityConfigurerAdapter {

            @Override
            protected void configure(HttpSecurity http) throws Exception {
                http.csrf().disable();
                http.authorizeRequests(requests -> requests
                        .antMatchers(HttpMethod.OPTIONS, "/**/**").permitAll()
                        .anyRequest().permitAll()
                );
            }
    }

}

另一个问题是AadResourceServerWebSecurityConfigurerAdapter会自动为JwtClaimNames的"roles"和"scp"设置前缀"SCOPE_"和"APPROLE_"。我希望为AAD和AWS Cognito设置不同的前缀,比如"AAD_SCOPE_"、"AAD_APPROLE_"和"COGNITO_GROUP_"。

我找到一些关于Spring Boot实现多租户JWT验证的资料,但它们都仅基于SQL数据库实现密码/用户认证。

有没有办法无需重新实现所有AAD逻辑,就能加入AWS Cognito颁发的JWT验证,或者能否基于路由进行区分?我知道可以通过HttpSecurity的oauth2ResourceServer()函数配置JWT使用,但仅找到单租户的实现信息。

如果有人已成功实现此类或类似案例,或能提供方向指引,我将不胜感激。或者我的思路完全错误,也请告知。


更新(2024年1月25日):可用解决方案

感谢帮助,我已实现功能,具体如下:

application.yml

com:
  c4-soft:
    springaddons:
      oidc:
        ops:
          - iss: https://cognito-idp.<region>.amazonaws.com/<cognito-pool>
            authorities:
              - path: $.cognito:groups
                prefix: COGNITO_GROUP_
          - iss: https://sts.windows.net/<entra objectid>/
            authorities:
              - path: $.roles.*
                prefix: AAD_APPROLE_
              - path: $.scp
                prefix: AAD_SCOPE_
            aud: <enterprise application id>
        resource-server:
          permit-all:
            - /api/route/noauth

SecurityConfig

package some.package;

import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.method.configuration.EnableMethodSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;

@EnableWebSecurity
@EnableMethodSecurity
@Configuration
public class SecurityConfig { }

控制器代码

package some.package;


import org.springframework.http.ResponseEntity;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.oauth2.jwt.Jwt;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequestMapping("/api/route")
public class JwtTestController {

    @GetMapping("/aadauth")
    @PreAuthorize("hasAuthority('AAD_APPROLE_GrantedApprole.XXX')")
    public ResponseEntity<String> aadauthRole() {
        Jwt jwt = (Jwt) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
        return ResponseEntity.ok(jwt.getClaims().toString());
    }

    @GetMapping("/aadauth")
    @PreAuthorize("hasAuthority('AAD_SCOPE_GrantedScope.XXX')")
    public ResponseEntity<String> aadauthScope() {
        Jwt jwt = (Jwt) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
        return ResponseEntity.ok(jwt.getClaims().toString());
    }

    @PreAuthorize("hasAuthority('COGNITO_GROUP_SomeGroup')")
    @GetMapping("/cognitoauth")
    public ResponseEntity<String> cognitoauth() {
        Jwt jwt = (Jwt) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
        return ResponseEntity.ok(jwt.getClaims().toString());
    }

    @GetMapping("/noauth")
    public ResponseEntity<String> noauth() {
        return ResponseEntity.ok("Hello World!");
    }

}

build.gradle

implementation 'org.springframework.boot:spring-boot-starter-oauth2-resource-server'
    implementation 'com.c4-soft.springaddons:spring-addons-starter-oidc:7.3.5'

这并非Spring官方starter,而是一个开源实现。目前运行正常,若遇到其他问题我会再次更新。


内容的提问来源于stack exchange,提问作者Fabian Schmidt

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.01 11:21:10