springBoot从2.x升级到3.x后Oauth 客户端模式兼容以前代码处理

原springboot使用的spring-security-oauth2

部分代码如下

@Configuration
@EnableWebSecurity
public class SpringSecurityConfig extends WebSecurityConfigurerAdapter {

    @Resource
    private UserDetailsService userDetailsService; //
    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        // 读取用户信息进行认证
        auth.userDetailsService(userDetailsService);
    }

    // password 模式需要此 bean
    @Bean
    @Override
    public AuthenticationManager authenticationManagerBean() throws Exception {
        return super.authenticationManagerBean();
    }
    //关闭 csrf 攻击
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.csrf().disable();
    }
}
@Configuration
// 开启了认证服务器
@EnableAuthorizationServer
public class AuthorizationServerConfig extends AuthorizationServerConfigurerAdapter {
    @Resource // 1. 数据源
    private DataSource dataSource;

    @Bean // 1. 客户端使用 jdbc 管理
    public ClientDetailsService jdbcClientDetailsService() {
        return new JdbcClientDetailsService(dataSource);
    }
    /**
     * 1. 配置被允许访问此认证服务器的客户端信息: 数据库方式
     * 如:门户客户端,后台客户端
     */
    @Override
    public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
        // jdbc 管理客户端
        clients.withClientDetails(jdbcClientDetailsService());
    }

    // 2. 在 SpringSecurityConfig 中添加到容器了, 密码模式需要
    @Resource
    private AuthenticationManager authenticationManager;
    // 不驗證登錄密碼
    @Resource
    private UserDetailsService userDetailsService;
    // token管理方式,引用 JwtTokenStoreConfig 配置的
    @Resource
    private TokenStore tokenStore;
    // jwt 转换器
    @Resource
    private JwtAccessTokenConverter jwtAccessTokenConverter;
    // 注入增强器
    @Resource
    private TokenEnhancer jwtTokenEnhancer;
    /**
     * 关于认证服务器端点配置
     * @param endpoints
     * @throws Exception
     */
    @Override
    public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {

        // 密码模块必须使用这个authenticationManager实例
        endpoints.authenticationManager(authenticationManager);
        // 刷新令牌需要 使用userDetailsService,不刷新令牌
        endpoints.userDetailsService(userDetailsService);
        // 令牌管理方式
        endpoints.tokenStore(tokenStore).accessTokenConverter(jwtAccessTokenConverter);

        // 添加增强器
        TokenEnhancerChain enhancerChain = new TokenEnhancerChain();
        // 组合 增强器和jwt转换器
        List<TokenEnhancer> enhancerList = new ArrayList<>();
        enhancerList.add(jwtTokenEnhancer);
        enhancerList.add(jwtAccessTokenConverter);
        enhancerChain.setTokenEnhancers(enhancerList);
        // 将认证信息的增强器添加到端点上
        endpoints.tokenEnhancer(enhancerChain).accessTokenConverter(jwtAccessTokenConverter);
        endpoints.pathMapping("/oauth/token", "/access-token");
    }
    @Override
    public void configure(AuthorizationServerSecurityConfigurer security) {
        // /oauth/check_token 解析令牌,默认情况 下拒绝访问
        security.checkTokenAccess("permitAll()");
//         .checkTokenAccess("isAuthenticated()");
    }
}

依赖如下

<dependency>
   <groupId>org.springframework.security.oauth</groupId>
   <artifactId>spring-security-oauth2</artifactId>
   <version>${spring.security.oauth.version}</version>
</dependency>

升级为springboot3后已经无法使用spring-security-oauth2,需要使用

spring-boot-starter-oauth2-authorization-server

依赖如下

<dependency>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-starter-oauth2-authorization-server</artifactId>
	<version>3.2.3</version>
</dependency>

主要代码如下

@Configuration
public class AuthorizationServerConfig {

