如何使用AWS Cognito的IAM角色实现Spring Boot接口的Spring Security权限控制?
问题根因
你遇到的403错误本质是两个核心问题:
- Spring Security OAuth2 默认不会自动解析
cognito:roles字段为权限集合,需要手动映射到Spring的GrantedAuthority体系 hasRole()方法会自动给权限值添加ROLE_前缀,你传入的完整ARN没有前缀,自然匹配失败
解决步骤
步骤1:自定义Cognito角色权限映射器
新增自定义权限映射逻辑,将cognito:roles中的角色转为Spring可识别的权限对象:
import org.springframework.security.core.GrantedAuthority; import org.springframework.security.core.authority.SimpleGrantedAuthority; import org.springframework.security.oauth2.core.user.OAuth2UserAuthority; import java.util.Collection; import java.util.Collections; import java.util.Map; import java.util.stream.Collectors; // 放在SecurityConfiguration类内部即可 private GrantedAuthoritiesMapper customAuthoritiesMapper() { return (authorities) -> { // 从OAuth2授权信息中提取用户属性 Map<String, Object> attributes = authorities.stream() .filter(OAuth2UserAuthority.class::isInstance) .map(OAuth2UserAuthority.class::cast) .findFirst() .map(OAuth2UserAuthority::getAttributes) .orElse(Collections.emptyMap()); // 提取cognito返回的角色列表 Object rolesObj = attributes.get("cognito:roles"); if (rolesObj instanceof Collection) { Collection<?> rawRoles = (Collection<?>) rolesObj; return rawRoles.stream() .map(Object::toString) // 如果要使用hasRole()方法,这里要加ROLE_前缀,示例: // .map(role -> new SimpleGrantedAuthority("ROLE_" + role)) // 如果直接用hasAuthority()方法,不需要加前缀,直接用完整ARN .map(SimpleGrantedAuthority::new) .collect(Collectors.toList()); } return Collections.emptyList(); }; }
步骤2:将映射器注册到安全配置中
修改你的SecurityConfiguration的configure方法,把权限映射器配置到OAuth2登录流程:
@Override protected void configure(HttpSecurity http) throws Exception { http.csrf() .and() .authorizeRequests() .antMatchers("/login", "/", "/home", "/logout", "/ping").permitAll() // 注意这里改用hasAuthority,因为我们映射的时候没有加ROLE_前缀 .antMatchers("/api/admin").hasAuthority("arn:aws:iam::xxxxxx:role/spring-sso-test-ADMIN") .antMatchers("/api/user").hasAuthority("arn:aws:iam::xxxxxx:role/spring-sso-test-USER") .anyRequest().authenticated() .and() .oauth2Login() // 注册自定义权限映射器 .userInfoEndpoint() .userAuthoritiesMapper(customAuthoritiesMapper()) .and() .and() .logout() .logoutSuccessUrl("/logout"); }
补充说明:
hasRole("ADMIN")等价于hasAuthority("ROLE_ADMIN"),如果你的角色ARN不想加前缀,统一用hasAuthority是最简单的方案。
步骤3:开启注解权限校验支持(如果需要用@Secured/@PreAuthorize)
首先在你的安全配置类上添加@EnableGlobalMethodSecurity注解开启方法级权限校验:
@Configuration @EnableGlobalMethodSecurity(securedEnabled = true, prePostEnabled = true) public class SecurityConfiguration extends WebSecurityConfigurerAdapter { // 原有配置不变 }
@Secured注解同样会默认匹配带ROLE_前缀的权限,如果你映射权限的时候没有加前缀,建议改用@PreAuthorize注解:
// 不需要ROLE_前缀的写法,和接口路径校验规则一致 @PreAuthorize("hasAuthority('arn:aws:iam::xxxxxx:role/spring-sso-test-ADMIN')") @GetMapping(produces = "application/json") public TestResponse get() { return new TestResponse("Admin API Response"); }
高版本Spring Boot适配说明
如果你使用的是Spring Boot 2.7+或3.x版本,WebSecurityConfigurerAdapter已经被废弃,建议改用SecurityFilterChain和GrantedAuthoritiesMapper Bean的写法即可,权限映射和校验逻辑和上述完全一致。
内容的提问来源于stack exchange,提问作者tomaytotomato
相关产品推荐
相关产品推荐

