oauth2-authorization-server;oauth2-resource-server;oauth2-client

spring-security-oauth2-authorization-server

  1. 依赖项
    <?xml version="1.0" encoding="UTF-8"?>
    <project xmlns="http://maven.apache.org/POM/4.0.0"
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
        <parent>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-parent</artifactId>
            <version>2.5.12</version>
            <relativePath/>
        </parent>
        <modelVersion>4.0.0</modelVersion>
    
        <groupId>test</groupId>
        <artifactId>default-authorizationserver</artifactId>
    
        <dependencies>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-web</artifactId>
            </dependency>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-security</artifactId>
            </dependency>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-jdbc</artifactId>
            </dependency>
            <dependency>
                <groupId>org.springframework.security</groupId>
                <artifactId>spring-security-oauth2-authorization-server</artifactId>
                <version>0.2.3</version>
            </dependency>
            <dependency>
                <groupId>com.h2database</groupId>
                <artifactId>h2</artifactId>
                <version>2.1.212</version>
            </dependency>
        </dependencies>
    </project>
  2. 核心代码
    package sample.config;
    
    import org.springframework.context.annotation.Bean;
    import org.springframework.security.config.Customizer;
    import org.springframework.security.config.annotation.web.builders.HttpSecurity;
    import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
    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.bcrypt.BCryptPasswordEncoder;
    import org.springframework.security.crypto.password.PasswordEncoder;
    import org.springframework.security.provisioning.InMemoryUserDetailsManager;
    import org.springframework.security.web.SecurityFilterChain;
    
    /**
    * Security配置
    */
    @EnableWebSecurity
    public class DefaultSecurityConfig {
    
        @Bean
        SecurityFilterChain defaultSecurityFilterChain(HttpSecurity http) throws Exception {
            http
                    .authorizeRequests(authorizeRequests ->
                            authorizeRequests.anyRequest().authenticated()
                    )
                    .formLogin(Customizer.withDefaults());
            return http.build();
        }
    
        @Bean
        UserDetailsService users() {
            UserDetails user = User.withUsername("user")
                    .password(passwordEncoder().encode("password"))
                    .roles("USER")
                    .build();
            return new InMemoryUserDetailsManager(user);
        }
    
        @Bean
        public PasswordEncoder passwordEncoder() {
            return new BCryptPasswordEncoder();
        }
    
    }
    
    package sample.config;
    
    import com.nimbusds.jose.jwk.JWKSet;
    import com.nimbusds.jose.jwk.RSAKey;
    import com.nimbusds.jose.jwk.source.JWKSource;
    import com.nimbusds.jose.proc.SecurityContext;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.core.Ordered;
    import org.springframework.core.annotation.Order;
    import org.springframework.jdbc.core.JdbcTemplate;
    import org.springframework.jdbc.datasource.embedded.EmbeddedDatabase;
    import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseBuilder;
    import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseType;
    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.crypto.bcrypt.BCryptPasswordEncoder;
    import org.springframework.security.crypto.password.NoOpPasswordEncoder;
    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.server.authorization.JdbcOAuth2AuthorizationConsentService;
    import org.springframework.security.oauth2.server.authorization.JdbcOAuth2AuthorizationService;
    import org.springframework.security.oauth2.server.authorization.OAuth2AuthorizationConsentService;
    import org.springframework.security.oauth2.server.authorization.OAuth2AuthorizationService;
    import org.springframework.security.oauth2.server.authorization.client.JdbcRegisteredClientRepository;
    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.web.SecurityFilterChain;
    import sample.jose.Jwks;
    
    import java.util.UUID;
    
    /**
    * 认证客户端配置
    */
    @Configuration(proxyBeanMethods = false)
    public class AuthorizationServerConfig {
    
    //自定义用户授权页面
    	/*private static final String CUSTOM_CONSENT_PAGE_URI = "/oauth2/consent";
    
    	@Bean
    	@Order(Ordered.HIGHEST_PRECEDENCE)
    	public SecurityFilterChain authorizationServerSecurityFilterChain(HttpSecurity http) throws Exception {
    		OAuth2AuthorizationServerConfigurer<HttpSecurity> authorizationServerConfigurer =
    				new OAuth2AuthorizationServerConfigurer<>();
    		//自定义用户授权页面
    		authorizationServerConfigurer
    				.authorizationEndpoint(authorizationEndpoint ->
    						authorizationEndpoint.consentPage(CUSTOM_CONSENT_PAGE_URI));
    
    		RequestMatcher endpointsMatcher = authorizationServerConfigurer
    				.getEndpointsMatcher();
    
    		http
    			.requestMatcher(endpointsMatcher)
    			.authorizeRequests(authorizeRequests ->
    				authorizeRequests.anyRequest().authenticated()
    			)
    			.csrf(csrf -> csrf.ignoringRequestMatchers(endpointsMatcher))
    			.apply(authorizationServerConfigurer);
    		return http.formLogin(Customizer.withDefaults()).build();
    	}*/
    
        @Autowired
        private PasswordEncoder passwordEncoder;
    
        @Bean
        @Order(Ordered.HIGHEST_PRECEDENCE)
        public SecurityFilterChain authenticationServerSecurityFilterChain(HttpSecurity http) throws Exception {
            OAuth2AuthorizationServerConfiguration.applyDefaultSecurity(http);
            return http.formLogin(Customizer.withDefaults()).build();
        }
    
        /*
        获取code
        http://localhost:9000/oauth2/authorize?response_type=code&client_id=messaging-client&scope=message.read&redirect_uri=https://baidu.com
        获取token
        post请求: localhost:9000/oauth2/token
        Authorization头:   Basic Auth Username=client_id; Password=client_secret
        Body form-data参数: grant_type=authorization_code; redirect_uri=https://baidu.com; code=
         */
        @Bean
        public RegisteredClientRepository registeredClientRepository(JdbcTemplate jdbcTemplate) {
            RegisteredClient registeredClient = RegisteredClient.withId(UUID.randomUUID().toString())
                    .clientId("messaging-client")
                    .clientSecret(passwordEncoder.encode("secret"))
                    .clientAuthenticationMethod(ClientAuthenticationMethod.CLIENT_SECRET_BASIC)
                    .authorizationGrantType(AuthorizationGrantType.AUTHORIZATION_CODE)
                    .authorizationGrantType(AuthorizationGrantType.REFRESH_TOKEN)
                    .authorizationGrantType(AuthorizationGrantType.CLIENT_CREDENTIALS)
                    .redirectUri("http://127.0.0.1:8080/login/oauth2/code/messaging-client-oidc")
                    .redirectUri("http://127.0.0.1:8080/authorized")
                    .scope(OidcScopes.OPENID)
                    .scope("message.read")
                    .scope("message.write")
                    .clientSettings(ClientSettings.builder().requireAuthorizationConsent(true).build())
                    .build();
            JdbcRegisteredClientRepository registeredClientRepository = new JdbcRegisteredClientRepository(jdbcTemplate);
            registeredClientRepository.save(registeredClient);
            return registeredClientRepository;
        }
    
    
        @Bean
        public OAuth2AuthorizationService authorizationService(JdbcTemplate jdbcTemplate, RegisteredClientRepository registeredClientRepository) {
            return new JdbcOAuth2AuthorizationService(jdbcTemplate, registeredClientRepository);
        }
    
        @Bean
        public OAuth2AuthorizationConsentService authorizationConsentService(JdbcTemplate jdbcTemplate, RegisteredClientRepository registeredClientRepository) {
            return new JdbcOAuth2AuthorizationConsentService(jdbcTemplate, registeredClientRepository);
        }
    
        @Bean
        public JWKSource<SecurityContext> jwkSource() {
            RSAKey rsaKey = Jwks.generateRsa();
            JWKSet jwkSet = new JWKSet(rsaKey);
            return (jwkSelector, securityContext) -> jwkSelector.select(jwkSet);
        }
    
        public static void main(String[] args) {
            BCryptPasswordEncoder passwordEncoder = new BCryptPasswordEncoder();
            System.err.println(passwordEncoder.encode("secret"));
        }
    
        @Bean
        public ProviderSettings providerSettings() {
            return ProviderSettings.builder().issuer("http://localhost:9000").build();
        }
    
        @Bean
        public EmbeddedDatabase embeddedDatabase() {
            return new EmbeddedDatabaseBuilder()
                    .generateUniqueName(true)
                    .setType(EmbeddedDatabaseType.H2)
                    .setScriptEncoding("UTF-8")
                    .addScript("org/springframework/security/oauth2/server/authorization/oauth2-authorization-schema.sql")
                    .addScript("org/springframework/security/oauth2/server/authorization/oauth2-authorization-consent-schema.sql")
                    .addScript("org/springframework/security/oauth2/server/authorization/client/oauth2-registered-client-schema.sql")
                    .build();
        }
    }
    
    package sample.jose;
    
    import com.nimbusds.jose.jwk.Curve;
    import com.nimbusds.jose.jwk.ECKey;
    import com.nimbusds.jose.jwk.OctetSequenceKey;
    import com.nimbusds.jose.jwk.RSAKey;
    
    import javax.crypto.SecretKey;
    import java.security.KeyPair;
    import java.security.interfaces.RSAPublicKey;
    import java.security.interfaces.RSAPrivateKey;
    import java.security.interfaces.ECPublicKey;
    import java.security.interfaces.ECPrivateKey;
    import java.util.UUID;
    
    /**
    * jwk配置
    */
    public final class Jwks {
    
        private Jwks() {
    
        }
    
        public static RSAKey generateRsa() {
            KeyPair keyPair = KeyGeneratorUtils.generateRsaKey();
            RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic();
            RSAPrivateKey privateKey = (RSAPrivateKey) keyPair.getPrivate();
            return new RSAKey.Builder(publicKey)
                    .privateKey(privateKey)
                    .keyID(UUID.randomUUID().toString())
                    .build();
        }
    
        public static ECKey generateEc() {
            KeyPair keyPair = KeyGeneratorUtils.generateEcKey();
            ECPublicKey publicKey = (ECPublicKey) keyPair.getPublic();
            ECPrivateKey privateKey = (ECPrivateKey) keyPair.getPrivate();
            Curve curve = Curve.forECParameterSpec(publicKey.getParams());
            return new com.nimbusds.jose.jwk.ECKey.Builder(curve, publicKey)
                    .privateKey(privateKey)
                    .keyID(UUID.randomUUID().toString())
                    .build();
        }
    
        public static OctetSequenceKey generateSecret() {
            SecretKey secretKey = KeyGeneratorUtils.generateSecretKey();
            return new OctetSequenceKey.Builder(secretKey)
                    .keyID(UUID.randomUUID().toString())
                    .build();
        }
    }
    
    package sample.jose;
    
    import javax.crypto.KeyGenerator;
    import javax.crypto.SecretKey;
    import java.math.BigInteger;
    import java.security.KeyPair;
    import java.security.KeyPairGenerator;
    import java.security.spec.ECFieldFp;
    import java.security.spec.ECParameterSpec;
    import java.security.spec.ECPoint;
    import java.security.spec.EllipticCurve;
    
    /**
    * 生成key
    */
    final class KeyGeneratorUtils {
    
        private KeyGeneratorUtils() {
    
        }
    
        static SecretKey generateSecretKey() {
            SecretKey hmacKey;
            try {
                hmacKey = KeyGenerator.getInstance("HmacSha256").generateKey();
            } catch (Exception ex) {
                throw new IllegalStateException(ex);
            }
            return hmacKey;
        }
    
        static KeyPair generateRsaKey() {
            KeyPair keyPair;
            try {
                KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA");
                keyPairGenerator.initialize(2048);
                keyPair = keyPairGenerator.generateKeyPair();
            } catch (Exception ex) {
                throw new IllegalStateException(ex);
            }
            return keyPair;
        }
    
        static KeyPair generateEcKey() {
            EllipticCurve ellipticCurve = new EllipticCurve(
                    new ECFieldFp(
                            new BigInteger("115792089210356248762697446949407573530086143415290314195533631308867097853951")),
                    new BigInteger("115792089210356248762697446949407573530086143415290314195533631308867097853948"),
                    new BigInteger("41058363725152142129326129780047268409114441015993725554835256314039467401291"));
            ECPoint ecPoint = new ECPoint(
                    new BigInteger("48439561293906451759052585252797914202762949526041747995844080717082404635286"),
                    new BigInteger("36134250956749795798585127919587881956611106672985015071877198253568414405109"));
            ECParameterSpec ecParameterSpec = new ECParameterSpec(
                    ellipticCurve,
                    ecPoint,
                    new BigInteger("115792089210356248762697446949407573529996955224135760342422259061068512044369"),
                    1);
            KeyPair keyPair;
            try {
                KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("EC");
                keyPairGenerator.initialize(ecParameterSpec);
                keyPair = keyPairGenerator.generateKeyPair();
            } catch (Exception e) {
                throw new IllegalStateException(e);
            }
            return keyPair;
        }
    
    }
    
  3. 配置文件
    server:
      port: 9000
    
    logging:
      level:
        root: INFO
        org.springframework.web: INFO
        org.springframework.security: INFO
        org.springframework.security.oauth2: INFO
  4. sql
