<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    paulwong

    OAUTH2 - SPRING SECURITY + KEYCLOAK

    根據(jù)OAUTH2協(xié)議,如果需要用戶協(xié)助的,則使用authorization_code流程,此時(shí)需要用戶登錄頁面、CLIENT SERVER、RESOURCE SERVER和AUTHORIZATION SERVER,其中CLIENT SERVER是通過http調(diào)用RESOURCE SERVER的api,AUTHORIZATION SERVER使用現(xiàn)成的KEYCLOAK。

    如果不需要用戶協(xié)助的,即SERVER對(duì)SERVER的,則適用client_credentials流程,此時(shí)需要CLIENT SERVER、RESOURCE SERVER和AUTHORIZATION SERVER。

    通常HTTP請(qǐng)求會(huì)在HEADER中夾帶ACCESS_TOKEN,格式為JWT。

    RESOURCE SERVER是如何知道該次的HTTP請(qǐng)求是合法的呢,只需用AUTHORIZATION SERVER提供的PUBLIC KEY能正常解密ACCESS_TOKEN,且不過期,則是合法的請(qǐng)求。

    如果需要做授權(quán)認(rèn)證,則檢查JWT中的ROLE字符是否是事先定義的字符,如是則認(rèn)為有權(quán)訪問,否則拒絕。

    RESOURCE SERVER

    pom.xml
    <?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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
        <modelVersion>4.0.0</modelVersion>
        <parent>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-parent</artifactId>
            <version>2.5.6</version>
            <relativePath /> <!-- lookup parent from repository -->
        </parent>
        <groupId>com.paul</groupId>
        <artifactId>test-oauth2-department-service</artifactId>
        <version>0.0.1-SNAPSHOT</version>
        <name>test-oauth2</name>
        <description>Demo project for Spring Boot</description>
        <properties>
            <java.version>1.8</java.version>
        </properties>
        
        <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-webflux</artifactId>
            </dependency>
            
            <dependency>
                <groupId>org.mariadb.jdbc</groupId>
                <artifactId>mariadb-java-client</artifactId>
            </dependency>


            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-test</artifactId>
                <scope>test</scope>
            </dependency>
        </dependencies>

        <build>
            <plugins>
                <plugin>
                    <groupId>org.springframework.boot</groupId>
                    <artifactId>spring-boot-maven-plugin</artifactId>
                    <configuration>
                        <layout>ZIP</layout>
                        <excludes>
                            <exclude>
                                <groupId>*</groupId>
                                <artifactId>*</artifactId>
                            </exclude>
                        </excludes>
                        <includes>
                            <include>
                                <groupId>com.paul</groupId>
                            </include>
                        </includes>
                    </configuration>
                </plugin>
            </plugins>
        </build>

    </project>

    application.yaml
    server:
       port: 8281
       
    spring:
      security:
        oauth2:
          #check OAuth2ResourceServerProperties
          resourceserver:
            jwt:
              #jwk-set-uri: "${rest.security.issuer-uri}/protocol/openid-connect/certs"
              issuer-uri: "${rest.security.issuer-uri}"
              #public-key-location: "classpath:/key.pub"


    #Logging Configuration

    logging:
       level:
          org.springframework.boot.autoconfigure.logging: INFO
          org.springframework.security: DEBUG
          com.paul: DEBUG
          root: INFO

    java配置文件
    package com.paul.testoauth2.config;

    import org.springframework.boot.autoconfigure.security.oauth2.resource.OAuth2ResourceServerProperties;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.http.HttpMethod;
    import org.springframework.security.config.annotation.web.builders.HttpSecurity;
    import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
    import org.springframework.security.oauth2.jwt.JwtDecoder;
    import org.springframework.security.oauth2.jwt.JwtDecoders;
    import org.springframework.security.oauth2.jwt.NimbusJwtDecoder;
    import org.springframework.security.oauth2.server.resource.authentication.JwtAuthenticationConverter;
    import org.springframework.security.oauth2.server.resource.web.BearerTokenAuthenticationEntryPoint;

    import com.fasterxml.jackson.databind.ObjectMapper;
    import com.paul.testoauth2.oauth2.converter.KeycloakRealmRoleConverter;
    import com.paul.testoauth2.oauth2.converter.UsernameSubClaimAdapter;

    @Configuration
    public class SecurityConfigurer extends WebSecurityConfigurerAdapter{
        
        @Override
        protected void configure(HttpSecurity http) throws Exception {
            // @formatter:off
            http
                .authorizeRequests(
                    a -> a.antMatchers("/", "/error", "/webjars/**")
                          .permitAll()
                          .antMatchers(HttpMethod.GET, "/protected/**").hasRole("READ_DEPARTMENT")
                          .anyRequest()
                          .authenticated()
                 )
                .exceptionHandling(
                    e -> e//.authenticationEntryPoint(new HttpStatusEntryPoint(HttpStatus.UNAUTHORIZED))
                          .authenticationEntryPoint(new BearerTokenAuthenticationEntryPoint())
    //                      .accessDeniedHandler(new BearerTokenAccessDeniedHandler())
                )
                .oauth2ResourceServer(
                    o -> o.jwt(
                              j -> j.jwtAuthenticationConverter(jwtAuthenticationConverter(null))
                                      .decoder(jwtDecoder(null))
                           )
                 )
    //            .decoder(jwtDecoder(null))
                ;
            // @formatter:on
        }
        
        @Bean
        public JwtAuthenticationConverter jwtAuthenticationConverter(ObjectMapper objectMapper) {
            JwtAuthenticationConverter jwtConverter = new JwtAuthenticationConverter();
            jwtConverter.setJwtGrantedAuthoritiesConverter(new KeycloakRealmRoleConverter(objectMapper));
            
            return jwtConverter;
        }
        
        //below is auto configured at OAuth2ResourceServerJwtConfiguration
        @Bean
        public JwtDecoder jwtDecoder(OAuth2ResourceServerProperties properties) {
            String issuerUri = properties.getJwt().getIssuerUri();
            // Use preferred_username from claims as authentication name, instead of UUID subject
            NimbusJwtDecoder jwtDecoder = 
                    JwtDecoders.<NimbusJwtDecoder>fromIssuerLocation(issuerUri);
            jwtDecoder.setClaimSetConverter(new UsernameSubClaimAdapter());
            return jwtDecoder;
        }

    }


    CLIENT SERVER

    pom.xml
    <?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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
        <modelVersion>4.0.0</modelVersion>
        <parent>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-parent</artifactId>
            <version>2.5.6</version>
            <relativePath /> <!-- lookup parent from repository -->
        </parent>
        <groupId>com.paul</groupId>
        <artifactId>test-oauth2</artifactId>
        <version>0.0.1-SNAPSHOT</version>
        <name>test-oauth2</name>
        <description>Demo project for Spring Boot</description>
        <properties>
            <java.version>1.8</java.version>
        </properties>
        
        <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-client</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-webflux</artifactId>
            </dependency>
            
            <dependency>
                <groupId>org.mariadb.jdbc</groupId>
                <artifactId>mariadb-java-client</artifactId>
            </dependency>

            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-data-jdbc</artifactId>
            </dependency>

            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-test</artifactId>
                <scope>test</scope>
            </dependency>
        </dependencies>

        <build>
            <plugins>
                <plugin>
                    <groupId>org.springframework.boot</groupId>
                    <artifactId>spring-boot-maven-plugin</artifactId>
                    <configuration>
                        <layout>ZIP</layout>
                        <excludes>
                            <exclude>
                                <groupId>*</groupId>
                                <artifactId>*</artifactId>
                            </exclude>
                        </excludes>
                        <includes>
                            <include>
                                <groupId>com.paul</groupId>
                            </include>
                        </includes>
                    </configuration>
                </plugin>
            </plugins>
        </build>

    </project>

    application.yaml
    server:
       port: 8280
       
    spring:
      security:
        oauth2:
          #check OAuth2ResourceServerProperties
          resourceserver:
            jwt:
              #jwk-set-uri: "${rest.security.issuer-uri}/protocol/openid-connect/certs"
              issuer-uri: "${rest.security.issuer-uri}"
              #public-key-location: "classpath:/key.pub"
                   
          #check OAuth2ClientProperties

          client:
            registration:
              my-client-1:
                client-id: "test-employee-service"
                client-secret: ${client-secret.my-client-1}
                client-name: "test-employee-service"
                provider: "keycloak-provider"
                scope: "openid"
                #redirect-uri: "https://my-redirect-uri.com"
                client-authentication-method: "basic"
                authorization-grant-type: "client_credentials"
              app-springboot-confidential:
                client-id: "app-springboot-confidential"
                client-secret: ${client-secret.app-springboot-confidential}
                client-name: "app-springboot-confidential"
                provider: "keycloak-provider"
                scope: "openid"
                redirect-uri: "https://my-redirect-uri.com"
                client-authentication-method: "basic"
                authorization-grant-type: "authorization_code"

            provider:
              keycloak-provider:
                issuer-uri : "${rest.security.issuer-uri}"
                user-name-attribute: "preferred_username"


    #Logging Configuration
    logging:
       level:
          org.springframework.boot.autoconfigure.logging: INFO
          org.springframework.security: DEBUG
          com.paul: DEBUG
          root: INFO

    SecurityConfigurer.java
    package com.paul.testoauth2.config;

    import org.springframework.boot.autoconfigure.security.oauth2.resource.OAuth2ResourceServerProperties;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.http.HttpMethod;
    import org.springframework.jdbc.core.JdbcOperations;
    import org.springframework.security.config.annotation.web.builders.HttpSecurity;
    import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
    import org.springframework.security.oauth2.client.JdbcOAuth2AuthorizedClientService;
    import org.springframework.security.oauth2.client.OAuth2AuthorizedClientService;
    import org.springframework.security.oauth2.client.registration.ClientRegistrationRepository;
    import org.springframework.security.oauth2.jwt.JwtDecoder;
    import org.springframework.security.oauth2.jwt.JwtDecoders;
    import org.springframework.security.oauth2.jwt.NimbusJwtDecoder;
    import org.springframework.security.oauth2.server.resource.authentication.JwtAuthenticationConverter;
    import org.springframework.security.oauth2.server.resource.web.BearerTokenAuthenticationEntryPoint;

    import com.fasterxml.jackson.databind.ObjectMapper;
    import com.paul.testoauth2.oauth2.converter.KeycloakRealmRoleConverter;
    import com.paul.testoauth2.oauth2.converter.UsernameSubClaimAdapter;

    @Configuration
    //@EnableGlobalMethodSecurity(prePostEnabled = true)
    public class SecurityConfigurer extends WebSecurityConfigurerAdapter{
        
        @Override
        protected void configure(HttpSecurity http) throws Exception {
            // @formatter:off
            http
                .authorizeRequests(
                    a -> a
                            .antMatchers("/", "/error", "/webjars/**")
                          .permitAll()
                          .antMatchers(HttpMethod.GET, "/protected/**").hasRole("USER")
                          .antMatchers(HttpMethod.GET, "/api/employees/**").hasRole("READ_EMPLOYEE")
                          .anyRequest()
                          .authenticated()
                 )
                .exceptionHandling(
                    e -> e//.authenticationEntryPoint(new HttpStatusEntryPoint(HttpStatus.UNAUTHORIZED))
                          .authenticationEntryPoint(new BearerTokenAuthenticationEntryPoint())
    //                      .accessDeniedHandler(new BearerTokenAccessDeniedHandler())
                 )
                .oauth2Client(
                    c -> c.authorizedClientService(
                              authorizedClientService(nullnull)
                           )
                 )
                .oauth2ResourceServer()
                .jwt(
                    c -> c.jwtAuthenticationConverter(
                              jwtAuthenticationConverter(null)
                           )
                          .decoder(jwtDecoder(null))
                 )
    //            .decoder(jwtDecoder(null))
                ;
            // @formatter:on
        }
        
        @Bean
        public OAuth2AuthorizedClientService authorizedClientService(
            JdbcOperations jdbcOperations, ClientRegistrationRepository clientRegistrationRepository
        ) {
            return new JdbcOAuth2AuthorizedClientService(jdbcOperations, clientRegistrationRepository);
        }
        
        @Bean
        public JwtAuthenticationConverter jwtAuthenticationConverter(ObjectMapper objectMapper) {
            JwtAuthenticationConverter jwtConverter = new JwtAuthenticationConverter();
            jwtConverter.setPrincipalClaimName("preferred_username");
            jwtConverter.setJwtGrantedAuthoritiesConverter(new KeycloakRealmRoleConverter(objectMapper));
            return jwtConverter;
        }
        
        //below is auto configured at OAuth2ResourceServerJwtConfiguration
        @Bean
        public JwtDecoder jwtDecoder(OAuth2ResourceServerProperties properties) {
            String issuerUri = properties.getJwt().getIssuerUri();
            // Use preferred_username from claims as authentication name, instead of UUID subject
            NimbusJwtDecoder jwtDecoder = 
                    JwtDecoders.<NimbusJwtDecoder>fromIssuerLocation(issuerUri);
            jwtDecoder.setClaimSetConverter(new UsernameSubClaimAdapter());
            return jwtDecoder;
        }

    }


    WebClientConfig.java
    package com.paul.testoauth2.config;

    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.security.oauth2.client.registration.ClientRegistrationRepository;
    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;

    @Configuration
    public class WebClientConfig {

        @Bean
        public WebClient webClient(ClientRegistrationRepository clientRegistrations,
                OAuth2AuthorizedClientRepository authorizedClients) {
            ServletOAuth2AuthorizedClientExchangeFilterFunction oauth = 
                    new ServletOAuth2AuthorizedClientExchangeFilterFunction(clientRegistrations, authorizedClients);
            oauth.setDefaultClientRegistrationId("my-client-1");
            return WebClient.builder().filter(oauth).build();
        }

    }

    DepartmentRestClient.java
    package com.paul.testoauth2.employee.service;


    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.beans.factory.annotation.Value;
    import org.springframework.stereotype.Component;
    import org.springframework.web.reactive.function.client.WebClient;

    @Component
    public class DepartmentRestClient {
        
    //    @NotNull
        @Value("${department-service.url}")
        private String endpoint;

        @Autowired
        private WebClient webClient;

        public String getDepartmentName() {
            return webClient.get()
                            .uri(endpoint + "/protected")
                            .retrieve()
                            .bodyToMono(String.class)
                            .block()
                            ;
        }
    }


    Reference:
    https://docs.spring.io/spring-security/site/docs/5.5.x/reference/html5/#oauth2

    Sample Project:
    https://github.com/spring-projects/spring-security-samples/tree/5.5.x

    !相當(dāng)不錯(cuò)的教程
    https://wstutorial.com/index.html
    https://wstutorial.com/rest/spring-security-oauth2-keycloak.html
    https://wstutorial.com/rest/spring-security-oauth2-keycloak-roles.html






    posted on 2021-11-03 16:58 paulwong 閱讀(744) 評(píng)論(0)  編輯  收藏 所屬分類: OAUTH2

    主站蜘蛛池模板: 亚洲AV无码一区二区三区在线| 91大神免费观看| 亚洲日本天堂在线| 亚洲av午夜福利精品一区 | 亚洲三级在线播放| 亚洲AV无码一区二区乱子伦| 免费大黄网站在线观| 好吊妞视频免费视频| 青娱分类视频精品免费2| 久久99热精品免费观看动漫| 亚洲免费日韩无码系列| 高潮毛片无遮挡高清免费视频| 亚洲情A成黄在线观看动漫软件| 亚洲黄色免费网站| 亚洲AV人无码综合在线观看| 亚洲人成图片小说网站| 国产成人精品日本亚洲专区| 亚洲VA综合VA国产产VA中| 国产免费黄色大片| 国产免费观看黄AV片| 国产在线观看免费不卡| 免费无码不卡视频在线观看| 成人毛片18女人毛片免费视频未| 无码区日韩特区永久免费系列| 99re6在线精品视频免费播放 | 亚洲性猛交XXXX| 国产成人精品日本亚洲专区61| 亚洲国产精品无码久久青草| 一本久到久久亚洲综合| 亚洲?V乱码久久精品蜜桃| 亚洲国产精品综合久久一线 | 国产免费一级高清淫曰本片 | 亚洲乱码中文字幕综合| 亚洲中文字幕不卡无码| 久久精品国产69国产精品亚洲| 国产亚洲精品a在线观看app| 亚洲视频在线免费观看| 亚洲国产精品日韩在线观看| 亚洲免费电影网站| 亚洲精品无码中文久久字幕| 国产精品亚洲专区一区|