    /**
     * 授权服务器 SecurityFilterChain
     */
    @Bean
    @Order(Ordered.HIGHEST_PRECEDENCE)
    public SecurityFilterChain authorizationServerSecurityFilterChain(HttpSecurity http)
            throws Exception {
        OAuth2AuthorizationServerConfiguration.applyDefaultSecurity(http);
        http.getConfigurer(OAuth2AuthorizationServerConfigurer.class)
                .oidc(Customizer.withDefaults());    // Enable OpenID Connect 1.0
        http
                // Redirect to the login page when not authenticated from the
                // authorization endpoint
                .exceptionHandling((exceptions) -> exceptions
                        .authenticationEntryPoint(
                                new LoginUrlAuthenticationEntryPoint("/login"))
                )
                // Accept access tokens for User Info and/or Client Registration
                .oauth2ResourceServer(OAuth2ResourceServerConfigurer::jwt);
        return http.build();
    }
    /**
     * 客户端配置,基于内存
     */
    @Bean
    public RegisteredClientRepository registeredClientRepository(JdbcTemplate jdbcTemplate) {
        BCryptPasswordEncoder passwordEncoder = new BCryptPasswordEncoder();
        CpParticipantEntity cpEntity = ParticipantUtils.getCRPObj();
        String clientId = cpEntity.getClientId();
        String secret = AESCbcUtil.decryptBase64(cpEntity.getClientSecret(), Const.Common.AES_PWD);
        RegisteredClient oidcClient = RegisteredClient.withId(UUID.randomUUID().toString())
                .clientId(clientId)
                .clientName(clientId)
                .clientIdIssuedAt(Instant.now())
                .clientSecret(passwordEncoder.encode(secret))
                .clientSecretExpiresAt(Instant.now().plus(14, ChronoUnit.DAYS))
                .clientAuthenticationMethod(ClientAuthenticationMethod.CLIENT_SECRET_BASIC)
                .clientAuthenticationMethod(ClientAuthenticationMethod.CLIENT_SECRET_POST)
                .authorizationGrantType(AuthorizationGrantType.CLIENT_CREDENTIALS)
                .authorizationGrantType(AuthorizationGrantType.REFRESH_TOKEN)
                .postLogoutRedirectUri("http://127.0.0.1:8081/logout")
                .scope("message.read")
                .clientSettings(ClientSettings.builder().requireAuthorizationConsent(false).build())
                .tokenSettings(TokenSettings.builder()
                        //access token 有效期
                        .accessTokenTimeToLive(Duration.ofMinutes(60))
                        .build())
                .build();

        return new InMemoryRegisteredClientRepository(oidcClient);
        //);
        //return registeredClientRepository;
    }

    /**
     * 默认发放令牌
     *
     * @return
     */
    @Bean
    public JWKSource<SecurityContext> jwkSource() {
        KeyPair keyPair = generateRsaKey();
        RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic();
        RSAPrivateKey privateKey = (RSAPrivateKey) keyPair.getPrivate();
        RSAKey rsaKey = new RSAKey.Builder(publicKey)
                .privateKey(privateKey)
                .keyID(UUID.randomUUID().toString())
                .build();
        JWKSet jwkSet = new JWKSet(rsaKey);
        return new ImmutableJWKSet<>(jwkSet);
    }

    private static KeyPair generateRsaKey() {
        KeyStoreKeyFactory factory = new KeyStoreKeyFactory(new ClassPathResource("hwss.jks"), "123456".toCharArray());
        return factory.getKeyPair("hwss");
        /*KeyPair keyPair;
        try {
            KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA");
            keyPairGenerator.initialize(2048);
            keyPair = keyPairGenerator.generateKeyPair();
        } catch (Exception ex) {
            throw new IllegalStateException(ex);
        }
        return keyPair;*/
    }

    @Bean
    public JwtDecoder jwtDecoder(JWKSource<SecurityContext> jwkSource) {
        return OAuth2AuthorizationServerConfiguration.jwtDecoder(jwkSource);
    }

    @Bean
    public AuthorizationServerSettings authorizationServerSettings() {
        return AuthorizationServerSettings.builder().build();
    }

}
@EnableWebSecurity
@Configuration(proxyBeanMethods = false)
public class DefaultSecurityConfig {
 
    @Bean
    @Order(2)
    public SecurityFilterChain defaultSecurityFilterChain(HttpSecurity http)
            throws Exception {
        http
                .authorizeHttpRequests((authorize) -> authorize
                        .requestMatchers(new AntPathRequestMatcher("/*/**")).permitAll()
                        .anyRequest().authenticated()
                )
                .cors(Customizer.withDefaults())
                .csrf((csrf) -> csrf.disable())
                .formLogin(Customizer.withDefaults())
        ;
 
        return http.build();
    }

    @Bean
    public UserDetailsService userDetailsService() {
        UserDetails userDetails = User.withDefaultPasswordEncoder()
                .username("user")
                .password("password")
                .roles("USER")
                .build();
 
        return new InMemoryUserDetailsManager(userDetails);

    }
 
}

由于以前使用spring-security-oauth2时指定了获取token的访问地址为/access-token

,更新后无法使用该地址进行访问,故添加controller进行转发处理

代码如下

@RequestMapping("/access-token")
    public void  forwardToTargetPage(HttpServletRequest request, HttpServletResponse response) {
        try {
            request.getRequestDispatcher("/oauth2/token").forward(request, response);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

这样就能兼容spring-security-oauth2的相关配置了,注意client_id,clientSecret需要使用以前的配置(目前代码是通过读库处理)

  • 11
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

浮生ソ若梦

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

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

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

打赏作者

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

抵扣说明:

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

余额充值