CREATE TABLE oauth2_registered_client (
    id varchar(100) NOT NULL,
    client_id varchar(100) NOT NULL,
    client_id_issued_at timestamp DEFAULT CURRENT_TIMESTAMP NOT NULL,
    client_secret varchar(200) DEFAULT NULL,
    client_secret_expires_at timestamp DEFAULT NULL,
    client_name varchar(200) NOT NULL,
    client_authentication_methods varchar(1000) NOT NULL,
    authorization_grant_types varchar(1000) NOT NULL,
    redirect_uris varchar(1000) DEFAULT NULL,
    scopes varchar(1000) NOT NULL,
    client_settings varchar(2000) NOT NULL,
    token_settings varchar(2000) NOT NULL,
    PRIMARY KEY (id)
);
CREATE TABLE oauth2_authorization_consent (
    registered_client_id varchar(100) NOT NULL,
    principal_name varchar(200) NOT NULL,
    authorities varchar(1000) NOT NULL,
    PRIMARY KEY (registered_client_id, principal_name)
);
/*
IMPORTANT:
    If using PostgreSQL, update ALL columns defined with 'blob' to 'text',
    as PostgreSQL does not support the 'blob' data type.
*/
CREATE TABLE oauth2_authorization (
    id varchar(100) NOT NULL,
    registered_client_id varchar(100) NOT NULL,
    principal_name varchar(200) NOT NULL,
    authorization_grant_type varchar(100) NOT NULL,
    attributes blob DEFAULT NULL,
    state varchar(500) DEFAULT NULL,
    authorization_code_value blob DEFAULT NULL,
    authorization_code_issued_at timestamp DEFAULT NULL,
    authorization_code_expires_at timestamp DEFAULT NULL,
    authorization_code_metadata blob DEFAULT NULL,
    access_token_value blob DEFAULT NULL,
    access_token_issued_at timestamp DEFAULT NULL,
    access_token_expires_at timestamp DEFAULT NULL,
    access_token_metadata blob DEFAULT NULL,
    access_token_type varchar(100) DEFAULT NULL,
    access_token_scopes varchar(1000) DEFAULT NULL,
    oidc_id_token_value blob DEFAULT NULL,
    oidc_id_token_issued_at timestamp DEFAULT NULL,
    oidc_id_token_expires_at timestamp DEFAULT NULL,
    oidc_id_token_metadata blob DEFAULT NULL,
    refresh_token_value blob DEFAULT NULL,
    refresh_token_issued_at timestamp DEFAULT NULL,
    refresh_token_expires_at timestamp DEFAULT NULL,
    refresh_token_metadata blob DEFAULT NULL,
    PRIMARY KEY (id)
);

