如何在Azure中实现Spring Security Web API与SSO Angular 9应用的认证对接?
我完全懂你折腾三周的崩溃——Azure AD前后端认证的坑确实多,尤其是把现成示例适配到自己项目时,很容易卡壳。咱们先把核心理清楚,再给你一套能直接落地的配置方案,避开那些常见的陷阱。
核心认证流程先搞明白
整个链路其实很清晰,你之前可能没抓准关键节点:
- 前端Angular通过
@azure/msal-angular向Azure AD请求针对后端API的Access Token(不是ID Token!这是很多人踩的第一个坑) - 前端每次调用后端API时,在请求头的
Authorization字段里带上Bearer <Access Token> - Spring Boot后端验证这个Token的有效性:包括签名是否合法、受众是否匹配、是否过期、签发者是否可信
- 验证通过后,后端处理请求并返回结果
Angular前端关键配置调整
你之前的SSO功能正常,但要确保拿到的是给后端用的Access Token:
- 在
msal配置里,添加后端API的专属scope,格式是api://<你的后端API的Azure AD客户端ID>/<自定义scope名>(比如api://xxxxxx/access_as_user) - 启用
MsalInterceptor,让它自动给后端API的请求带上Token,配置示例:export const protectedResourceMap = new Map<string, Array<string>>([ ['http://localhost:8080/api/**', ['api://xxxxxx/access_as_user']] ]); @NgModule({ providers: [ { provide: HTTP_INTERCEPTORS, useClass: MsalInterceptor, multi: true }, { provide: MSAL_INSTANCE, useFactory: MSALInstanceFactory }, { provide: MSAL_GUARD_CONFIG, useFactory: MSALGuardConfigFactory }, { provide: MSAL_INTERCEPTOR_CONFIG, useFactory: MSALInterceptorConfigFactory }, MsalService, MsalGuard, MsalBroadcastService ] }) - 可以在浏览器控制台的Network标签里,查看后端请求的
Authorization头,确认是长串的Access Token(不是ID Token,ID Token里会有name、email等用户信息,Access Token主要是权限相关)
Spring Boot后端亲测有效的配置
别再乱试零散的示例了,用官方的azure-spring-boot-starter-active-directory就能搞定,步骤如下:
- 先加依赖(注意和Spring Boot版本匹配,Spring Boot 3.x用4.x以上的starter):
<dependency> <groupId>com.azure.spring</groupId> <artifactId>azure-spring-boot-starter-active-directory</artifactId> <version>4.12.0</version> <!-- 选最新兼容版本 --> </dependency> - 在
application.yml里配置Azure AD信息:azure: active-directory: client-id: <你的后端API在Azure AD里的客户端ID> tenant-id: <你的Azure AD租户ID> app-id-uri: <后端API的应用ID URI,比如api://xxxxxx> - 配置安全过滤器链,处理认证和跨域:
@Configuration @EnableWebSecurity public class SecurityConfig { private final AADResourceServerHttpSecurityConfigurer aadConfigurer; public SecurityConfig(AADResourceServerHttpSecurityConfigurer aadConfigurer) { this.aadConfigurer = aadConfigurer; } @Bean public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { http .authorizeHttpRequests(auth -> auth.anyRequest().authenticated()) .csrf(csrf -> csrf.disable()) // 前后端分离场景下关闭CSRF .cors(cors -> cors.configurationSource(corsConfig())) .apply(aadConfigurer); // 启用Azure AD的资源服务器验证 return http.build(); } @Bean public CorsConfigurationSource corsConfig() { CorsConfiguration config = new CorsConfiguration(); config.setAllowedOrigins(List.of("http://localhost:4200")); // 你的Angular前端地址 config.setAllowedMethods(List.of("GET", "POST", "PUT", "DELETE", "OPTIONS")); config.setAllowedHeaders(List.of("*")); config.setAllowCredentials(true); UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource(); source.registerCorsConfiguration("/**", config); return source; } }
必须检查的Azure AD配置(重中之重)
很多时候代码没问题,是Azure AD的配置没到位:
- 后端API的Azure AD应用里,必须配置暴露API:添加一个scope(比如
access_as_user),并设置为“已启用” - 前端Angular的Azure AD应用里,必须添加API权限:找到后端API的scope,授权并同意(管理员同意)
- 确认后端API的
应用ID URI和配置文件里的app-id-uri完全一致,否则Token的受众(aud)不匹配,验证会失败
常见坑点排查
如果你还是卡壳,先检查这几点:
- 用
https://jwt.ms/解析前端拿到的Token,看aud字段是否等于后端的app-id-uri或者客户端ID,不对的话就是前端请求的scope错了 - 看后端日志,是否有
invalid audience、invalid signature之类的错误,针对性调整 - 确保Spring Boot和Azure starter的版本兼容,比如Spring Boot 2.x用3.x的starter,3.x用4.x的starter
内容的提问来源于stack exchange,提问作者Marcus Lanvers
相关产品推荐
相关产品推荐

