码迷,mamicode.com
首页 > 编程语言 > 详细

spring boot zuul集成kubernetes等第三方登录

时间:2019-11-15 18:54:26      阅读:116      评论:0      收藏:0      [点我收藏+]

标签:bool   services   轻松   cat   import   media   CND   nta   iba   

介绍一下,在单点登录平台集成kubernetes登录,集成其它系统的登录原理是一样的,如grafana, nacos, jenkins等。

POM引用:

        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
            <version>1.2.58</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-zuul</artifactId>
        </dependency>

系统入口类:

@SpringBootApplication
@EnableZuulProxy
@Slf4j
public class DemoApplication {

    public static void main(String[] args) {

        SpringApplication.run(DemoApplication.class, args);

    }
}

 

controller:

这里要说下,kubernetes的登录逻辑:

技术图片

 

 

 

有两个login:

第一个login:https://***:30000/api/v1/csrftoken/login

返回json:

{
  "token": "4IJufIQiwOWcaFmQdMMHKQqNEro:1573810029428"
 }

第二个login:https://**30000/api/v1/login,使用第一个login返回的token进行登录:

技术图片

 

返回json:

{
  "jweToken": "{\"protected\":\"eyJhbGciOiJSU0EtT0FFUC0yNTYiLCJlbmMiOiJBMjU2R0NNIn0\",\"aad\":\"eyJleHAiOiIyMDE5LTExLTE1VDE5OjI3OjA5WiIsImlhdCI6IjIwMTktMTEtMTVUMDk6Mjc6MDlaIn0\",\"encrypted_key\":\"Pq5FWwv06JXsPL8H5N3ZAlk7jTGHIGwbdjFdNUoAa6mWn-avNnPiZNjgsDFPZF8cNDgVsN_J-BmranVabxVe9VeJmuDgfY-2KTANslsKF4g2nPdZC3DDmFdLB6V-eXaBduw0ABLGaGisPX_T-3Qxls1sx9EuJ8vvH9a3Fr_iQPxiGxyG_61jSjqqtwXB-sftxULpAuDv84V4Ebba9JLFxCSJnmQ0E8hw3w5Ady1pw3dbPb8q1HnuPEd3Ry27EJYRzswQWkG9CJRxbcQtOzlneW0jBqrbbi-UpVy2vQC2zmdLKACzwkas3l9BBKHJF7xwxUoX-oc4i6NM6HqkwIbSAQ\",\"iv\":\"HoG3iDTSawS7-xBS\",\"ciphertext\":\"Ad696v6QmyciUmE_F3xstK6xX9CZAQw1IsKmi9oDwjoVELaBDZOPTfR-Cqub3WHj520Svdubei8QiIC5zg\",\"tag\":\"8Rf53qa5hBn7jrAiuYqrLw\"}",
  "errors": []
 }

然后我们就可以用jweToken写入cookie 轻松访问k8s了。

技术图片

 

 

 下面的代码显示这这三个步骤:

package com.cis.jpa.demo.controller;

import com.alibaba.fastjson.JSONObject;
import com.cis.jpa.demo.dto.LoginResult;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;

import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.net.URLEncoder;

/**
 * @author :hkk
 * @date :Created in 2019/11/15 13:29
 */
@RestController
public class K8sController {
    private static final String K8S_ADDR = "https://***:30000/";

    @Autowired
    private RestTemplate restTemplate;
    @RequestMapping("/sso")
    public void index(HttpServletResponse response) throws IOException {

        String loginToken = getLoginToken();
        LoginResult body = getLoginJweToken(loginToken);
        String code = URLEncoder.encode(body.getJweToken(), "utf-8");
        Cookie cookie = new Cookie("jweToken",code);
        cookie.setPath("/");
        response.addCookie(cookie);
        response.addHeader("jweToken",body.getJweToken());
        response.sendRedirect("/");

    }

    private LoginResult getLoginJweToken(String loginToken) {
        JSONObject json = new JSONObject();
        json.put("kubeconfig", "");
        json.put("password", "admin");
        json.put("username", "admin");
        json.put("token", "");

        HttpHeaders headers = new HttpHeaders();
        MediaType type = MediaType.parseMediaType("application/json; charset=UTF-8");
        headers.setContentType(type);
        headers.add("Accept", MediaType.APPLICATION_JSON.toString());
        headers.add("x-csrf-token", loginToken);

        HttpEntity<String> formEntity = new HttpEntity<>(json.toString(), headers);

        String loginUrl = K8S_ADDR + "api/v1/login";
        return restTemplate.postForEntity(loginUrl, formEntity, LoginResult.class).getBody();
    }

    private String getLoginToken() {
        String preLoginUrl = K8S_ADDR +"api/v1/csrftoken/login";

        LoginResult body = restTemplate.getForEntity(preLoginUrl, LoginResult.class).getBody();

        return body.getToken();
    }
    
}

 

这里先用两个restTemplate获取token和jweToken,但由于是https所以,需要配置restTemplate:

这个类摘自网络,出处找不到了。。。

package com.cis.jpa.demo.confing;

import org.springframework.http.client.SimpleClientHttpRequestFactory;
import org.springframework.stereotype.Component;

import javax.net.ssl.*;
import java.io.IOException;
import java.net.HttpURLConnection;
import java.net.InetAddress;
import java.net.Socket;
import java.security.cert.X509Certificate;

/**
 * @author :hkk
 * @date :Created in 2019/11/15 11:14
 */
@Component
public class HttpsClientRequestFactory extends SimpleClientHttpRequestFactory {

