springboot 2.7 oauth server配置源码走读一

springboot 2.7 oauth server配置源码走读

入口:
在这里插入图片描述
上述截图中的方法签名和OAuth2AuthorizationServerConfiguration类中的一个方法一样,只不过我们自己的配置类优先级比spring中的配置类低,算是配置覆盖,看下图所示:
在这里插入图片描述
它们都提到了 OAuth2AuthorizationServerConfiguration.applyDefaultSecurity(http);
所以我们分析它:
在这里插入图片描述
一. new出来的OAuth2AuthorizationServerConfigurer:
官方声称它是:An AbstractHttpConfigurer for OAuth 2.0 Authorization Server support.(一个用于OAuth 2.0 授权服务器的抽象配置类)。
从源码中可以看到它“管理”着以下具体配置类:
在这里插入图片描述
先给出结论:这些配置类endpoint访问默认值对应如下(如何推导请耐心往下看):
在这里插入图片描述
我们具体看下上述第77行:getRequestMatcher(OAuth2TokenEndpointConfigurer.class).matches(request) 的实现:
我们可以看到第一条绿色下划线:tokenEndpoint的来源,等下我们再去探究它:
在这里插入图片描述
所以我们去AntPathRequestMatcher类 查看实现:
可以看到用到了策略模式:根据pattern (/**表示MATCH_ALL)不同,初始化的matcher也不同:
在这里插入图片描述
接下来我们可以看上述第一条绿色下划线:tokenEndpoint的来源,现在去探究它:

ProviderSettings:它是一个配置类,继承于AbstractSettings(接下来我们自己配置中用到的TokenSettings+ClientSettings类也继承于它),如下所求,我们可以指定token endpoint(当然还有授权,introspection等等),
在这里插入图片描述

如果不指定,则默认配置如下:注意 /oauth2/jwks, 后面resource-server就可以指定它来验证token的有效性。
在这里插入图片描述

那ProvideSettings如何初始化呢?又是和配置类关联起来?
1.构造方法中传递:
在这里插入图片描述
2.在我们的配置类中流入bean(官方示例也是这么做的):
在这里插入图片描述

然后看源码:
在这里插入图片描述

其中providerSettings.getJwkSetEndpoint()我们上面看过,如果没有指定配置,则默认值为:
/oauth2/jwks
在这里插入图片描述
二. 我们配置类中的其它配置:
在这里插入图片描述
上述2个配置方法在OAuth2AuthorizationServerConfiguration类中也可以找到类似的方法,如下所示:
在这里插入图片描述
三.最后把完整的oauth2 server配置如下:

package com.jel.tech.auth.config;

import com.nimbusds.jose.jwk.JWKSet;
import com.nimbusds.jose.jwk.RSAKey;
import com.nimbusds.jose.jwk.source.ImmutableJWKSet;
import com.nimbusds.jose.jwk.source.JWKSource;
import com.nimbusds.jose.proc.SecurityContext;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Role;
import org.springframework.core.annotation.Order;
import org.springframework.security.config.Customizer;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.OAuth2AuthorizationServerConfiguration;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.factory.PasswordEncoderFactories;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.oauth2.core.AuthorizationGrantType;
import org.springframework.security.oauth2.core.ClientAuthenticationMethod;
import org.springframework.security.oauth2.core.oidc.OidcScopes;
import org.springframework.security.oauth2.jwt.JwtDecoder;
import org.springframework.security.oauth2.jwt.NimbusJwtDecoder;
import org.springframework.security.oauth2.server.authorization.client.InMemoryRegisteredClientRepository;
import org.springframework.security.oauth2.server.authorization.client.RegisteredClient;
import org.springframework.security.oauth2.server.authorization.client.RegisteredClientRepository;
import org.springframework.security.oauth2.server.authorization.config.ClientSettings;
import org.springframework.security.oauth2.server.authorization.config.ProviderSettings;
import org.springframework.security.oauth2.server.authorization.config.TokenSettings;
import org.springframework.security.provisioning.InMemoryUserDetailsManager;
import org.springframework.security.web.SecurityFilterChain;

import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.NoSuchAlgorithmException;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import java.time.Duration;
import java.util.UUID;

/**
 * @author: jelex.xu
 * @Date: 2024/1/2 18:31
 * @desc:
 **/
@Configuration
public class OAuth2AuthorizeSecurityConfig {

    /**
     * 重写:org.springframework.security.config.annotation.web.configuration.OAuth2AuthorizationServerConfiguration
     *          #authorizationServerSecurityFilterChain(HttpSecurity)
     * @param http
     * @return
     * @throws Exception
     */
    @Bean
    @Order(1)
    public SecurityFilterChain authorizationServerSecurityFilterChain(HttpSecurity http) throws Exception {

        OAuth2AuthorizationServerConfiguration.applyDefaultSecurity(http);
        return http.formLogin(Customizer.withDefaults()).build();
    }

    @Bean
    @Order(2)
    public SecurityFilterChain standardSecurityFilterChain(HttpSecurity http) throws Exception {

        // @formatter:off
        http
                .authorizeHttpRequests(authorize -> authorize
                        .anyRequest().authenticated())
                .formLogin(Customizer.withDefaults());
        // @formatter:on

        return http.build();
    }

    @Bean
    public RegisteredClientRepository registeredClientRepository() {

        RegisteredClient loginClient = RegisteredClient.withId(UUID.randomUUID().toString())
                .clientId("login-client")
                .clientSecret("{noop}openid-connect")
                .clientAuthenticationMethod(ClientAuthenticationMethod.CLIENT_SECRET_BASIC)
                .authorizationGrantType(AuthorizationGrantType.AUTHORIZATION_CODE)
                .authorizationGrantType(AuthorizationGrantType.REFRESH_TOKEN)
                .redirectUri("http://127.0.0.1:8080/login/oauth2/code/login-client")
                .redirectUri("http://127.0.0.1:8080/authorized")
                .scope(OidcScopes.OPENID)
                .scope(OidcScopes.PROFILE)
                .clientSettings(ClientSettings.builder().requireAuthorizationConsent(true).build())
                .build();

        RegisteredClient registeredClient = RegisteredClient.withId(UUID.randomUUID().toString())
                .clientId("messaging-client")
                .clientSecret("{noop}secret")
                .clientAuthenticationMethod(ClientAuthenticationMethod.CLIENT_SECRET_BASIC)
                .authorizationGrantType(AuthorizationGrantType.CLIENT_CREDENTIALS)
                .scope("message:read")
                .scope("message:write")
                // 指定token有效期:token:30分(默认5分钟),refresh_token:1天
                .tokenSettings(TokenSettings.builder()
                        .accessTokenTimeToLive(Duration.ofMinutes(30))
                        .refreshTokenTimeToLive(Duration.ofDays(1))
                        .build())
//                .id("xxx")
                .build();

        return new InMemoryRegisteredClientRepository(loginClient, registeredClient);
    }

    @Bean
    public JWKSource<SecurityContext> jwkSource(KeyPair keyPair) {

        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);
    }

    @Bean
    public JwtDecoder jwtDecoder(KeyPair keyPair) {
        return NimbusJwtDecoder.withPublicKey((RSAPublicKey) keyPair.getPublic()).build();
    }

    @Bean
    public ProviderSettings providerSettings() {
        return ProviderSettings.builder().issuer("http://127.0.0.1:9000").build();
    }

    @Bean
    public UserDetailsService userDetailsService() {

        PasswordEncoder encoder = PasswordEncoderFactories.createDelegatingPasswordEncoder();
        // outputs {bcrypt}$2a$10$dXJ3SW6G7P50lGmMkkmwe.20cQQubK3.HZWzG3YB1tlRy.fqvM/BG
        // remember the password that is printed out and use in the next step
        System.out.println(encoder.encode("password"));

        UserDetails userDetails = User.withUsername("user")
                .username("user")
                .password("{bcrypt}$2a$10$dXJ3SW6G7P50lGmMkkmwe.20cQQubK3.HZWzG3YB1tlRy.fqvM/BG")
                .roles("USER")
                .build();

        return new InMemoryUserDetailsManager(userDetails);
    }

    @Bean
    @Role(BeanDefinition.ROLE_INFRASTRUCTURE)
    KeyPair generateRsaKey() {

        KeyPair keyPair;

        try {
            KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA");
            keyPairGenerator.initialize(2048);
            keyPair = keyPairGenerator.generateKeyPair();
            return keyPair;

        } catch (NoSuchAlgorithmException e) {
            throw new IllegalArgumentException(e);
        }
    }
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/300738.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

[蓝桥 2020]最长递增

最长递增 题目描述 在数列 a1​,a2​,⋯,an​ 中&#xff0c;如果 ai​<ai1​<ai2​<⋯<aj​&#xff0c;则称 ai​ 至 aj​ 为一段递增序列&#xff0c;长度为 j−i1。 定一个数列&#xff0c;请问数列中最长的递增序列有多长。 输入描述 输入的第一行包含一…

day10 用栈实现队列 用队列实现栈

题目1&#xff1a;232 用栈实现队列 题目链接&#xff1a;232 用栈实现队列 题意 用两个栈实现先入先出队列&#xff08;一个入栈&#xff0c;一个出栈&#xff09;&#xff0c;实现如下功能&#xff1a; 1&#xff09;push&#xff1a;将元素x推到队列末尾 2&#xff09;…

【Python学习】Python学习6-循环语句

目录 【Python学习】【Python学习】Python学习6-循环语句 前言for循环for循环示例通过序列索引迭代循环使用 else 语句 while循环while循环示例continue和 break无限循环循环使用 else 语句简单语句组 嵌套循环Python for 循环嵌套语法&#xff1a;Python while 循环嵌套语法&…

关键字:package关键字

在 Java 中&#xff0c;package关键字用于组织和管理类文件。它将类文件分组到不同的包中&#xff0c;以提供更好的代码组织和可读性。 以下是package关键字的用法&#xff1a; 1.package语句&#xff1a;在 Java 源代码的开头使用package关键字来声明当前类所属的包。例如&a…

【pytorch学习】 深度学习 教程 and 实战

pytorch编程实战博主&#xff1a;https://github.com/lucidrains https://github.com/lucidrains/vit-pytorch

有趣的前端知识(一)

推荐阅读 智能化校园&#xff1a;深入探讨云端管理系统设计与实现&#xff08;一&#xff09; 智能化校园&#xff1a;深入探讨云端管理系统设计与实现&#xff08;二&#xff09; 文章目录 推荐阅读HTML简介基础声明HTML标签标题段落注释水平线文本格式化标签超链接图像<i…

CSS 彩虹按钮效果

<template><view class"content"><button class"btn">彩虹按钮</button></view> </template><script></script><style>body{background-color: #000;}.content {margin-top: 300px;}.btn {width: 1…

python中的异常处理

目录 一&#xff1a;处理机制 二&#xff1a;实例 一&#xff1a;处理机制 Python中的异常处理主要通过try/except语句实现。try语句块包含可能会引发异常的代码&#xff0c;而except语句块包含在try块中发生异常时要执行的代码。此外&#xff0c;Python还提供了一个finally语…

强化学习1——多臂老虎机(上)

在强化学习中&#xff0c;关注智能体在与环境的交互中学习&#xff0c;成为试错型学习。多臂老虎机不存在状态信息&#xff0c;只有动作和奖励&#xff0c;是最简单的“和环境交互中学习“。 什么是多臂老虎机 老虎机_百度百科 (baidu.com) 多臂老虎机即有多个摇杆的老虎机&a…

原子性、CAS操作

Java中的原子性操作 所谓原子性操作&#xff0c;是指执行一系列操作时&#xff0c;这些操作要么全部执行&#xff0c;要么全部不执行&#xff0c;不存在只执行其中一部分的情况。 在设计计数器时一般都先读取当前值&#xff0c;然后1,再更新。 这个过程是读—改—写的过程&a…

Java学习苦旅(二十二)——MapSet

本篇博客将详细讲解Map和Set。 文章目录 搜索概念模型 MapMap.Entry<K, V>Map的常用方法说明TreeMap和HashMap的区别 Set常用方法说明TreeSet和HashSet的区别 结尾 搜索 概念 Map和set是一种专门用来进行搜索的容器或者数据结构&#xff0c;其搜索的效率与其具体的实例…

记一个React组件入参不当导致页面卡死的问题

一、问题描述 1.1 触发现象 点击按钮后页面卡死 1.2 最小 Demo CodeSandBox&#xff1a;https://codesandbox.io/p/sandbox/react-hook-component-stuck-755wcyinscode&#xff1a;https://inscode.csdn.net/ import ./App.css; import React, { useState, useEffect } f…

GPT实战系列-简单聊聊LangChain

GPT实战系列-简单聊聊LangChain LLM大模型相关文章&#xff1a; GPT实战系列-ChatGLM3本地部署CUDA111080Ti显卡24G实战方案 GPT实战系列-Baichuan2本地化部署实战方案 GPT实战系列-大话LLM大模型训练 GPT实战系列-探究GPT等大模型的文本生成 GPT实战系列-Baichuan2等大模…

docker的基础知识

介绍docker 什么是docker Docker是一种开源的容器化平台&#xff0c;可以让开发人员将应用程序与其依赖的运行时环境一起打包到一个称为容器的独立单元中。这个容器可以在任何支持Docker的机器上运行&#xff0c;提供了一种快速和可移植的方式来部署应用程序。Docker的核心组件…

嵌入式(六)模数转换ADC | ADC 工作模式 寄存器 轮询和中断方式

文章目录 1 CC2530的ADC模块2 ADC工作模式3 ADC相关寄存器3.1数据寄存器3.2 控制寄存器 4 ADC初始化配置5 ADC使用方式5.1 轮询方式5.2 中断方式 模拟/数字转换 (Analog to Digital Converter&#xff0c;简称ADC) 是将输入的模拟信号转换为数字信号。 各种被测控的物理量&…

GeoServer发布地图服务(WMS、WFS)

文章目录 1. 概述2. 矢量数据源3. 栅格数据源 1. 概述 我们知道将GIS数据大致分成矢量数据和栅格数据&#xff08;地形和三维模型都是兼具矢量和栅格数据的特性&#xff09;。但是如果用来Web环境中&#xff0c;那么使用图片这个栅格形式的数据载体无疑是最为方便的&#xff0…

实战Flink Java api消费kafka实时数据落盘HDFS

文章目录 1 需求分析2 实验过程2.1 启动服务程序2.2 启动kafka生产 3 Java API 开发3.1 依赖3.2 代码部分 4 实验验证STEP1STEP2STEP3 5 时间窗口 1 需求分析 在Java api中&#xff0c;使用flink本地模式&#xff0c;消费kafka主题&#xff0c;并直接将数据存入hdfs中。 flin…

VQ-VAE(Neural Discrete Representation Learning)论文解读及实现

pytorch 实现git地址 论文地址&#xff1a;Neural Discrete Representation Learning 1 论文核心知识点 encoder 将图片通过encoder得到图片点表征 如输入shape [32,3,32,32] 通过encoder后输出 [32,64,8,8] (其中64位输出维度) 量化码本 先随机构建一个码本&#xff0c;维度…

三大主要排序方法总结:快速排序,选择排序,冒泡排序

本文介绍&#xff1a;三大排序方法&#xff08;快速排序&#xff0c;选择排序&#xff0c;冒泡排序&#xff09;&#xff08;后续期间可能会发布一篇关于qsort函数的文章&#xff09; 自我介绍&#xff1a;一个脑子不好的大一学生&#xff0c;c语言接触还没到半年&#xff0c;…

Spring面试篇

Spring面试篇 前置知识ApplicationContextInitializerApplicationListenerBeanFactoryBeanDefinitionBeanFactoryPostProcesssorAwareInitialzingBean&#xff0c;DisposableBeanBeanPostProcessor SpringBoot启动流程IOC容器初始化流程Bean生命周期Bean循环依赖解决 SpringMvc…