基于Spring Security 6的OAuth2 系列之十四 - 资源服务器--自定义资源服务器

之所以想写这一系列,是因为之前工作过程中使用Spring Security OAuth2搭建了网关和授权服务器,但当时基于spring-boot 2.3.x,其默认的Spring Security是5.3.x。之后新项目升级到了spring-boot 3.3.0,结果一看Spring Security也升级为6.3.0。无论是Spring Security的风格和以及OAuth2都做了较大改动,里面甚至将授权服务器模块都移除了,导致在配置同样功能时,花费了些时间研究新版本的底层原理,这里将一些学习经验分享给大家。

注意由于框架不同版本改造会有些使用的不同,因此本次系列中使用基本框架是 spring-boo-3.3.0(默认引入的Spring Security是6.3.0),JDK版本使用的是19,本系列OAuth2的代码采用Spring Security6.3.0框架,所有代码都在oauth2-study项目上:https://github.com/forever1986/oauth2-study.git

前面2章我们对资源服务器的基本配置和底层原理做了一个演示和说明,那么资源服务器还有哪些配置,一般资源服务器可能会作为内部网关使用,那么又该如何配置。这一章会讲述自定义资源服务器的配置到一个生产可用的网关配置。

从下图我们可以看到,其资源服务器可以自定义配置,下面就一些常见的配置做一下说明。
在这里插入图片描述

1 自定义异常处理

这里的异常处理其实是使用Spring Security的异常处理,因此只需要实现以下2个不同的处理逻辑即可:

  • AuthenticationEntryPoint:处理认证失败的异常
  • AccessDeniedHandler:处理没有权限或者没有登录的异常

2 自定义JWT

2.1 加载本地jwtdecoder

我们从上一章知道资源服务器会去授权服务器请求得到JWT的公钥,或者配置某一个地方获取公钥。这里还有一种办法,就是本地公钥,可以通过自定义decoder方式,获取本地公钥,这样就可以不依赖其它服务。

代码参考lesson08子模块

1)新建lesson08子模块,复制和lesson07子模块一致

2)在SecurityConfig配置下,配置自己加载本地的公钥

@Configuration
public class SecurityConfig {

    @Bean
    public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
        http
                .authorizeHttpRequests(authorize -> authorize
                        // userInfo接口需要SCOPE_profile权限
                        .requestMatchers("/userInfo").hasAuthority("SCOPE_profile")
                        // 其它访问都需要鉴权
                        .anyRequest().authenticated()
                )
                // 资源服务器默认配置
                .oauth2ResourceServer((oauth2) -> oauth2.jwt(jwt -> jwt
                        // 配置set-uri替换yaml的jwk-set-uri配置
//                        .jwkSetUri("")
                        // 配置自己的decoder,替换从远程获取的公钥
                        .decoder(jwtDecoder())
                ));
        return http.build();
    }

    /**
     * 自定义JwtDecoder
     */
    public JwtDecoder jwtDecoder() {
        return NimbusJwtDecoder.withPublicKey(generateRsaKey()).build();
    }


    /**
     * 其 key 在启动时生成,用于创建上述 JWKSource
     */
    private static RSAPublicKey generateRsaKey() {
        KeyStoreKeyFactory factory = new KeyStoreKeyFactory(new ClassPathResource("demo.jks"), "linmoo".toCharArray());
        KeyPair keyPair = factory.getKeyPair("demo", "linmoo".toCharArray());
        RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic();
        return publicKey;
    }
}

3)把lesson05子模块resources下面的demo.jks复制到lesson08子模块

4)测试方式和开篇中的《系列之十二 - 资源服务器–开篇中 3 自定义获取Jwks信息》一样

2.2 自定义AuthenticationConverter

JwtAuthenticationProvider中,有一个功能就是通过JwtAuthenticationConverter
将JWT的token转换为AbstractAuthenticationToken,而这个AbstractAuthenticationToken里面存储了用户的信息,包括权限scopes,可供下游使用。

在这里插入图片描述

在官方网站说可以通过重新实现JwtAuthenticationConverter,如下图,这里就不演示了,因为一般情况下,我们权限管理不会采用Spring Security这一套。

在这里插入图片描述

2.3 自定义OAuth2TokenValidator

我们在JwtAuthenticationProvider中还看到一个OAuth2TokenValidator,其作用就是用于对JWT的token进行格外验证,默认会设置JwtIssuerValidatorX509CertificateThumbprintValidator的验证
在这里插入图片描述

如果你想自定义,你可以在定义时,设置自己想要的自定义,比如下面的例子就是设置JwtTimestampValidatorJwtIssuerValidator

/**
     * 自定义JwtDecoder
 */
public JwtDecoder jwtDecoder() {
    NimbusJwtDecoder jwtDecoder = NimbusJwtDecoder.withPublicKey(generateRsaKey()).build();
    OAuth2TokenValidator<Jwt> withClockSkew = new DelegatingOAuth2TokenValidator<>(
            new JwtTimestampValidator(Duration.ofSeconds(60)),
            new JwtIssuerValidator(issuerUri));
    jwtDecoder.setJwtValidator(withClockSkew);
    return jwtDecoder;
}

结语:目前我们对客户端、授权服务器以及资源服务器都做了从配置到底层原理的讲解,相信学到此处的朋友已经能够很好地掌握。接下来还有几章的内容是关于高级功能(涉及OAuth2.1等)和真实案例应用的,这样能让我们学以致用。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

linmoo1986

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值