如何使用id_token保护对接Azure AD B2C的Java Spring Boot 3 API?
解决方案思路与实现步骤
首先明确:Azure AD B2C的id_token是标准JWT令牌,尽管它的设计初衷是用户身份认证凭证而非API授权凭证,但我们可以通过验证其签名、核心声明(如受众、签发者、有效期)来实现API保护,完全不需要依赖access_token或OBO(On-Behalf-Of)流程。
步骤1:Azure AD B2C应用注册配置
- 确保你的API应用注册已启用ID令牌支持:在API应用的「身份验证」设置中,勾选「ID令牌」选项(用于让B2C的密钥服务能为id_token提供验证依据)
- 记录三个关键信息:API应用的客户端ID(对应id_token的
aud声明)、B2C租户ID、用户流/自定义策略名称(用于构造JWKS验证端点)
步骤2:Spring Boot 3 依赖与配置(Java 17)
依赖配置(pom.xml)
引入Spring Security OAuth2资源服务器依赖,它原生支持JWT验证:
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-oauth2-resource-server</artifactId> </dependency>
应用配置(application.yml)
配置JWT验证的核心参数,确保与id_token的声明匹配:
spring: security: oauth2: resourceserver: jwt: audience: <你的API应用客户端ID> issuer-uri: https://<你的B2C租户名>.b2clogin.com/<你的B2C租户ID>/<用户流/自定义策略名称>/v2.0/ jwk-set-uri: https://<你的B2C租户名>.b2clogin.com/<你的B2C租户ID>/<用户流/自定义策略名称>/discovery/v2.0/keys
注意:
issuer-uri必须和id_token里的iss声明完全一致,audience必须匹配id_token的aud声明(即API应用的客户端ID)
步骤3:Spring Security 安全规则配置
创建安全配置类,保护API端点并启用JWT验证:
import org.springframework.context.annotation.Bean; 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.web.SecurityFilterChain; @Configuration @EnableWebSecurity public class SecurityConfig { @Bean public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception { http .authorizeHttpRequests(auth -> auth .anyRequest().authenticated() ) .oauth2ResourceServer(oauth2 -> oauth2 .jwt(jwt -> jwt // 可选:自定义身份转换,从id_token提取用户信息 .jwtAuthenticationConverter(new CustomJwtAuthConverter()) ) ); return http.build(); } }
可选:自定义用户身份提取
如果需要从id_token中提取用户信息(如邮箱、用户名)用于业务逻辑,可自定义转换器:
import org.springframework.core.convert.converter.Converter; import org.springframework.security.authentication.AbstractAuthenticationToken; import org.springframework.security.oauth2.jwt.Jwt; import org.springframework.security.oauth2.server.resource.authentication.JwtAuthenticationToken; import org.springframework.security.oauth2.server.resource.authentication.JwtGrantedAuthoritiesConverter; import java.util.Collections; public class CustomJwtAuthConverter implements Converter<Jwt, AbstractAuthenticationToken> { private final JwtGrantedAuthoritiesConverter defaultConverter = new JwtGrantedAuthoritiesConverter(); @Override public AbstractAuthenticationToken convert(Jwt jwt) { var authorities = defaultConverter.convert(jwt); // 从id_token的声明中提取用户名,这里用email示例 String username = jwt.getClaim("email"); return new JwtAuthenticationToken(jwt, authorities != null ? authorities : Collections.emptySet(), username); } }
关键注意事项
- 受众声明必须匹配:如果Web应用获取的id_token的
aud是Web应用的客户端ID,需要在B2C用户流/自定义策略中修改id_token的aud为API的客户端ID,或者在API配置中允许多个受众(将spring.security.oauth2.resourceserver.jwt.audiences设为数组) - 细粒度授权处理:id_token默认不包含API权限信息,如果需要按角色/权限控制访问,可在B2C中为id_token添加自定义声明(如
roles),然后在Security配置中基于这些声明做权限校验 - 确保令牌未被篡改:Web应用必须原样转发id_token,不能修改任何内容,否则签名验证会失败
- 自动验证核心声明:Spring Security会自动验证JWT的签名、过期时间(
exp)、生效时间(nbf)等,无需手动处理
为什么user_impersonation和OBO流程不适用?
user_impersonation权限是用于申请access_token的前置条件,而你的场景无法获取access_token,因此该权限无效- OBO流程需要以access_token为输入,用于中间层API向下游API申请新的access_token,你只有id_token,不符合该流程的触发条件
内容的提问来源于stack exchange,提问作者Martinsiyo
相关产品推荐
相关产品推荐

