1. <strong id="7actg"></strong>
    2. <table id="7actg"></table>

    3. <address id="7actg"></address>
      <address id="7actg"></address>
      1. <object id="7actg"><tt id="7actg"></tt></object>

        Spring Security 中使用Keycloak作為認證授權(quán)服務器

        共 14201字,需瀏覽 29分鐘

         ·

        2021-08-09 22:36

        Keycloak對流行的Java應用提供了適配器。在系列文章的上一篇我們演示了針對Spring Boot的安全保護,用的就是適配器的一種。Keycloak同樣提供Spring Security的適配器,后續(xù)的幾篇文章我們就來共同學習Spring Security適配器的使用。

        ?

        Keycloak的安裝可參考前面的系列教程。

        適配器集成

        在Spring 應用中我們集成keycloak-spring-security-adapter

        <dependency>
            <groupId>org.keycloak</groupId>
            <artifactId>keycloak-spring-security-adapter</artifactId>
            <version>15.0.0</version>
        </dependency>

        在Spring Boot中可以這樣集成:

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-security</artifactId>
        </dependency>
        <dependency>
            <groupId>org.keycloak</groupId>
            <artifactId>keycloak-spring-boot-starter</artifactId>
            <version>15.0.0</version>
        </dependency>       

        然后就能利用Spring Security的特性來集成Keycloak。Keycloak 提供了一個 KeycloakWebSecurityConfigurerAdapter 作為創(chuàng)建WebSecurityConfigurer 實例的方便基類。我們可以編寫了一個配置類來定制我們的安全策略,就像這樣:

        @KeycloakConfiguration
        public class SecurityConfig extends KeycloakWebSecurityConfigurerAdapter
        {
            /**
             *  注冊了一個Keycloak的AuthenticationProvider
             */

            @Autowired
            public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
                auth.authenticationProvider(keycloakAuthenticationProvider());
            }

            /**
             * 定義會話策略
             */

            @Bean
            @Override
            protected SessionAuthenticationStrategy sessionAuthenticationStrategy() {
                return new RegisterSessionAuthenticationStrategy(new SessionRegistryImpl());
            }

            /**
             * 常見的Spring Security安全策略
             */
         
            @Override
            protected void configure(HttpSecurity http) throws Exception
            
        {
                super.configure(http);
                http
                        .authorizeRequests()
                        .antMatchers("/customers*").hasRole("USER")
                        .antMatchers("/admin/**").hasRole("base_user")
                        .anyRequest().permitAll();
            }
        }

        ?

        注意:上面的配置并不能成功。

        配置完上面的然后我們直接啟動應用,結(jié)果并不像期望的那樣:

        java.io.FileNotFoundException: Unable to locate Keycloak configuration file: keycloak.json

        拋出找不到 keycloak.json文件的異常。Keycloak支持的每個Java適配器都可以通過一個簡單的JSON文件進行配置,我們?nèi)笔У木褪沁@個文件。

        {
          "realm" : "demo",
          "resource" : "customer-portal",
          "realm-public-key" : "MIGfMA0GCSqGSIb3D...31LwIDAQAB",
          "auth-server-url" : "https://localhost:8443/auth",
          "ssl-required" : "external",
          "use-resource-role-mappings" : false,
          "enable-cors" : true,
          "cors-max-age" : 1000,
          "cors-allowed-methods" : "POST, PUT, DELETE, GET",
          "cors-exposed-headers" : "WWW-Authenticate, My-custom-exposed-Header",
          "bearer-only" : false,
          "enable-basic-auth" : false,
          "expose-token" : true,
          "verify-token-audience" : true,
           "credentials" : {
              "secret" : "234234-234234-234234"
           },

           "connection-pool-size" : 20,
           "socket-timeout-millis": 5000,
           "connection-timeout-millis": 6000,
           "connection-ttl-millis": 500,
           "disable-trust-manager"false,
           "allow-any-hostname" : false,
           "truststore" : "path/to/truststore.jks",
           "truststore-password" : "geheim",
           "client-keystore" : "path/to/client-keystore.jks",
           "client-keystore-password" : "geheim",
           "client-key-password" : "geheim",
           "token-minimum-time-to-live" : 10,
           "min-time-between-jwks-requests" : 10,
           "public-key-cache-ttl": 86400,
           "redirect-rewrite-rules" : {
           "^/wsmaster/api/(.*)$" : "/api/$1"
           }
        }

        上面包含的客戶端配置屬性都可以在Keycloak控制臺進行配置,見下圖:

        配置Keycloak客戶端屬性

        也就是說我們需要的json文件和圖中的配置項是對應的。比較人性化的是我們不需要自行編寫這個json文件,Keycloak提供了下載客戶端配置的方法,這里我只使用了必要的配置項:

        你可以下載客戶端json配置

        引入客戶端配置

        雖然順利拿到json文件,但是加載這個json配置卻不太順利,經(jīng)過我的摸索需要實現(xiàn)一個KeycloakConfigResolver并注入Spring IoC,有下面兩種實現(xiàn)方式。

        復用Spring Boot Adapter配置

        直接復用Spring Boot的配置形式,先聲明Spring BootKeycloakConfigResolver實現(xiàn):

          /**
             * 復用spring boot 的方法
             *
             * @return the keycloak config resolver
             */

            @Bean
            public KeycloakConfigResolver keycloakConfigResolver() {
                return new KeycloakSpringBootConfigResolver();
            }

        然后復用Spring Bootapplication.yaml的配置項:

        復用Spring Boot配置項

        ?

        原來的角色資源映射約束失效。

        自定義實現(xiàn)

        你也可以自定義寫解析,這個時候json形式已經(jīng)不重要了,你可以將json文件的內(nèi)容存儲到任何你擅長的地方。

        /**
         * 自己寫解析
         *
         * @return the keycloak config resolver
         */

        @Bean
        public KeycloakConfigResolver fileKeycloakConfigResolver() {
            return  new KeycloakConfigResolver() {
                @SneakyThrows
                @Override
                public KeycloakDeployment resolve(HttpFacade.Request request) {
                    // json 文件放到resources 文件夾下
                    ClassPathResource classPathResource = new ClassPathResource("./keycloak.json");
                    AdapterConfig adapterConfig = new ObjectMapper().readValue(classPathResource.getFile(), AdapterConfig.class);

                    return KeycloakDeploymentBuilder.build(adapterConfig);
                }
            };
        }

        角色命名策略

        Spring Security會為每個角色添加ROLE_前綴,這需要我們聲明GrantedAuthoritiesMapper的實現(xiàn)SimpleAuthorityMapper來完成這一功能。KeycloakKeycloakAuthenticationProvider中配置該功能:

                KeycloakAuthenticationProvider authenticationProvider = keycloakAuthenticationProvider();
                authenticationProvider.setGrantedAuthoritiesMapper(new SimpleAuthorityMapper());

        完整的配置

        applicaiton.yaml:

        keycloak:
        # 聲明客戶端所在的realm
          realm: felord.cn
        # keycloak授權(quán)服務器的地址
          auth-server-url: http://localhost:8011/auth
        # 客戶端名稱
          resource: springboot-client
        # 聲明這是一個公開的客戶端,否則不能在keycloak外部環(huán)境使用,會403
          public-client: true

        ?

        這里要結(jié)合Keycloak導出的json文件配置。

        Spring Security配置:

        @KeycloakConfiguration
        public class SecurityConfig extends KeycloakWebSecurityConfigurerAdapter {
            
            /**
             * 復用spring boot 的方法
             *
             * @return the keycloak config resolver
             */

            @Bean
            public KeycloakConfigResolver keycloakConfigResolver() {
                return new KeycloakSpringBootConfigResolver();
            }
            /**
             * 自己寫解析
             *
             * @return the keycloak config resolver
             */

        //    @Bean
            public KeycloakConfigResolver fileKeycloakConfigResolver() {
                return request -> {
                    // json 文件放到resources 文件夾下
                    ClassPathResource classPathResource = new ClassPathResource("./keycloak.json");
                    AdapterConfig adapterConfig = null;
                    try {
                        adapterConfig = new ObjectMapper().readValue(classPathResource.getFile(), 
                                AdapterConfig.class);
                    } catch (IOException e) {
                        e.printStackTrace();
                    }

                    return KeycloakDeploymentBuilder.build(adapterConfig);
                };
            }
            /**
             *  配置{@link AuthenticationManager}
             *  這里會引入Keycloak的{@link AuthenticationProvider}實現(xiàn)
             *
             * @param auth the auth
             */

            @Autowired
            public void configureGlobal(AuthenticationManagerBuilder auth) {
                KeycloakAuthenticationProvider authenticationProvider = keycloakAuthenticationProvider();
                authenticationProvider.setGrantedAuthoritiesMapper(new SimpleAuthorityMapper());
                auth.authenticationProvider(authenticationProvider);
            }
            /**
             * 會話身份驗證策略
             */

            @Bean
            @Override
            protected SessionAuthenticationStrategy sessionAuthenticationStrategy() {
                return new RegisterSessionAuthenticationStrategy(new SessionRegistryImpl());
            }
            /**
             * 配置 session 監(jiān)聽器 保證單點退出生效
             *
             * @return the servlet listener registration bean
             */

            @Bean
            public ServletListenerRegistrationBean<HttpSessionEventPublisher> httpSessionEventPublisher() {
                return new ServletListenerRegistrationBean<>(new HttpSessionEventPublisher());
            }
            @Override
            protected void configure(HttpSecurity http) throws Exception {
                super.configure(http);
                http
                        .authorizeRequests()
                        .antMatchers("/customers*").hasRole("USER")
                        .antMatchers("/admin/**").hasRole("base_user")
                        .anyRequest().permitAll();
            }
        }

        調(diào)用流程

        資源客戶端springboot-client有一個接口/admin/foo,當未登錄調(diào)用該接口時會轉(zhuǎn)發(fā)到:

        http://localhost:8011/auth/realms/felord.cn/protocol/openid-connect/auth?response_type=code&client_id=springboot-client&redirect_uri=http%3A%2F%2Flocalhost%3A8080%2Fsso%2Flogin&state=ec00d608-5ce7-47a0-acc8-8a20a2bfadfd&login=true&scope=openid

        輸入正確的用戶密碼后才能得到期望的結(jié)果。

        ?

        典型的authorazation code flow

        總結(jié)

        Keycloak整合Spring Security的要點這里需要再梳理一下。在原生情況下,客戶端的配置、用戶的信息、角色信息都由Keycloak負責;客戶端只負責角色和資源的映射關系。后續(xù)會深入并定制KeycloakSpring Security以滿足實際場景需要。




        往期推薦

        騰訊員工吐槽:團隊來了個阿里高p,瞬間會議變多,群多了

        程序員加入新團隊必問的20道問題

        只是想虐下春麗,一不小心擼了臺游戲機...

        Spring Boot中使用時序數(shù)據(jù)庫InfluxDB

        萬萬沒想到!logger.info() 還能導致線上故障?


        瀏覽 56
        點贊
        評論
        收藏
        分享

        手機掃一掃分享

        分享
        舉報
        評論
        圖片
        表情
        推薦
        點贊
        評論
        收藏
        分享

        手機掃一掃分享

        分享
        舉報
        1. <strong id="7actg"></strong>
        2. <table id="7actg"></table>

        3. <address id="7actg"></address>
          <address id="7actg"></address>
          1. <object id="7actg"><tt id="7actg"></tt></object>
            打飞机视频网站 | 能看的黄色小说 | 公车上岳好紧好紧我要进去了 | 肏逼片 | 夜夜爽妓女8888 | 男男被各种姿势c到高潮高h | 成人午夜福利免费视频 | 男插女视频久久精品 | 久久久久99精品成人片欧美片 | 日韩亚洲欧美在线 |