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

React+Spring Boot集成Azure AD:认证成功但授权失败

React+Spring Boot集成Azure AD:认证正常但授权失效问题

问题概述

搭建React前端+Spring Boot后端应用,集成Azure Active Directory实现认证授权,认证功能正常,但授权失效。

前端MSAL认证状态

前端通过MSAL实现认证,已成功获取用户账户,控制台日志无异常。令牌请求/响应关键信息:

  • 请求地址:https://login.microsoftonline.com/{XX}/oauth2/v2.0/token
  • 令牌核心参数:
    scope: "User.Read profile openid email"
    token_type: "Bearer"
    

后端错误详情

后端返回授权失败,日志显示核心问题:资源服务器未解析出用户权限范围,Granted Authorities为空数组:

Failed to authorize filter invocation [GET /api/document/list] with attributes [hasAuthority('SCOPE_User.Read')] using AffirmativeBased [DecisionVoters=[org.springframework.security.web.access.expression.WebExpressionVoter@470b5213], AllowIfAllAbstainDecisions=false]
Sending JwtAuthenticationToken [Principal=org.springframework.security.oauth2.jwt.Jwt@43ebd8ff, Credentials=[PROTECTED], Authenticated=true, Details=WebAuthenticationDetails [RemoteIpAddress=0:0:0:0:0:0:0:1, SessionId=null], Granted Authorities=[]] to access denied handler since access is denied

后端配置信息

Spring Security配置类

@Configuration
public class SecurityConfig {
    @Bean
    SecurityFilterChain web(HttpSecurity http) throws Exception {
        http.authorizeRequests((authorize) -> authorize
                        .mvcMatchers("/**").hasAuthority("SCOPE_User.Read")      // .permitAll()
                        .anyRequest().authenticated())
                .oauth2ResourceServer(OAuth2ResourceServerConfigurer::jwt);
        return http.build();
    }
}

application.properties配置

spring.security.oauth2.resourceserver.jwt.issuer-uri=https://login.microsoftonline.com/{XX}/v2.0

问题原因与解决方案

核心原因

Azure AD v2.0版本的JWT令牌中,委派权限默认存放在scp字段(而非Spring Security默认读取的scope字段),导致权限无法被自动解析。

解决方案

1. 配置JWT权限转换器,从scp字段提取权限

添加自定义转换器,指定从scp字段读取权限并保留SCOPE_前缀,与配置中的hasAuthority匹配:

@Configuration
public class SecurityConfig {
    @Bean
    SecurityFilterChain web(HttpSecurity http) throws Exception {
        http.authorizeRequests((authorize) -> authorize
                        .mvcMatchers("/**").hasAuthority("SCOPE_User.Read")
                        .anyRequest().authenticated())
                .oauth2ResourceServer(oauth2 -> oauth2
                        .jwt(jwt -> jwt.jwtAuthenticationConverter(jwtAuthenticationConverter())));
        return http.build();
    }

    private JwtAuthenticationConverter jwtAuthenticationConverter() {
        JwtGrantedAuthoritiesConverter grantedAuthoritiesConverter = new JwtGrantedAuthoritiesConverter();
        // 指定从scp字段提取权限
        grantedAuthoritiesConverter.setAuthoritiesClaimName("scp");
        // 保持SCOPE_前缀,与hasAuthority参数一致
        grantedAuthoritiesConverter.setAuthorityPrefix("SCOPE_");

        JwtAuthenticationConverter jwtAuthenticationConverter = new JwtAuthenticationConverter();
        jwtAuthenticationConverter.setJwtGrantedAuthoritiesConverter(grantedAuthoritiesConverter);
        return jwtAuthenticationConverter;
    }
}

2. 验证Azure AD应用注册配置

  • 确保后端应用注册已添加Microsoft Graph的User.Read委派权限,并完成管理员同意(若涉及企业账户);
  • 前端MSAL请求的scope需使用完整格式(如https://graph.microsoft.com/User.Read),避免权限字段解析异常。

3. 校验JWT令牌有效性

用JWT解析工具解码前端传递的access token,确认:

  • scp字段存在且包含User.Read值;
  • aud(受众)字段匹配后端应用注册的客户端ID或API ID,受众不匹配会导致权限解析被跳过。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.11 21:01:02