使用token调用Spring OAuth2 Resource Server接口错误 insufficient_scope

1、场景

最近照着《Spring Security实战》学习,学到第18章,使用Keycloak作为授权服务器,使用

org.springframework.boot:spring-boot-starter-oauth2-resource-server

 实现资源服务器,调用资源服务器的接口返回403,具体错误信息如下:

WWW-Authenticate: Bearer error="insufficient_scope", error_description="The request requires higher privileges than provided by the access token.", error_uri="https://tools.ietf.org/html/rfc6750#section-3.1"

 那就检查scope吧

2、检查scope

2.1 查看access_token(JWK)

到这个网址查看明文的令牌:JSON Web Tokens - jwt.io

看看 scope 都有哪些值。

2.2 资源服务配置

    @Bean
    public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
        http
                .authorizeHttpRequests(authorize -> authorize
//                        .requestMatchers(HttpMethod.POST, "/workout/").hasAuthority("SCOPE_fitnessapp")
                        .requestMatchers(HttpMethod.POST, "/workout/").access(hasScope("fitnessapp"))
                        .requestMatchers(HttpMethod.DELETE, "/**").hasAuthority("fitnessadmin")
                                .anyRequest().authenticated()
                )
                .oauth2ResourceServer(oauth2 -> oauth2
                        .jwt(Customizer.withDefaults())
                );
        return http.build();
    }

上一步看到 scope 包含 fitnessapp,那就设置 

access(hasScope("fitnessapp"))

注:实际上资源服务器不设置 scope 也是可以的,因为根本原因不在 scope!!!

3、根本原因以及解决办法

3.1 开启 Spring Security 的日志

在 application.yml 添加配置:

logging:
  level:
    org.springframework.security: DEBUG 

再次调用接口,发现这样一段信息:

ExpressionAuthorizationDecision [granted=false, expressionAttribute=#workout.user == authentication.name] 

出问题的代码就是下面这个方法:

@PreAuthorize("#workout.user == authentication.name")
public void saveWorkout(Workout workout) {
    workoutRepository.save(workout);
}

于是打印看认证后获取的用户名

String name = SecurityContextHolder.getContext().getAuthentication().getName();
System.out.println("###  authentication.name=" + name);

 果然,name不是预期的用户名,而是一段UUID字符串,问DeepSeek这是怎么回事,接着再细看JWK的明文,name 就是token中的 sub 字段的值。

3.2 解决办法

登录Keycloak控制台添加映射器,Client scopes -> fitnessapp -> Mappers

 

 

 

然后重新获取token,看看 sub 字段的值是不是对应的用户名,是的话就没问题了。

最后使用新的token重新调用资源服务器接口,返回200,调用成功!

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值