oauth2-resource-server的

  1. 依赖项
    <?xml version="1.0" encoding="UTF-8"?>
    <project xmlns="http://maven.apache.org/POM/4.0.0"
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
        <parent>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-parent</artifactId>
            <version>2.5.12</version>
            <relativePath/>
        </parent>
        <modelVersion>4.0.0</modelVersion>
    
        <groupId>test.oauth</groupId>
        <artifactId>com.oauth2.resource</artifactId>
    
        <dependencies>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-web</artifactId>
            </dependency>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-oauth2-resource-server</artifactId>
            </dependency>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-security</artifactId>
            </dependency>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-oauth2-resource-server</artifactId>
            </dependency>
        </dependencies>
    
    </project>
  2. 核心代码
    package sample.config;
    
    import org.springframework.context.annotation.Bean;
    import org.springframework.security.config.annotation.web.builders.HttpSecurity;
    import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
    import org.springframework.security.web.SecurityFilterChain;
    /**
    * resource配置安全链
    */
    @EnableWebSecurity
    public class ResourceServerConfig {
        @Bean
        SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
            http.mvcMatcher("/messages/**")
                    .authorizeRequests()
                    .mvcMatchers("/messages/**")
                    .access("hasAuthority('SCOPE_message.read')")
                    .and()
                    .oauth2ResourceServer()
                    .jwt();
            return http.build();
        }
    
    }
    
    /*
     * Copyright 2020 the original author or authors.
     *
     * Licensed under the Apache License, Version 2.0 (the "License");
     * you may not use this file except in compliance with the License.
     * You may obtain a copy of the License at
     *
     *      https://www.apache.org/licenses/LICENSE-2.0
     *
     * Unless required by applicable law or agreed to in writing, software
     * distributed under the License is distributed on an "AS IS" BASIS,
     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     * See the License for the specific language governing permissions and
     * limitations under the License.
     */
    package sample.web;
    
    import org.springframework.web.bind.annotation.GetMapping;
    import org.springframework.web.bind.annotation.RestController;
    
    /**
     * @author Joe Grandja
     * 案例:受保护资源
     * @since 0.0.1
     */
    @RestController
    public class MessagesController {
    
        @GetMapping("/messages")
        public String[] getMessages() {
            return new String[] {"Message 1", "Message 2", "Message 3"};
        }
    }
    
  3. 配置文件