    @Override
    protected void prepareConnection(HttpURLConnection connection, String httpMethod) {
        try {
            if (!(connection instanceof HttpsURLConnection)) {
                throw new RuntimeException("An instance of HttpsURLConnection is expected");
            }

            HttpsURLConnection httpsConnection = (HttpsURLConnection) connection;

            TrustManager[] trustAllCerts = new TrustManager[]{
                    new X509TrustManager() {
                        @Override
                        public X509Certificate[] getAcceptedIssuers() {
                            return null;
                        }
                        @Override
                        public void checkClientTrusted(X509Certificate[] certs, String authType) {
                        }
                        @Override
                        public void checkServerTrusted(X509Certificate[] certs, String authType) {
                        }

                    }
            };
            SSLContext sslContext = SSLContext.getInstance("TLS");
            sslContext.init(null, trustAllCerts, new java.security.SecureRandom());
            httpsConnection.setSSLSocketFactory(new MyCustomSSLSocketFactory(sslContext.getSocketFactory()));

            httpsConnection.setHostnameVerifier(new HostnameVerifier() {
                @Override
                public boolean verify(String s, SSLSession sslSession) {
                    return true;
                }
            });

            super.prepareConnection(httpsConnection, httpMethod);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * We need to invoke sslSocket.setEnabledProtocols(new String[] {"SSLv3"});
     * see http://www.oracle.com/technetwork/java/javase/documentation/cve-2014-3566-2342133.html (Java 8 section)
     */
    // SSLSocketFactory用于创建 SSLSockets
    private static class MyCustomSSLSocketFactory extends SSLSocketFactory {

        private final SSLSocketFactory delegate;

        public MyCustomSSLSocketFactory(SSLSocketFactory delegate) {
            this.delegate = delegate;
        }

        // 返回默认启用的密码套件。除非一个列表启用,对SSL连接的握手会使用这些密码套件。
        // 这些默认的服务的最低质量要求保密保护和服务器身份验证
        @Override
        public String[] getDefaultCipherSuites() {
            return delegate.getDefaultCipherSuites();
        }

        // 返回的密码套件可用于SSL连接启用的名字
        @Override
        public String[] getSupportedCipherSuites() {
            return delegate.getSupportedCipherSuites();
        }


        @Override
        public Socket createSocket(final Socket socket, final String host, final int port,
                                   final boolean autoClose) throws IOException {
            final Socket underlyingSocket = delegate.createSocket(socket, host, port, autoClose);
            return overrideProtocol(underlyingSocket);
        }


        @Override
        public Socket createSocket(final String host, final int port) throws IOException {
            final Socket underlyingSocket = delegate.createSocket(host, port);
            return overrideProtocol(underlyingSocket);
        }

        @Override
        public Socket createSocket(final String host, final int port, final InetAddress localAddress,
                                   final int localPort) throws
                IOException {
            final Socket underlyingSocket = delegate.createSocket(host, port, localAddress, localPort);
            return overrideProtocol(underlyingSocket);
        }

        @Override
        public Socket createSocket(final InetAddress host, final int port) throws IOException {
            final Socket underlyingSocket = delegate.createSocket(host, port);
            return overrideProtocol(underlyingSocket);
        }

        @Override
        public Socket createSocket(final InetAddress host, final int port, final InetAddress localAddress,
                                   final int localPort) throws
                IOException {
            final Socket underlyingSocket = delegate.createSocket(host, port, localAddress, localPort);
            return overrideProtocol(underlyingSocket);
        }

        private Socket overrideProtocol(final Socket socket) {
            if (!(socket instanceof SSLSocket)) {
                throw new RuntimeException("An instance of SSLSocket is expected");
            }
            ((SSLSocket) socket).setEnabledProtocols(new String[]{"TLSv1"});
            return socket;
        }
    }
}

再配置restTemplate:

@Bean
    public RestTemplate restTemplate(HttpsClientRequestFactory factory){

        return new RestTemplate(factory);
    }

restTemplate就可以访问https站点了。

 

controller中第三步跳转到“ / ”根目录:

根目录在是zuul中配置跳转的:

zuul:
  host:
    max-per-route-connections: 300000
    socket-timeout-millis: 300000
    connect-timeout-millis: 60000
  ignoredServices: ‘*‘
  ignoredPatterns: ‘/sso‘
  routes:
    k8s-config:
      path: /**
      url: https://***:30000/
      stripPrefix: true
      sensitiveHeaders: Cookie,Set-Cookie

与restTemplate一样,zuul也是默认不支持访问https的,(kubernetes与其它系统的不同点是它是https登录),其他都是http协议。

zuul网关路由https时,需要对httpclient做一些处理,否则会报错:

Caused by: sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target

 

解决这个问题有两个思络,一是对特定站点进行证书的导入配置,另一种是无论是哪个https站点,都可以访问,这里我们选择第二种:

    @Bean
    public CloseableHttpClient httpClient() throws NoSuchAlgorithmException, KeyManagementException, KeyStoreException {
        SSLConnectionSocketFactory scsf = new SSLConnectionSocketFactory(
                SSLContexts.custom().loadTrustMaterial(null, new TrustSelfSignedStrategy()).build()
                , NoopHostnameVerifier.INSTANCE
        );

        return HttpClients.custom().setSSLSocketFactory(scsf).build();
    }

这样我们就可以像访问自己的站点一样,访问k8s dashboard了。

 

spring boot zuul集成kubernetes等第三方登录

标签:bool   services   轻松   cat   import   media   CND   nta   iba   

原文地址:https://www.cnblogs.com/hankuikui/p/11868408.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!