如何用Azure AD B2C保护Spring Boot REST API?配置遇401问题求助
Hey there! Let's tackle this 401 "invalid_token" issue you're facing with your Spring Boot 2.2.0 + Azure AD B2C REST API setup. The problem likely stems from conflicting dependencies and missing configuration to properly validate B2C-issued tokens. Here's a step-by-step solution tailored to your setup:
You mentioned adding spring-security-oauth2 2.3.7.RELEASE alongside the azure-active-directory-b2c-spring-boot-starter 2.2.0—this is almost certainly causing dependency conflicts. The Azure B2C starter already includes all necessary Spring Security OAuth2 components for both web UI and resource server scenarios.
Remove the explicit spring-security-oauth2 dependency from your build file. Your relevant dependencies should look like this:
For Maven (pom.xml):
<dependencies> <!-- Spring Boot Web --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <!-- Thymeleaf + Security for web pages --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-thymeleaf</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-security</artifactId> </dependency> <!-- Azure AD B2C Starter --> <dependency> <groupId>com.microsoft.azure</groupId> <artifactId>azure-active-directory-b2c-spring-boot-starter</artifactId> <version>2.2.0</version> </dependency> </dependencies>
For Gradle (build.gradle):
dependencies { implementation 'org.springframework.boot:spring-boot-starter-web' implementation 'org.springframework.boot:spring-boot-starter-thymeleaf' implementation 'org.springframework.boot:spring-boot-starter-security' implementation 'com.microsoft.azure:azure-active-directory-b2c-spring-boot-starter:2.2.0' }
Update your application.yml (or application.properties) with settings that tell Spring how to validate B2C Bearer tokens. Replace placeholders with your actual tenant ID, policy name, and API client ID:
spring: security: oauth2: resourceserver: jwt: issuer-uri: https://<your-tenant-id>.b2clogin.com/<your-tenant-id>.onmicrosoft.com/B2C_1_<your-custom-policy>/v2.0/ jwk-set-uri: https://<your-tenant-id>.b2clogin.com/<your-tenant-id>.onmicrosoft.com/B2C_1_<your-custom-policy>/discovery/v2.0/keys azure: activedirectory: b2c: tenant: <your-tenant-id>.onmicrosoft.com client-id: <your-api-client-id> # Client ID of your API registered in Azure AD B2C user-flows: sign-up-or-sign-in: B2C_1_<your-custom-policy> # Match your custom policy name
Critical Note: The
client-idhere must match the audience (audclaim) in the access token you get from the password flow. When requesting the token, always include theresourceparameter set to your API's client ID—otherwise theaudclaim will be incorrect, triggering the "invalid_token" error.
You need to split security rules to handle both your existing Thymeleaf web pages and REST API endpoints with Bearer token validation. Create or modify your security config class like this:
import org.springframework.context.annotation.Configuration; import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; @Configuration public class SecurityConfig extends WebSecurityConfigurerAdapter { @Override protected void configure(HttpSecurity http) throws Exception { http // Allow unauthenticated access to static assets (adjust paths as needed) .authorizeRequests() .antMatchers("/css/**", "/js/**", "/images/**").permitAll() // Protect all API endpoints with Bearer token validation .antMatchers("/api/**").authenticated() // Protect web pages with your existing B2C form-based auth .anyRequest().authenticated() .and() // Configure resource server for Bearer tokens .oauth2ResourceServer() .jwt() .and() .and() // Keep your existing web UI security setup .formLogin() .and() .logout() .logoutSuccessUrl("/"); } }
Double-check that your token request includes the correct parameters to ensure the token is valid for your API. Your POST request should look like this (using form-data or x-www-form-urlencoded format):
POST https://<your-tenant-id>.b2clogin.com/<your-tenant-id>.onmicrosoft.com/oauth2/v2.0/token?p=B2C_1_<your-custom-policy>
Required parameters:
grant_type: passwordusername: your-user@example.compassword: your-user-passwordclient_id:# Client ID of your registered mobile app in B2C resource:# Must match the client-id in your Spring config scope: openid offline_access # Add any API-specific scopes you've defined
If you still get 401 errors, run through these checks:
- Audience Mismatch: Use a tool like jwt.io to decode your token and confirm the
audclaim exactly matches your API's client ID. - Issuer Validation: Ensure the
issclaim in the token matches theissuer-uriin your config (including the trailing slash and policy name). - JWKS Endpoint Access: Confirm your Spring app can reach the
jwk-set-uri—check firewall/proxy settings if your app is behind a corporate network. - Token Expiry: Verify the
expclaim to make sure the token hasn't expired.
内容的提问来源于stack exchange,提问作者Wim Deblauwe