server:
  port: 8090

logging:
  level:
    root: INFO
    org.springframework.web: INFO
    org.springframework.security: INFO
    org.springframework.security.oauth2: INFO
#    org.springframework.boot.autoconfigure: DEBUG

spring:
  security:
    oauth2:
      resourceserver:
        jwt:
          issuer-uri: http://localhost:9000

oauth2-client

  1. 依赖项
    <?xml version="1.0" encoding="UTF-8"?>
    <project xmlns="http://maven.apache.org/POM/4.0.0"
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
        <parent>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-parent</artifactId>
            <version>2.5.12</version>
            <relativePath/>
        </parent>
        <modelVersion>4.0.0</modelVersion>
    
        <groupId>test.oauth</groupId>
        <artifactId>com.oauth2.client</artifactId>
    
        <dependencies>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-web</artifactId>
            </dependency>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-security</artifactId>
            </dependency>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-oauth2-client</artifactId>
            </dependency>
            <dependency>
                <groupId>org.springframework</groupId>
                <artifactId>spring-webflux</artifactId>
                <version>5.2.21.RELEASE</version>
            </dependency>
            <dependency>
                <groupId>io.projectreactor.netty</groupId>
                <artifactId>reactor-netty</artifactId>
                <version>1.0.18</version>
            </dependency>
        </dependencies>
    </project>
  2. 核心代码
    /*
     * Copyright 2020-2021 the original author or authors.
     *
     * Licensed under the Apache License, Version 2.0 (the "License");
     * you may not use this file except in compliance with the License.
     * You may obtain a copy of the License at
     *
     *      https://www.apache.org/licenses/LICENSE-2.0
     *
     * Unless required by applicable law or agreed to in writing, software
     * distributed under the License is distributed on an "AS IS" BASIS,
     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     * See the License for the specific language governing permissions and
     * limitations under the License.
     */
    package sample.config;
    
    import org.springframework.context.annotation.Bean;
    import org.springframework.security.config.annotation.web.builders.HttpSecurity;
    import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
    import org.springframework.security.config.annotation.web.configuration.WebSecurityCustomizer;
    import org.springframework.security.web.SecurityFilterChain;
    
    import static org.springframework.security.config.Customizer.withDefaults;
    
    /**
     * @author Joe Grandja
     * 配置oauth2 client
     * @since 0.0.1
     */
    @EnableWebSecurity
    public class SecurityConfig {
    
        /*
         * OAuth2AuthorizationRequestRedirectFilter:
         * 		处理 /oauth2/authorization 路径,主要场景是默认或手动配置的 oauth2login 路径,它会将上述路径处理转发给 认证中心 对应的路径 /oauth2/authorize
         * OAuth2AuthorizationCodeGrantFilter:
         * 		该过滤器负责处理认证中心的授权码回调请求,主要场景就是认证中心生成授权码后的回调请求这里会进行诸如回调地址重定向、OAuth2AuthorizedClient 的创建等处理
         * OAuth2LoginAuthenticationFilter:
         *		处理 /login/oauth2/code/* 路径,默认的授权码回调路径,此过滤器会向认证中心请求对应的 Token 信息
         */
        @Bean
        WebSecurityCustomizer webSecurityCustomizer() {
            return (web) -> web.ignoring().antMatchers("/webjars/**");
        }
    
        /*
         *  SecurityFilterChain 是 Spring Security 本身的组件
         *  此处是 Spring Boot 自动装配类提供的默认实例,其中
         *  oauth2Login 是开启 oauth2Login 模式
         *  oauth2Client 声明为 OAuth2 Client,引入对应组件
         * */
        @Bean
        SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
            http
                    .authorizeRequests(authorizeRequests ->
                            authorizeRequests.anyRequest().authenticated()
                    )
                    .oauth2Login(oauth2Login ->
                            oauth2Login.loginPage("/oauth2/authorization/messaging-client-oidc"))
                    .oauth2Client(withDefaults());
            return http.build();
        }
    }
    
    /*
     * Copyright 2020 the original author or authors.
     *
     * Licensed under the Apache License, Version 2.0 (the "License");
     * you may not use this file except in compliance with the License.
     * You may obtain a copy of the License at
     *
     *      https://www.apache.org/licenses/LICENSE-2.0
     *
     * Unless required by applicable law or agreed to in writing, software
     * distributed under the License is distributed on an "AS IS" BASIS,
     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     * See the License for the specific language governing permissions and
     * limitations under the License.
     */
    package sample.config;
    
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.security.oauth2.client.OAuth2AuthorizedClientManager;
    import org.springframework.security.oauth2.client.OAuth2AuthorizedClientProvider;
    import org.springframework.security.oauth2.client.OAuth2AuthorizedClientProviderBuilder;
    import org.springframework.security.oauth2.client.registration.ClientRegistrationRepository;
    import org.springframework.security.oauth2.client.web.DefaultOAuth2AuthorizedClientManager;
    import org.springframework.security.oauth2.client.web.OAuth2AuthorizedClientRepository;
    import org.springframework.security.oauth2.client.web.reactive.function.client.ServletOAuth2AuthorizedClientExchangeFilterFunction;
    import org.springframework.web.reactive.function.client.WebClient;
    
    /**
     * @author Joe Grandja
     * 配置webClient 请求携带token
     * @since 0.0.1
     */
    @Configuration
    public class WebClientConfig {
    
    	@Bean
    	WebClient webClient(OAuth2AuthorizedClientManager authorizedClientManager) {
    		ServletOAuth2AuthorizedClientExchangeFilterFunction oauth2Client =
    				new ServletOAuth2AuthorizedClientExchangeFilterFunction(authorizedClientManager);
    		return WebClient.builder()
    				.apply(oauth2Client.oauth2Configuration())
    				.build();
    	}
    
    	@Bean
    	OAuth2AuthorizedClientManager authorizedClientManager(
    			ClientRegistrationRepository clientRegistrationRepository,
    			OAuth2AuthorizedClientRepository authorizedClientRepository) {
    
    		OAuth2AuthorizedClientProvider authorizedClientProvider =
    				OAuth2AuthorizedClientProviderBuilder.builder()
    						.authorizationCode()
    						.refreshToken()
    						.clientCredentials()
    						.build();
    		DefaultOAuth2AuthorizedClientManager authorizedClientManager = new DefaultOAuth2AuthorizedClientManager(
    				clientRegistrationRepository, authorizedClientRepository);
    		authorizedClientManager.setAuthorizedClientProvider(authorizedClientProvider);
    
    		return authorizedClientManager;
    	}
    }
    
    /*
     * Copyright 2020 the original author or authors.
     *
     * Licensed under the Apache License, Version 2.0 (the "License");
     * you may not use this file except in compliance with the License.
     * You may obtain a copy of the License at
     *
     *      https://www.apache.org/licenses/LICENSE-2.0
     *
     * Unless required by applicable law or agreed to in writing, software
     * distributed under the License is distributed on an "AS IS" BASIS,
     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     * See the License for the specific language governing permissions and
     * limitations under the License.
     */
    package sample.web;
    
    import org.springframework.beans.factory.annotation.Value;
    import org.springframework.security.oauth2.client.OAuth2AuthorizedClient;
    import org.springframework.security.oauth2.client.annotation.RegisteredOAuth2AuthorizedClient;
    import org.springframework.security.oauth2.core.OAuth2AccessToken;
    import org.springframework.security.oauth2.core.OAuth2Error;
    import org.springframework.security.oauth2.core.endpoint.OAuth2ParameterNames;
    import org.springframework.stereotype.Controller;
    import org.springframework.ui.Model;
    import org.springframework.util.StringUtils;
    import org.springframework.web.bind.annotation.GetMapping;
    import org.springframework.web.bind.annotation.RequestParam;
    import org.springframework.web.bind.annotation.ResponseBody;
    import org.springframework.web.bind.annotation.RestController;
    import org.springframework.web.reactive.function.client.WebClient;
    
    import javax.servlet.http.HttpServletRequest;
    
    import java.util.Arrays;
    import java.util.Collections;
    import java.util.List;
    
    import static org.springframework.security.oauth2.client.web.reactive.function.client.ServletOAuth2AuthorizedClientExchangeFilterFunction.clientRegistrationId;
    import static org.springframework.security.oauth2.client.web.reactive.function.client.ServletOAuth2AuthorizedClientExchangeFilterFunction.oauth2AuthorizedClient;
    
    /**
     * @author Joe Grandja
     * 测试代码
     * @since 0.0.1
     */
    @RestController
    public class AuthorizationController {
        private final WebClient webClient;
        private final String messagesBaseUri;
    
        public AuthorizationController(WebClient webClient,
                                       @Value("${messages.base-uri}") String messagesBaseUri) {
            this.webClient = webClient;
            this.messagesBaseUri = messagesBaseUri;
        }
    
        @GetMapping(value = "/authorize", params = "grant_type=authorization_code")
        public List<String> authorizationCodeGrant(
                @RegisteredOAuth2AuthorizedClient("messaging-client-authorization-code")
                        OAuth2AuthorizedClient authorizedClient) {
    
            String[] messages = this.webClient
                    .get()
                    .uri(this.messagesBaseUri)
                    .attributes(oauth2AuthorizedClient(authorizedClient))
                    .retrieve()
                    .bodyToMono(String[].class)
                    .block();
    
            return messages != null ? Arrays.asList(messages) : Collections.singletonList("没数据");
        }
    
        @GetMapping(value = "/authorize", params = "grant_type=client_credentials")
        public List<String> clientCredentialsGrant() {
    
            String[] messages = this.webClient
                    .get()
                    .uri(this.messagesBaseUri)
                    .attributes(clientRegistrationId("messaging-client-client-credentials"))
                    .retrieve()
                    .bodyToMono(String[].class)
                    .block();
            return messages != null ? Arrays.asList(messages) : Collections.singletonList("没数据");
        }
    }
    
  3. 配置文件
    server:
      port: 8080
    
    logging:
      level:
        root: INFO
        org.springframework.web: INFO
        org.springframework.security: INFO
        org.springframework.security.oauth2: INFO
    #    org.springframework.boot.autoconfigure: DEBUG
    
    spring:
      thymeleaf:
        cache: false
      security:
        oauth2:
          client:
            registration:
              messaging-client-oidc:
                provider: spring
                client-id: messaging-client
                client-secret: secret
                authorization-grant-type: authorization_code
                redirect-uri: "http://127.0.0.1:8080/login/oauth2/code/{registrationId}"
                scope: openid
                client-name: messaging-client-oidc
              messaging-client-authorization-code:
                provider: spring
                client-id: messaging-client
                client-secret: secret
                authorization-grant-type: authorization_code
                redirect-uri: "http://127.0.0.1:8080/authorized"
                scope: message.read,message.write
                client-name: messaging-client-authorization-code
              messaging-client-client-credentials:
                provider: spring
                client-id: messaging-client
                client-secret: secret
                authorization-grant-type: client_credentials
                scope: message.read,message.write
                client-name: messaging-client-client-credentials
            provider:
              spring:
                issuer-uri: http://localhost:9000
    
    messages:
      base-uri: http://127.0.0.1:8090/messages
    

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值