├── changelog └── README.md ├── deployment ├── jar-runapp.md ├── docker-compose-runapp.md ├── micrometer.md ├── production-environment.md ├── docker-runapp.md └── deployment-core.md ├── share-file ├── playbook │ ├── test-playbook.yml │ ├── 4-node-playbook.yml │ ├── 2-jdk8-playbook.yml │ ├── 5-mysql-playbook.yml │ ├── 6-redis-playbook.yml │ ├── 1-install-basic-playbook.yml │ ├── 3-maven-playbook.yml │ └── 7-nginx-playbook.yml ├── shell │ └── runapp.sh └── postman │ └── tkey-sso-server-api_collection_2.1_format.json ├── client ├── dev-spring-security-client.md └── dev-rest-client.md ├── server ├── oauth-grant-type │ ├── README.md │ ├── token.md │ ├── client_credentials.md │ ├── password.md │ ├── code.md │ └── common.md ├── remote-debug.md └── dev.md ├── roadmap └── README.md ├── management ├── dev-backend.md └── dev-frontend.md ├── .editorconfig ├── SUMMARY.md ├── .gitignore ├── other ├── project-structure.md └── tkey-baisc.md ├── test └── performance.md ├── .gitattributes ├── faq └── README.md └── README.md /changelog/README.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | ## 1.0.0(2019-08-27) 4 | 5 | - 撒花上线 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /deployment/jar-runapp.md: -------------------------------------------------------------------------------- 1 | 2 | ## JAR 方式 3 | 4 | - [点击我查看整个过程 Gif 演示](http://img.gitnavi.com/tkey/tkey-runapp-jar.gif) 5 | - 把 jar 文件和 runapp.sh 上传到 /data/jar/tkey-sso-server 目录下 6 | - 给两个文件增加执行权限:`chmod +x runapp.sh tkey-sso-server-1.0.0.jar` 7 | - 运行命令:`sh runapp.sh start` 8 | - 如果需要调整目录位置、端口、启动参数(Redis 连接参数),可以自行修改 runapp.sh 文件,该脚本写得很简单,一般都可以看懂 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /share-file/playbook/test-playbook.yml: -------------------------------------------------------------------------------- 1 | - hosts: all 2 | remote_user: root 3 | tasks: 4 | - name : ansible-test 5 | shell : sleep 30 6 | async : 1000 7 | poll : 0 8 | register: kevin_result 9 | 10 | - name: 'check ansible-test task polling results ' 11 | async_status: jid={{ kevin_result.ansible_job_id }} 12 | register: job_result 13 | until: job_result.finished 14 | retries: 200 15 | -------------------------------------------------------------------------------- /client/dev-spring-security-client.md: -------------------------------------------------------------------------------- 1 | ## TKey Client 开发环境 2 | 3 | - [参考 TKey SSO Server 环境](https://github.com/cdk8s/tkey-docs/blob/master/server/dev.md) 4 | 5 | ## TKey Client 项目核心组件版本 6 | 7 | - [参考 TKey SSO Server 环境](https://github.com/cdk8s/tkey-docs/blob/master/server/dev.md) 8 | 9 | 10 | ## Spring Boot 1.5.x 和 2.1.x 的区别 11 | 12 | - Spring Boot 1.5.x 搭配 Spring Security 4 一起使用 13 | - Spring Boot 2.1.x 搭配 Spring Security 5 一起使用 14 | - Spring Security 4 和 5 变化比较大,所以分开了两个项目进行演示 15 | - 虽然 TKey SSO 支持 Spring Security OAuth2 客户端,但是因为 Spring Security 封装过多,较庞大,所以还是推荐你使用 TKey 自己的 Client,可以控制的细节内容会多得多 16 | -------------------------------------------------------------------------------- /deployment/docker-compose-runapp.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | ## Docker Compose 启动 TKey SSO Server + Redis 4 | 5 | - git clone 项目 6 | - 保持在项目根目录,输入:`mvn clean install -DskipTests` 7 | - 保持在项目根目录,输入:`docker-compose -f ./docker-compose-quickstart.yml up --build -d` 8 | 9 | ## 测试 10 | 11 | - cURL 测试结果: 12 | 13 | ``` 14 | curl -X POST \ 15 | http://sso.cdk8s.com:9091/sso/oauth/token \ 16 | -H 'Content-Type: application/x-www-form-urlencoded' \ 17 | -H 'cache-control: no-cache' \ 18 | -d 'grant_type=password&client_id=test_client_id_1&client_secret=test_client_secret_1&username=admin&password=123456' 19 | ``` 20 | -------------------------------------------------------------------------------- /deployment/micrometer.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | ## 相应组件部署 4 | 5 | - [部署说明](https://github.com/cdk8s/tkey-docs/blob/master/deployment/deployment-core.md) 6 | 7 | ## 引入 Prometheus 8 | 9 | ``` 10 | 11 | io.micrometer 12 | micrometer-registry-prometheus 13 | 14 | ``` 15 | 16 | 17 | 访问: 18 | 19 | 可以看到 prometheus 暴露出来的埋点信息 20 | 21 | 22 | ## Micrometer Tag 23 | 24 | ``` 25 | $instance - Instance Name 26 | $application - Spring Boot Application Name 27 | $hikaricp - HikariCP Connection Pool Name 28 | ``` 29 | 30 | -------------------------------------------------------------------------------- /server/oauth-grant-type/README.md: -------------------------------------------------------------------------------- 1 | 2 | ## 授权码模式 3 | 4 | - [点击我查看](https://github.com/cdk8s/tkey-docs/blob/master/server/oauth-grant-type/code.md) 5 | 6 | ## 密码模式 7 | 8 | - [点击我查看](https://github.com/cdk8s/tkey-docs/blob/master/server/oauth-grant-type/password.md) 9 | 10 | ## 简化模式 11 | 12 | - [点击我查看](https://github.com/cdk8s/tkey-docs/blob/master/server/oauth-grant-type/token.md) 13 | 14 | ## 客户端模式 15 | 16 | - [点击我查看](https://github.com/cdk8s/tkey-docs/blob/master/server/oauth-grant-type/client_credentials.md) 17 | 18 | ## 通用接口 19 | 20 | - [点击我查看](https://github.com/cdk8s/tkey-docs/blob/master/server/oauth-grant-type/common.md) 21 | -------------------------------------------------------------------------------- /server/remote-debug.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | ## 配置 IntelliJ IDEA 远程 Debug 4 | 5 | 6 | ![debug 配置](http://img.gitnavi.com/tkey/remote-debug-1.png) 7 | 8 | 9 | - **复制这个 VM 配置** 10 | 11 | ``` 12 | -agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=5005 13 | ``` 14 | 15 | 16 | ## 调整应用启动参数 17 | 18 | - 在 应用的原有 JAVA_OPTS 参数基础上补加,效果如下: 19 | 20 | ``` 21 | JAVA_OPTS="-Xms512m -Xmx2048m -agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=5005" 22 | ``` 23 | 24 | 25 | ## 启动本地项目 26 | 27 | ![debug 启动](http://img.gitnavi.com/tkey/remote-debug-2.png) 28 | 29 | - 然后在项目代码中打断点,跟平时本地 debug 一样 30 | 31 | 32 | ![debug 住断点效果](http://img.gitnavi.com/tkey/remote-debug-3.png) 33 | -------------------------------------------------------------------------------- /roadmap/README.md: -------------------------------------------------------------------------------- 1 | # Roadmap 2 | 3 | ## 1.0.1 4 | 5 | - 登录日志记录到 MySQL 6 | 7 | ## 1.0.2 8 | 9 | - 各类配置开关 10 | - 登录错误次数展示验证码 11 | 12 | ## 1.0.3 13 | 14 | - 企业微信扫码登录 15 | 16 | ## 1.0.4 17 | 18 | - 钉钉扫码登录 19 | 20 | ## 1.1.0 21 | 22 | - 普通微信扫码登录 23 | 24 | ## 1.1.1 25 | 26 | - QQ 登录 27 | 28 | ## 1.1.2 29 | 30 | - 微博登录 31 | 32 | ## 1.1.3 33 | 34 | - 小程序登录 35 | 36 | ## 1.1.4 37 | 38 | - 公众号登陆 39 | 40 | ## 1.1.5 41 | 42 | - 基于 K8S 整套方案发布 43 | 44 | ## 2.0.0 45 | 46 | - Github 登录 47 | - Google 登录 48 | - Facebook 登录 49 | - Twitter 登录 50 | 51 | ## 3.0.0 52 | 53 | - 自己 APP 的扫码登录 54 | - geetest 验证码 55 | - vaptcha 验证码 56 | - 多语言 57 | - 多因素认证 58 | - 人脸识别登录(旷视,腾讯AI) 59 | - LDAP 60 | -------------------------------------------------------------------------------- /management/dev-backend.md: -------------------------------------------------------------------------------- 1 | 2 | ## TKey Client Management 开发环境 3 | 4 | - [参考 TKey SSO Server 环境](https://github.com/cdk8s/tkey-docs/blob/master/server/dev.md) 5 | 6 | ## TKey Client Management 项目核心组件版本 7 | 8 | - [参考 TKey SSO Server 环境](https://github.com/cdk8s/tkey-docs/blob/master/server/dev.md) 9 | 10 | 11 | ## TKey Client Management Token 有效期设置 12 | 13 | 14 | 在没有 API 网关的情况下,各业务系统的 Token 是自己维护的。 15 | 16 | Client Management 的 Token 有效时长参数是:`token-max-time-to-live-in-seconds: 86400`,也就是 24 小时 17 | 18 | 如果你设置为 30 秒,其实也没事。用户体验上会出现:用户登录操作 30 秒之后,浏览器又重定向到 TKey SSO 重新生成了新 Token,整个过程依旧还是不需要用户重新输入账号密码。因为 TGC 的有效期很长。 19 | 20 | 21 | ## H2 数据库 22 | 23 | 为了方便开发,默认 `application-dev.yml` 是 H2 数据库。 24 | 25 | 为了生产 MySQL 的需要,也带有 `application-devmysql.yml`,大家可以自行切换 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | -------------------------------------------------------------------------------- /share-file/playbook/4-node-playbook.yml: -------------------------------------------------------------------------------- 1 | - hosts: all 2 | remote_user: root 3 | tasks: 4 | - name: remove the nodejs 5 | yum: 6 | name: nodejs 7 | state: absent 8 | 9 | - name: remove the npm 10 | yum: 11 | name: npm 12 | state: absent 13 | 14 | - name: curl node 15 | shell: "curl --silent --location https://rpm.nodesource.com/setup_12.x | sudo bash -" 16 | 17 | - name: install node 18 | command: "{{ item }}" 19 | with_items: 20 | - yum -y install nodejs 21 | 22 | - name: curl yarn 23 | shell: "curl --silent --location https://dl.yarnpkg.com/rpm/yarn.repo | sudo tee /etc/yum.repos.d/yarn.repo" 24 | 25 | - name: install yarn 26 | command: "{{ item }}" 27 | with_items: 28 | - yum -y install yarn 29 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | # http://editorconfig.org 2 | root = true 3 | 4 | [*] 5 | indent_style = space 6 | indent_size = 4 7 | charset = utf-8 8 | end_of_line = lf 9 | trim_trailing_whitespace = true 10 | insert_final_newline = true 11 | max_line_length = 300 12 | 13 | [*.{groovy,java,kt,kts}] 14 | indent_style = tab 15 | continuation_indent_size = 8 16 | 17 | [*.{xml,xsd}] 18 | indent_style = tab 19 | 20 | [Makefile] 21 | indent_style = tab 22 | 23 | [*.py] 24 | indent_size = 4 25 | 26 | [*.js] 27 | indent_size = 4 28 | 29 | [*.ts] 30 | indent_size = 4 31 | 32 | [*.html] 33 | indent_size = 4 34 | 35 | [*.{less,css}] 36 | indent_size = 2 37 | 38 | [*.json] 39 | indent_size = 2 40 | 41 | [*.{tsx,jsx}] 42 | indent_size = 2 43 | 44 | [*.yml] 45 | indent_size = 2 46 | 47 | [*.sql] 48 | indent_size = 2 49 | 50 | [*.md] 51 | insert_final_newline = false 52 | trim_trailing_whitespace = false 53 | -------------------------------------------------------------------------------- /client/dev-rest-client.md: -------------------------------------------------------------------------------- 1 | ## TKey Client 开发环境 2 | 3 | - [参考 TKey SSO Server 环境](https://github.com/cdk8s/tkey-docs/blob/master/server/dev.md) 4 | 5 | ## TKey Client 项目核心组件版本 6 | 7 | - [参考 TKey SSO Server 环境](https://github.com/cdk8s/tkey-docs/blob/master/server/dev.md) 8 | 9 | 10 | ## Maven 中央库已发布 11 | 12 | - 中央库地址: 13 | - Maven 14 | 15 | ``` 16 | 1.0.0 17 | 18 | 19 | 20 | com.cdk8s.tkey 21 | tkey-sso-client-starter-rest 22 | ${tkey-sso-client-starter-rest.version} 23 | 24 | ``` 25 | 26 | - Gradle Groovy DSL: 27 | 28 | ``` 29 | implementation 'com.cdk8s.tkey:tkey-sso-client-starter-rest:1.0.0' 30 | ``` 31 | 32 | - Gradle Kotlin DSL 33 | 34 | ``` 35 | compile("com.cdk8s.tkey:tkey-sso-client-starter-rest:1.0.0") 36 | ``` -------------------------------------------------------------------------------- /deployment/production-environment.md: -------------------------------------------------------------------------------- 1 | 2 | # 生产提醒 3 | 4 | - 请不要轻视安全问题,这是一个永远永远都要放心上的问题 5 | - 请结合该篇一起阅读: 6 | - 故意设计点(常见问题):[Github](https://github.com/cdk8s/tkey-docs/blob/master/faq/README.md)、[Gitee](https://gitee.com/cdk8s/tkey-docs/blob/master/faq/README.md) 7 | 8 | ## 必备要求 9 | 10 | 1. 全网 HTTPS,全网 HTTPS,全网 HTTPS 11 | 2. 不要明文存储用户密码,不要明文,不要明文(前端 MD5 后再传输) 12 | 4. Cookie 的 httpOnly 和 secure 都为 true 13 | 14 | 15 | ## 可以额外改造的 16 | 17 | 3. Token 绑定 IP 和 User-Agent 18 | 5. 客户端必传 state 防止 CSRF 19 | 5. 增加多因素认证 20 | 6. 增加异地登入审查 21 | 6. 分析异常登入记录 22 | 23 | ## 关于 Client 信息管理 24 | 25 | - 在 TKey Server 中有一个类:`ApplicationTestDataInitRunner.java` 会在本地开发环境、测试环境生成一个测试专用的 Client 26 | - 如果你已经准备上对外测试、生产记得梳理下 Client 的管理。默认是应该在 TKey Management 项目中进行管理 Client,而 TKey Server 只是读取 Client 27 | - TKey Management 中也有一个类:`ApplicationTestDataInitRunner.java` 会在本地开发环境、测试环境启动的时候读取 H2 数据库,初始化 Client 到 Redis 中 28 | - 以上两个人类都没有强加在 Prod 环境,担心开发者无意识地操作,造成生产事故,所以大家如果需要这个初始化,需要自己评估,并且开启在 Prod 环境下 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | -------------------------------------------------------------------------------- /server/oauth-grant-type/token.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | ## Postman 接口集分享 4 | 5 | - 链接地址: 6 | - [Postman 导入 TKey 接口集方法(Gif 动图)](http://img.gitnavi.com/tkey/postman-import-link.gif) 7 | - [Postman 接口转 cURL 方法(Gif 动图)](http://img.gitnavi.com/tkey/postman-to-curl.gif) 8 | 9 | ## 简化模式 10 | 11 | - **GET 请求** 12 | - 请求地址: 13 | - 参数: 14 | 15 | ``` 16 | response_type: token 17 | client_id: test_client_id_1 18 | redirect_uri: http://www.gitnavi.com 19 | ``` 20 | 21 | ### 浏览器访问 22 | 23 | - 24 | 25 | ### 请求参数合法,系统返回 26 | 27 | - 状态码 302 28 | - Location 29 | 30 | ``` 31 | http://www.gitnavi.com#access_token=AT-TxshSaBDm0RMxFEw1osvnFE7PIJmBvWU-103&token_type=Bearer&expires_in=57600&refresh_token=RT-WHD9vlVxiB4Q2XB0OnCrXHeLnptyIbPv-104 32 | ``` 33 | 34 | 35 | ### 请求参数不合法,系统返回 36 | 37 | - 停留在登录页面或跳转到 error 页面 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | -------------------------------------------------------------------------------- /share-file/playbook/2-jdk8-playbook.yml: -------------------------------------------------------------------------------- 1 | - hosts: all 2 | remote_user: root 3 | vars: 4 | java_install_folder: /usr/local 5 | file_name: jdk-8u261-linux-x64.tar.gz 6 | tasks: 7 | - name: copy jdk 8 | copy: 9 | src=/opt/{{ file_name }} 10 | dest={{ java_install_folder }} 11 | 12 | - name: tar jdk 13 | shell: 14 | chdir={{ java_install_folder }} 15 | tar zxf {{ file_name }} 16 | 17 | - name: set JAVA_HOME 18 | blockinfile: 19 | path: /root/.zshrc 20 | marker: "#{mark} JDK ENV" 21 | block: | 22 | JAVA_HOME={{ java_install_folder }}/jdk1.8.0_261 23 | JRE_HOME=$JAVA_HOME/jre 24 | PATH=$PATH:$JAVA_HOME/bin 25 | CLASSPATH=.:$JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar 26 | export JAVA_HOME 27 | export JRE_HOME 28 | export PATH 29 | export CLASSPATH 30 | 31 | - name: source zshrc 32 | shell: source /root/.zshrc 33 | 34 | - name: remove tar.gz file 35 | file: 36 | state: absent 37 | path: "{{ java_install_folder }}/{{ file_name }}" 38 | -------------------------------------------------------------------------------- /SUMMARY.md: -------------------------------------------------------------------------------- 1 | * 认识阶段 (必读) 2 | * [单点登录系统认知与基础介绍](other/tkey-baisc.md) 3 | * [故意设计点(常见问题)](faq/README.md) 4 | * [项目结构与端口占用](other/project-structure.md) 5 | * [OAuth2.0 四种模式](server/oauth-grant-type/README.md) 6 | * [JAR 方式部署](deployment/jar-runapp.md) 7 | * [Docker 方式部署](deployment/docker-runapp.md) 8 | * [Docker Compose 方式部署](deployment/docker-compose-runapp.md) 9 | * TKey Server 开发阶段 10 | * [开发改造引导](server/dev.md) 11 | * TKey Management 开发阶段(也是前后端分离的最佳实践示例) 12 | * [后端开发改造引导](management/dev-backend.md) 13 | * [前端开发改造引导](management/dev-frontend.md) 14 | * TKey Client Java 开发阶段 15 | * [自己封装的 REST Client](client/dev-rest-client.md) 16 | * [Spring Security 支持](client/dev-spring-security-client.md) 17 | * 测试阶段 18 | * 单元测试 19 | * [压力测试](test/performance.md) 20 | * 部署阶段 21 | * [生产注意事项](deployment/production-environment.md) 22 | * [部署环境搭建](deployment/deployment-core.md) 23 | * 监控阶段 24 | * [Spring Boot Micrometer](deployment/micrometer.md) 25 | * 其他工具全在 `部署环境搭建`,请自行查看 26 | * 线上问题诊断 27 | * [Actuator 在线修改 log 输出级别(Gif 动图)](http://img.gitnavi.com/tkey/actuator-update-log-level.gif) 28 | * [Arthas 诊断 Docker 应用](https://alibaba.github.io/arthas/docker.html#dockerjava) 29 | * [夜间开放端口,挑选流量远程 Debug](server/remote-debug.md) -------------------------------------------------------------------------------- /deployment/docker-runapp.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | ## 手工构建镜像 4 | 5 | - git clone 项目 6 | - 保持在项目根目录,输入:`mvn clean install -DskipTests` 7 | - 保持在项目根目录,输入:`docker build . -t cdk8s/tkey-sso-server` 8 | - 查看镜像大小:`docker images` 9 | 10 | ``` 11 | cdk8s/tkey-sso-server latest e0eefff8590b 4 seconds ago 205MB 12 | ``` 13 | 14 | 15 | ## 启动 TKey SSO Server(使用外部 Redis) 16 | 17 | - 启动容器:(挂载路径大家自行修改) 18 | 19 | ``` 20 | docker run -d \ 21 | -p 9091:9091 \ 22 | --add-host redis.cdk8s.com:192.168.0.107 \ 23 | --name=tkey-sso-server --hostname=tkey-sso-server \ 24 | --restart=unless-stopped \ 25 | -v /Users/youmeek/docker_data/logs/:/logs/ \ 26 | -v /Users/youmeek/docker_data/headDump/:/data/headDump/ \ 27 | -e SPRING_PROFILES_ACTIVE=test \ 28 | -e SPRING_REDIS_DATABASE=0 \ 29 | -e SPRING_REDIS_PORT=6379 \ 30 | -e SPRING_REDIS_HOST=redis.cdk8s.com \ 31 | -e SPRING_REDIS_PASSWORD=123456 \ 32 | -e TKEY_NODE_NUMBER=10 \ 33 | -e JAVA_OPTS="-Xms1024m -Xmx1024m -XX:MetaspaceSize=124m -XX:MaxMetaspaceSize=224m -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/data/headDump" \ 34 | cdk8s/tkey-sso-server:latest 35 | ``` 36 | 37 | ## 测试 38 | 39 | - cURL 测试结果: 40 | 41 | ``` 42 | curl -X POST \ 43 | http://sso.cdk8s.com:9091/sso/oauth/token \ 44 | -H 'Content-Type: application/x-www-form-urlencoded' \ 45 | -H 'cache-control: no-cache' \ 46 | -d 'grant_type=password&client_id=test_client_id_1&client_secret=test_client_secret_1&username=admin&password=123456' 47 | ``` -------------------------------------------------------------------------------- /server/oauth-grant-type/client_credentials.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | ## Postman 接口集分享 4 | 5 | - 链接地址: 6 | - [Postman 导入 TKey 接口集方法(Gif 动图)](http://img.gitnavi.com/tkey/postman-import-link.gif) 7 | - [Postman 接口转 cURL 方法(Gif 动图)](http://img.gitnavi.com/tkey/postman-to-curl.gif) 8 | 9 | ## 客户端模式 10 | 11 | - **GET 请求** 12 | - 请求地址: 13 | - 参数: 14 | 15 | ``` 16 | grant_type: client_credentials 17 | client_id: test_client_id_1 18 | client_secret: test_client_secret_1 19 | ``` 20 | 21 | - 也支持请求头验证 client:`Authorization: Basic dGVzdF9jbGllbnRfaWRfMTp0ZXN0X2NsaWVudF9zZWNyZXRfMQ==` 22 | 23 | 24 | ### cURL 25 | 26 | ``` 27 | curl -X GET \ 28 | 'http://sso.cdk8s.com:9091/sso/oauth/token?grant_type=client_credentials&client_id=test_client_id_1&client_secret=test_client_secret_1' \ 29 | -H 'cache-control: no-cache' 30 | ``` 31 | 32 | 33 | ### 请求参数合法,系统返回 34 | 35 | - 状态码 200 36 | - JSON 数据 37 | 38 | ``` 39 | { 40 | "access_token": "AT-102-dJTLEsFLR2PbxU1l8GPx3CUS9O3Lhzdn", 41 | "token_type": "Bearer", 42 | "expires_in": 57600, 43 | "refresh_token": "RT-mTeOPJHDbcDeeUhRM0V52giRgiisu6ar-102" 44 | } 45 | ``` 46 | 47 | 48 | ### 请求参数不合法,系统返回 49 | 50 | - 状态码 400 51 | - JSON 数据 52 | 53 | ``` 54 | { 55 | "error": "invalid request", 56 | "error_description": "请求类型不匹配", 57 | "error_uri_msg": "See the full API docs at https://github.com/cdk8s" 58 | } 59 | ``` 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | -------------------------------------------------------------------------------- /management/dev-frontend.md: -------------------------------------------------------------------------------- 1 | 2 | ## TKey Client Management 开发环境 3 | 4 | - [参考 TKey SSO Server 环境](https://github.com/cdk8s/tkey-docs/blob/master/server/dev.md) 5 | 6 | ## TKey Client Management 项目核心组件版本 7 | 8 | - 依赖包完整列表 package.json:[Github](https://github.com/cdk8s/tkey-management-frontend/blob/master/package.json)、[Gitee](https://gitee.com/cdk8s/tkey-management-frontend/blob/master/package.json) 9 | 10 | ------------------------------------------------------------------- 11 | 12 | ## 前后端分离的场景特别说明 13 | 14 | ### 相同二级域名 15 | 16 | - 前端:f.cdk8s.com 17 | - 后端:b.cdk8s.com 18 | - 这种场景下,后端可以通过写入 `.cdk8s.com` Cookie 的方式来存储 Token,前端也可以拿到 Token 19 | - 但是,在前后端分离情况下我更建议采用下面 `不同二级域名` 的解决办法 20 | 21 | 22 | ### 不同二级域名 23 | 24 | - 前端:f.ffffff.com 25 | - 后端:b.bbbbbb.com 26 | - 这种场景下,Cookie 方式不可用 27 | - 只能把 code 的回调地址写成前端系统,前端拿到 code 之后转发给后端,后端把 code 换取到 token 再 response 给前端,前端可以选择存储到 localstorage 中 28 | - 这种方式麻烦的地方在于:本地环境、开发环境、测试环境、生产环境的回调配置 29 | 30 | ------------------------------------------------------------------- 31 | 32 | ## 常量参数 33 | 34 | - **在该文件中配置了不同环境的各种需要配置的请求地址** 35 | - globalConstant.ts 36 | 37 | ## 本地环境使用 38 | 39 | - `.umirc.ts` 40 | 41 | 42 | ``` 43 | yarn install 44 | 45 | yarn start 46 | 47 | yarn build 48 | ``` 49 | 50 | 51 | ## 测试环境使用 52 | 53 | - `.umirc.test.ts` 54 | 55 | ``` 56 | yarn install 57 | 58 | yarn start:test 59 | 60 | yarn build:test 61 | ``` 62 | 63 | 64 | ## 生产环境使用 65 | 66 | - `.umirc.prod.ts` 67 | 68 | ``` 69 | yarn install 70 | 71 | yarn start:prod 72 | 73 | yarn build:prod 74 | ``` 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | -------------------------------------------------------------------------------- /server/oauth-grant-type/password.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | ## Postman 接口集分享 4 | 5 | - 链接地址: 6 | - [Postman 导入 TKey 接口集方法(Gif 动图)](http://img.gitnavi.com/tkey/postman-import-link.gif) 7 | - [Postman 接口转 cURL 方法(Gif 动图)](http://img.gitnavi.com/tkey/postman-to-curl.gif) 8 | 9 | ## 密码模式 10 | 11 | - **POST 请求** 12 | - 请求地址: 13 | - 参数: 14 | 15 | ``` 16 | grant_type: password 17 | client_id: test_client_id_1 18 | client_secret: test_client_secret_1 19 | username: admin 20 | password: 123456 21 | 22 | ``` 23 | 24 | - 也支持请求头验证 client:`Authorization: Basic dGVzdF9jbGllbnRfaWRfMTp0ZXN0X2NsaWVudF9zZWNyZXRfMQ==` 25 | 26 | ### cURL 27 | 28 | 29 | ``` 30 | curl -X POST \ 31 | http://sso.cdk8s.com:9091/sso/oauth/token \ 32 | -H 'Content-Type: application/x-www-form-urlencoded' \ 33 | -H 'cache-control: no-cache' \ 34 | -d 'grant_type=password&client_id=test_client_id_1&client_secret=test_client_secret_1&username=admin&password=123456' 35 | ``` 36 | 37 | ### 请求参数合法,系统返回 38 | 39 | - 状态码 200 40 | - JSON 数据 41 | 42 | ``` 43 | { 44 | "access_token": "AT-MISqrbWUxFWc1xU4e8JK2OcMgJYusF22-101", 45 | "token_type": "Bearer", 46 | "expires_in": 57600, 47 | "refresh_token": "RT-7UPY41g9j5K8rKBZse4qo4iP6sAbU2Df-102" 48 | } 49 | ``` 50 | 51 | 52 | ### 请求参数不合法,系统返回 53 | 54 | - 状态码 400 55 | - JSON 数据 56 | 57 | ``` 58 | { 59 | "error": "invalid request", 60 | "error_description": "请求类型不匹配", 61 | "error_uri_msg": "See the full API docs at https://github.com/cdk8s" 62 | } 63 | ``` 64 | 65 | ### 用户名密码有问题,系统返回 66 | 67 | - 状态码 400 68 | - JSON 数据 69 | 70 | ``` 71 | { 72 | "error": "invalid request", 73 | "error_description": "用户名或密码错误", 74 | "error_uri_msg": "See the full API docs at https://github.com/cdk8s" 75 | } 76 | ``` 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | out/ 2 | target/ 3 | node_modules/ 4 | classes/ 5 | .deploy*/ 6 | .gradle 7 | *.log.* 8 | *.log 9 | 10 | # ====================================================== 11 | 12 | ### STS ### 13 | .apt_generated 14 | .classpath 15 | .factorypath 16 | .project 17 | .settings 18 | .springBeans 19 | 20 | ### IntelliJ IDEA ### 21 | .idea 22 | *.iws 23 | *.iml 24 | *.ipr 25 | 26 | ### NetBeans ### 27 | nbproject/private/ 28 | build/ 29 | nbbuild/ 30 | dist/ 31 | nbdist/ 32 | .nb-gradle/ 33 | 34 | # ====================================================== 35 | 36 | # Windows image file caches 37 | Thumbs.db 38 | ehthumbs.db 39 | 40 | # Folder config file 41 | Desktop.ini 42 | 43 | # Recycle Bin used on file shares 44 | $RECYCLE.BIN/ 45 | 46 | # Windows Installer files 47 | *.cab 48 | *.msi 49 | *.msm 50 | *.msp 51 | 52 | # Windows shortcuts 53 | *.lnk 54 | 55 | # ====================================================== 56 | 57 | # OSX 58 | .DS_Store 59 | .AppleDouble 60 | .LSOverride 61 | 62 | # Thumbnails 63 | ._* 64 | 65 | # Files that might appear in the root of a volume 66 | .DocumentRevisions-V100 67 | .fseventsd 68 | .Spotlight-V100 69 | .TemporaryItems 70 | .Trashes 71 | .VolumeIcon.icns 72 | 73 | # Directories potentially created on remote AFP share 74 | .AppleDB 75 | .AppleDesktop 76 | Network Trash Folder 77 | Temporary Items 78 | .apdisk 79 | 80 | # ====================================================== 81 | 82 | npm-debug.log* 83 | yarn-error.log 84 | .idea/ 85 | .ipr 86 | .iws 87 | *~ 88 | ~* 89 | *.diff 90 | *.patch 91 | *.bak 92 | .*proj 93 | .svn/ 94 | *.swp 95 | *.swo 96 | *.json.gzip 97 | .buildpath 98 | nohup.out 99 | dist 100 | *.tmp 101 | 102 | # ====================================================== 103 | 104 | .DS_STORE 105 | *.pyc 106 | remote-repo/ 107 | coverage/ 108 | .module-cache 109 | *.log* 110 | chrome-user-data 111 | *.sublime-project 112 | *.sublime-workspace 113 | .vscode 114 | 115 | -------------------------------------------------------------------------------- /other/project-structure.md: -------------------------------------------------------------------------------- 1 | 2 | # 项目结构与占用端口 3 | 4 | ## TKey Docs 5 | 6 | - 文档集中维护 7 | - Github: 8 | - Gitee: 9 | 10 | ## TKey SSO Server 11 | 12 | - TKey 单点登录核心系统 13 | - Github: 14 | - Gitee: 15 | - 占用端口 16 | - 9091 17 | - 19091 18 | 19 | ## TKey SSO Client Management 20 | 21 | - TKey Client 管理系统(后端) 22 | - Github: 23 | - Gitee: 24 | - 占用端口 25 | - 9095 26 | - 19095 27 | 28 | ## TKey SSO Client Management Frontend(React) 29 | 30 | - TKey Client 管理系统(前端) 31 | - Github: 32 | - Gitee: 33 | - 占用端口 34 | - 8000 35 | 36 | ## TKey Issues 37 | 38 | - 统一的 issues 提问入口 39 | - Github: 40 | - Gitee: 41 | 42 | ## TKey Test 43 | 44 | - 压力测试脚本 45 | - Github: 46 | - Gitee: 47 | 48 | ## TKey SSO Client Java 49 | 50 | - 我们自己封装的 Java 客户端以及 demo 51 | - Github: 52 | - Gitee: 53 | - 占用端口 54 | - 9094 55 | 56 | ## TKey SSO Client Spring Security 57 | 58 | - 基于 Spring Security OAuth 做客户端 59 | - Github: 60 | - Gitee: 61 | - Spring Boot 2.1.x 62 | - 占用端口 63 | - 9092 64 | 65 | - Spring Boot 1.5.x 66 | - 占用端口 67 | - 9093 68 | 69 | 70 | ## TKey SSO Client Management Frontend(Vue) 71 | 72 | ## TKey SSO Client Management Frontend(Angular) 73 | 74 | ## TKey SSO Client Python 75 | 76 | ## TKey SSO Client Go 77 | 78 | ## TKey SSO Client PHP 79 | 80 | ## TKey SSO Client C Sharp 81 | 82 | ## TKey SSO Client Node 83 | 84 | ## TKey SSO Client Ruby 85 | 86 | 87 | 88 | -------------------------------------------------------------------------------- /test/performance.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | # TKey SSO Server 压力测试 4 | 5 | ## Gatling 方式压力测试 6 | 7 | - 不带参数运行命令: 8 | 9 | ``` 10 | mvn gatling:test -Dgatling.simulationClass=test.load.oauth.TkeyPasswordGrantType 11 | ``` 12 | 13 | 14 | - 带参数运行命令: 15 | 16 | ``` 17 | mvn gatling:test -Dgatling.simulationClass=test.load.oauth.TkeyPasswordGrantType -DtotalConcurrency=1000 -DrepeatTime=10 -DinjectTime=10 18 | ``` 19 | 20 | ------------------------------------------------------------------- 21 | 22 | 23 | ## JMeter 5.1 方式压力测试 24 | 25 | - 如果 JVM 不够可以修改 bin/jmeter 文件中的:`"${HEAP:="-Xms1g -Xmx1g -XX:MaxMetaspaceSize=256m"}"` 26 | 27 | ``` 28 | cd /Users/youmeek/software/apache-jmeter-5.1.1/bin 29 | 30 | ./jmeter -n -t /Users/youmeek/TkeyPasswordGrantTypeJMeter.jmx -l /Users/youmeek/tkeyReport.jtl -e -o /Users/youmeek/htmlResult 31 | ``` 32 | 33 | ------------------------------------------------------------------- 34 | 35 | ## wrk 简单压力测试 36 | 37 | 38 | ``` 39 | sudo yum groupinstall 'Development Tools' 40 | sudo yum install -y openssl-devel git 41 | 42 | git clone --depth=1 https://github.com/wg/wrk.git wrk 43 | cd wrk 44 | make 45 | 46 | sudo cp wrk /usr/local/bin 47 | ``` 48 | 49 | ``` 50 | wrk -t5 -c5 -d10s --script=/opt/post-wrk.lua --latency http://sso.cdk8s.com/sso/oauth/token 51 | ``` 52 | 53 | - post-wrk.lua 54 | 55 | ``` 56 | wrk.method = "POST" 57 | wrk.body = "grant_type=password&client_id=test_client_id_1&client_secret=test_client_secret_1&username=admin&password=123456" 58 | wrk.headers["Content-Type"] = "application/x-www-form-urlencoded" 59 | ``` 60 | 61 | 62 | ------------------------------------------------------------------- 63 | 64 | ## 如何继续提高 QPS 65 | 66 | 在压力测试过程中我们用 JProfile 监控了 CPU 情况,具体如下图: 67 | 68 | ![JProfile CPU](http://img.gitnavi.com/tkey/tkey-jprofile-cpu.png) 69 | 70 | 经过上图我们已经有明确的答案:`checkClientIdParam()` 71 | 72 | 在校验 client 正确性的地方,读取了 redis,这个过程如果用二级缓存,经过我们压力测试可以再提高 15~20% 左右的 QPS。但是这样改造复杂度会提高,如果 TKey SSO Server 是多节点情况下,同步变更是个麻烦事,还要再引入 MQ,我觉得不划算。中小企业不建议为了这点性能提高系统复杂度。 73 | 74 | 对于中小企业发展,最核心的还是走对业务,能有一个随时掉头,变更方向的能力,所以系统复杂度一定要尽可能不高,或者契合当前企业的发展情况。 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | -------------------------------------------------------------------------------- /share-file/shell/runapp.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # 记得给 sh 增加执行权限:chmod +x jar.sh 4 | pid=0 5 | ENV=test 6 | LOG_DATE=`date +%Y%m%d%H%M%S` 7 | APP_NAME=tkey-sso-server 8 | JAR_NAME=tkey-sso-server-1.0.0.jar 9 | APP_PATH=/data/jar/$APP_NAME 10 | APP_LOG_PATH=/data/jar/$APP_NAME/logs 11 | 12 | DUMP_PATH=$APP_PATH/headDump 13 | LOG_PATH=$APP_LOG_PATH/$APP_NAME.out 14 | JAR_FILE=$APP_PATH/$JAR_NAME 15 | 16 | APP_ENVIRONMENT="--SPRING_PROFILES_ACTIVE=$ENV --SERVER_PORT=9091 --SPRING_REDIS_HOST=redis.cdk8s.com --SPRING_REDIS_PASSWORD=123456 --TKEY_NODE_NUMBER=20" 17 | 18 | # JVM 参数 19 | JAVA_OPTS="$APP_ENVIRONMENT -Xms1024m -Xmx1024m -XX:MetaspaceSize=124m -XX:MaxMetaspaceSize=224m -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=$DUMP_PATH" 20 | 21 | # 支持远程 debug 22 | #JAVA_OPTS="$APP_ENVIRONMENT -Xms1024m -Xmx1024m -XX:MetaspaceSize=124m -XX:MaxMetaspaceSize=224m -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=$DUMP_PATH -agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=5005" 23 | 24 | 25 | if [ ! -d $APP_LOG_PATH ]; then 26 | mkdir -p $APP_LOG_PATH 27 | fi 28 | 29 | 30 | start(){ 31 | getpid 32 | if [ ! -n "$pid" ]; then 33 | nohup java -jar $JAR_FILE $JAVA_OPTS > $LOG_PATH 2>&1 & 34 | echo "----------------------------" 35 | echo "Application Startup Success" 36 | echo "----------------------------" 37 | sleep 2s 38 | tail -f $LOG_PATH 39 | else 40 | echo "$APP_NAME is runing PID: $pid" 41 | fi 42 | 43 | } 44 | 45 | status(){ 46 | getpid 47 | if [ ! -n "$pid" ]; then 48 | echo "$APP_NAME not runing" 49 | else 50 | echo "$APP_NAME runing PID: $pid" 51 | fi 52 | } 53 | 54 | stop(){ 55 | getpid 56 | if [ ! -n "$pid" ]; then 57 | echo "$APP_NAME not runing" 58 | else 59 | echo "$APP_NAME stop" 60 | kill -9 $pid 61 | fi 62 | } 63 | 64 | restart(){ 65 | stop 66 | sleep 2s 67 | start 68 | } 69 | 70 | getpid(){ 71 | pid=`ps -ef |grep $JAR_FILE |grep -v grep |awk '{print $2}'` 72 | } 73 | 74 | case $1 in 75 | start) start;; 76 | stop) stop;; 77 | restart) restart;; 78 | status) status;; 79 | *) echo "shell parameter: start|stop|restart|status" ;; 80 | esac 81 | -------------------------------------------------------------------------------- /share-file/playbook/5-mysql-playbook.yml: -------------------------------------------------------------------------------- 1 | - hosts: all 2 | remote_user: root 3 | tasks: 4 | - name: remove the mariadb 5 | yum: 6 | name: mariadb 7 | state: absent 8 | 9 | - name: install mysql 1 10 | shell: "{{ item }}" 11 | with_items: 12 | - wget http://dev.mysql.com/get/mysql57-community-release-el7-11.noarch.rpm 13 | - yum localinstall -y mysql57-community-release-el7-11.noarch.rpm 14 | 15 | - name : install mysql 2 16 | yum: 17 | name: mysql-community-server 18 | async : 1000 19 | poll : 0 20 | register: mysql_install_result 21 | 22 | - name: 'check install result' 23 | async_status: jid={{ mysql_install_result.ansible_job_id }} 24 | register: job_mysql_install_result 25 | until: job_mysql_install_result.finished 26 | retries: 250 27 | 28 | - name: remove old /etc/my.cnf 29 | file: 30 | path: "/etc/my.cnf" 31 | state: absent 32 | 33 | - name: create my.cnf file 34 | file: 35 | path="/etc/{{ item }}" 36 | state=touch 37 | with_items: 38 | - my.cnf 39 | 40 | - name: set my.cnf 41 | blockinfile: 42 | path: /etc/my.cnf 43 | marker: "" 44 | block: | 45 | [mysql] 46 | default-character-set = utf8mb4 47 | [mysqld] 48 | max_connections = 500 49 | datadir = /var/lib/mysql 50 | socket = /var/lib/mysql/mysql.sock 51 | bind-address = 127.0.0.1 52 | symbolic-links=0 53 | log-error=/var/log/mysqld.log 54 | pid-file=/var/run/mysqld/mysqld.pid 55 | default-storage-engine = InnoDB 56 | collation-server = utf8mb4_unicode_520_ci 57 | init_connect = 'SET NAMES utf8mb4' 58 | character-set-server = utf8mb4 59 | lower_case_table_names = 1 60 | max_allowed_packet = 50M 61 | sql_mode=STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION 62 | 63 | - name: enable mysql 64 | shell: "{{ item }}" 65 | with_items: 66 | - systemctl enable mysqld.service 67 | - systemctl restart mysqld.service 68 | -------------------------------------------------------------------------------- /server/dev.md: -------------------------------------------------------------------------------- 1 | 2 | ## TKey 开发环境 3 | 4 | - 系统环境 5 | - macOS High Sierra 10.13.6 6 | - 后端 7 | - IntelliJ IDEA 2019.2 8 | - Oracle JDK 1.8.0_191 9 | - Maven 3.6.1 10 | - Redis 4(Docker Image) 11 | - Prometheus 2.11(Docker Image) 12 | - Grafana 6.2.5(Docker Image) 13 | - MySQL 5.7(Docker Image) 14 | - Postman 7.5.0 15 | - JMeter 5.1.1 16 | - Jenkins 2.176.2 17 | - JProfiler 11.0.1 18 | - Docker version 18.09.2 19 | - Docker Desktop 2.0.0.3 20 | - 前端 21 | - WebStorm 2019.2 22 | - Node 10.14.2 23 | - npm 6.4.1 24 | - Yarn 1.12.3 25 | 26 | ## TKey 项目核心组件版本(版本号 pom.xml 为准) 27 | 28 | - 依赖包完整列表 [pom.xml](https://github.com/cdk8s/tkey/blob/master/pom.xml) 29 | - 核心:`Spring Boot 2.1.7.RELEASE` 30 | - 其他(后续以 pom.xml 文件为主): 31 | 32 | ``` 33 | 3.8.1 34 | 1.5 35 | 4.2 36 | 2.6 37 | 1.11 38 | 39 | 27.0.1-jre 40 | 3.12.1 41 | 4.5.13 42 | ``` 43 | 44 | 45 | 46 | ## 推荐使用 Postman 进行尝试性的接口测试 47 | 48 | 49 | - Postman 的设置 302 重定向:`Settings > General > Automatically follow redirects` 50 | 51 | 默认是:ON,如果需要查看 302 的跳转中间状态,需要关闭为 OFF,不然在调试的时候如果客户端服务已经关闭,则只会看到报错信息,但是不知道是具体什么报错。 52 | 53 | - Postman 导入我们已经准备好的请求参数,避免你直接摸索 54 | 55 | 链接地址: 56 | 57 | - [Postman 导入 TKey 接口集方法(Gif 动图)](http://img.gitnavi.com/tkey/postman-import-link.gif) 58 | - [Postman 接口转 cURL 方法(Gif 动图)](http://img.gitnavi.com/tkey/postman-to-curl.gif) 59 | 60 | ## Docker 环境 61 | 62 | - 如果你还没有 Docker 环境,建议查看我们此系列教程:[CentOS 操作系统](https://github.com/cdk8s/cdk8s-team-style/tree/master/os/linux) 63 | - TKey SSO Server 需要 Redis,Redis 信息可以在该文件进行修改:`application-dev.yml` 64 | 65 | ## 核心的用户校验逻辑 66 | 67 | - 在 OauthController.java 类中 68 | - 这里采用的是 REST API 校验,如果你们要直连数据库,可以在改写该逻辑 69 | - 至于为什么要这么设计,已经在下面文章进行了说明 70 | - 故意设计点(常见问题):[Github](https://github.com/cdk8s/tkey-docs/blob/master/faq/README.md)、[Gitee](https://gitee.com/cdk8s/tkey-docs/blob/master/faq/README.md) 71 | 72 | 73 | ``` 74 | OauthUserAttribute oauthUserAttribute = requestLoginApi(oauthFormLoginParam); 75 | ``` 76 | 77 | ## 登录页面改造 78 | 79 | - TKey SSO Server 没有采用前后端分离,目前考虑是没有必要,就一个登录页面 80 | - 使用的是 Thymeleaf 模板引擎 81 | - 登录页面路径:`/resources/templates/login.html` 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | -------------------------------------------------------------------------------- /share-file/playbook/6-redis-playbook.yml: -------------------------------------------------------------------------------- 1 | - hosts: all 2 | remote_user: root 3 | tasks: 4 | - name: install redis 5 | yum: 6 | name: redis 7 | 8 | - name: remove old /etc/redis.conf 9 | file: 10 | path: "/etc/redis.conf" 11 | state: absent 12 | 13 | - name: create /etc/redis.conf file 14 | file: 15 | path="/etc/{{ item }}" 16 | state=touch 17 | mode=777 18 | with_items: 19 | - redis.conf 20 | 21 | - name: set redis.conf 22 | blockinfile: 23 | path: /etc/redis.conf 24 | marker: "" 25 | block: | 26 | bind 0.0.0.0 27 | requirepass adgredis123456 28 | protected-mode yes 29 | port 6379 30 | tcp-backlog 511 31 | timeout 0 32 | tcp-keepalive 300 33 | daemonize no 34 | supervised no 35 | pidfile /var/run/redis_6379.pid 36 | loglevel notice 37 | logfile /var/log/redis/redis.log 38 | databases 16 39 | save 900 1 40 | save 300 10 41 | save 60 10000 42 | stop-writes-on-bgsave-error yes 43 | rdbcompression yes 44 | rdbchecksum yes 45 | dbfilename dump.rdb 46 | dir /var/lib/redis 47 | slave-serve-stale-data yes 48 | slave-read-only yes 49 | repl-diskless-sync no 50 | repl-diskless-sync-delay 5 51 | repl-disable-tcp-nodelay no 52 | slave-priority 100 53 | appendonly no 54 | appendfilename "appendonly.aof" 55 | appendfsync everysec 56 | no-appendfsync-on-rewrite no 57 | auto-aof-rewrite-percentage 100 58 | auto-aof-rewrite-min-size 64mb 59 | aof-load-truncated yes 60 | lua-time-limit 5000 61 | slowlog-log-slower-than 10000 62 | slowlog-max-len 128 63 | latency-monitor-threshold 0 64 | notify-keyspace-events "" 65 | hash-max-ziplist-entries 512 66 | hash-max-ziplist-value 64 67 | list-max-ziplist-size -2 68 | list-compress-depth 0 69 | set-max-intset-entries 512 70 | zset-max-ziplist-entries 128 71 | zset-max-ziplist-value 64 72 | hll-sparse-max-bytes 3000 73 | activerehashing yes 74 | client-output-buffer-limit normal 0 0 0 75 | client-output-buffer-limit slave 256mb 64mb 60 76 | client-output-buffer-limit pubsub 32mb 8mb 60 77 | hz 10 78 | aof-rewrite-incremental-fsync yes 79 | 80 | - name: enable redis 81 | shell: "{{ item }}" 82 | with_items: 83 | - systemctl enable redis 84 | - systemctl restart redis 85 | -------------------------------------------------------------------------------- /share-file/playbook/1-install-basic-playbook.yml: -------------------------------------------------------------------------------- 1 | - hosts: all 2 | remote_user: root 3 | tasks: 4 | - name: Disable SELinux at next reboot 5 | selinux: 6 | state: disabled 7 | 8 | - name: disable firewalld 9 | command: "{{ item }}" 10 | with_items: 11 | - systemctl stop firewalld 12 | - systemctl disable firewalld 13 | - echo "vm.swappiness = 0" >> /etc/sysctl.conf 14 | - swapoff -a 15 | - sysctl -w vm.swappiness=0 16 | 17 | - name: install-epel 18 | command: "{{ item }}" 19 | with_items: 20 | - yum install -y epel-release 21 | 22 | - name: install-basic 23 | command: "{{ item }}" 24 | with_items: 25 | - yum install -y zip unzip lrzsz git wget htop deltarpm 26 | 27 | - name: install zsh oh-my-zsh 28 | shell: "{{ item }}" 29 | with_items: 30 | - yum install -y zsh 31 | - wget https://gitee.com/mirrors/oh-my-zsh/raw/master/tools/install.sh -O - | sh 32 | - chsh -s /bin/zsh root 33 | 34 | - name: install zsh plugin 35 | shell: "{{ item }}" 36 | with_items: 37 | - git clone https://github.com/zsh-users/zsh-autosuggestions.git ${ZSH_CUSTOM:-~/.oh-my-zsh/custom}/plugins/zsh-autosuggestions 38 | - git clone https://github.com/zsh-users/zsh-syntax-highlighting.git ${ZSH_CUSTOM:-~/.oh-my-zsh/custom}/plugins/zsh-syntax-highlighting 39 | 40 | - name: replace zshrc theme 41 | lineinfile: 42 | path: /root/.zshrc 43 | regexp: '^ZSH_THEME=' 44 | line: ZSH_THEME="af-magic" 45 | 46 | - name: replace zshrc plugins 47 | lineinfile: 48 | path: /root/.zshrc 49 | regexp: '^plugins=' 50 | line: plugins=(git zsh-autosuggestions zsh-syntax-highlighting) 51 | 52 | 53 | - name: install-vim 54 | shell: "{{ item }}" 55 | with_items: 56 | - yum install -y vim 57 | - curl https://raw.githubusercontent.com/wklken/vim-for-server/master/vimrc > ~/.vimrc 58 | 59 | - name: install-docker 60 | shell: "{{ item }}" 61 | with_items: 62 | - yum install -y yum-utils device-mapper-persistent-data lvm2 63 | - yum-config-manager --add-repo http://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo 64 | - yum makecache fast 65 | - yum install -y docker-ce docker-ce-cli containerd.io 66 | - systemctl start docker.service 67 | 68 | - name: create /etc/docker directory 69 | file: 70 | path: /etc/docker 71 | state: directory 72 | 73 | - name: create daemon.json file 74 | file: 75 | path=/etc/docker/{{ item }} 76 | state=touch 77 | mode=777 78 | with_items: 79 | - daemon.json 80 | 81 | - name: set docker registry mirrors 82 | blockinfile: 83 | path: /etc/docker/daemon.json 84 | marker: "" 85 | block: | 86 | { 87 | "registry-mirrors": [ 88 | "https://ldhc17y9.mirror.aliyuncs.com", 89 | "https://hub-mirror.c.163.com", 90 | "https://mirror.baidubce.com", 91 | "https://docker.mirrors.ustc.edu.cn" 92 | ] 93 | } 94 | 95 | - name: restart docekr 96 | shell: "{{ item }}" 97 | with_items: 98 | - systemctl daemon-reload 99 | - systemctl restart docker 100 | 101 | - name: install-docker-compose 102 | shell: "{{ item }}" 103 | with_items: 104 | - curl -L https://get.daocloud.io/docker/compose/releases/download/1.26.2/docker-compose-`uname -s`-`uname -m` > /usr/local/bin/docker-compose 105 | - chmod +x /usr/local/bin/docker-compose 106 | - docker-compose --version 107 | - systemctl restart docker.service 108 | - systemctl enable docker.service 109 | -------------------------------------------------------------------------------- /server/oauth-grant-type/code.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | ## Postman 接口集分享 4 | 5 | - 链接地址: 6 | - [Postman 导入 TKey 接口集方法(Gif 动图)](http://img.gitnavi.com/tkey/postman-import-link.gif) 7 | - [Postman 接口转 cURL 方法(Gif 动图)](http://img.gitnavi.com/tkey/postman-to-curl.gif) 8 | 9 | ## 授权码模式 10 | 11 | 12 | ### 用户未认证,跳转登录页面 13 | 14 | - **GET 请求**(业务系统重定向) 15 | - 请求地址: 16 | - URL 参数 17 | 18 | ``` 19 | response_type: code 20 | client_id: test_client_id_1 21 | redirect_uri: http://test1.cdk8s.com:9393/client-scribejava/user?id=123456&name=cdk8s 22 | state: 12345 23 | ``` 24 | 25 | - 完整 demo: 26 | 27 | ``` 28 | http://sso.cdk8s.com:9091/sso/oauth/authorize?response_type=code&client_id=test_client_id_1&redirect_uri=http%3A%2F%2Ftest1.cdk8s.com%3A9393%2Fclient-scribejava%2FcodeCallback%3Fredirect_uri%3Dhttp%253A%252F%252Ftest1.cdk8s.com%253A9393%252Fclient-scribejava%252Fuser%253Fid%253D123456%2526name%253Dcdk8s 29 | ``` 30 | 31 | - 其中,最让人看不懂的是:`http%3A%2F%2Ftest1.cdk8s.com%3A9393%2Fclient-scribejava%2FcodeCallback%3Fredirect_uri%3Dhttp%253A%252F%252Ftest1.cdk8s.com%253A9393%252Fclient-scribejava%252Fuser%253Fid%253D123456%2526name%253Dcdk8s` 32 | - 这里进行了 URL 转码 33 | - 其中还有一个子参数:`%3Fredirect_uri%3Dhttp%253A%252F%252Ftest1.cdk8s.com%253A9393%252Fclient-scribejava%252Fuser%253Fid%253D123456%2526name%253Dcdk8s` 34 | - 该参数也进行了一个 URL 转码 35 | - 这个地址也就是用户最终登录后的跳转地址 36 | - Spring Security 的客户端没有这种情况,是因为它内部做了 cookie 的映射,所以最终重定向的地址不是根据 url 参数来的 37 | - 我们封装的 tkey-sso-client-scribejava 则是完全根据 url 参数来做最后登录成功的跳转 38 | - state 可以为空 39 | 40 | 41 | ### 用户提交的用户名和密码不匹配 42 | 43 | - 停留在登录页面,显示登录错误信息 44 | 45 | ### 用户提交的用户名和密码匹配 46 | 47 | - 301 重定向到:`http://test1.cdk8s.com:9393/client-scribejava/codeCallback?redirect_uri=http%3A%2F%2Ftest1.cdk8s.com%3A9393%2Fclient-scribejava%2Fuser%3Fid%3D123456%26name%3Dcdk8s` 48 | 49 | ------------------------------------------------------------------- 50 | 51 | ## 业务系统回调接口触发授权码第二步,通过 code 换取 token(核心点) 52 | 53 | - **POST 请求** 54 | - 请求地址: 55 | - 参数: 56 | 57 | ``` 58 | grant_type: authorization_code 59 | code: OC-106-uUddPxoWCEa4NBO5GaVIRJOTZLlWbHNr 60 | redirect_uri: http://test1.cdk8s.com:9393/client-scribejava/user?id=123456&name=cdk8s 61 | client_id: test_client_id_1 62 | client_secret: test_client_secret_1 63 | ``` 64 | 65 | 66 | ### 请求参数合法,系统返回 67 | 68 | - 状态码 200 69 | - JSON 数据 70 | 71 | ``` 72 | { 73 | "access_token": "AT-MISqrbWUxFWc1xU4e8JK2OcMgJYusF22-101", 74 | "token_type": "Bearer", 75 | "expires_in": 57600, 76 | "refresh_token": "RT-7UPY41g9j5K8rKBZse4qo4iP6sAbU2Df-102" 77 | } 78 | ``` 79 | 80 | ### 请求参数不合法,系统返回 81 | 82 | - 状态码 400 83 | - JSON 数据 84 | 85 | ``` 86 | { 87 | "error": "invalid request", 88 | "error_description": "请求类型不匹配", 89 | "error_uri_msg": "See the full API docs at https://github.com/cdk8s" 90 | } 91 | ``` 92 | 93 | ------------------------------------------------------------------- 94 | 95 | 96 | ## 业务系统通过 access_token 换取用户信息(核心点) 97 | 98 | - **GET 请求** 99 | - 请求地址: 100 | - 参数: 101 | 102 | ``` 103 | access_token: AT-dJTLEsFLR2PbxU1l8GPx3CUS9O3Lhzdn-102 104 | ``` 105 | 106 | 107 | ### 请求参数合法,系统返回 108 | 109 | - 状态码 200 110 | - JSON 数据 111 | 112 | ``` 113 | { 114 | "username": "admin", 115 | "name": "admin", 116 | "id": "111222333", 117 | "user_id": "111222333", 118 | "user_attribute": { 119 | "email": "admin@cdk8s.com", 120 | "user_id": "111222333", 121 | "username": "admin" 122 | }, 123 | "grant_type": "authorization_code", 124 | "client_id": "test_client_id_1", 125 | "iat": 1562134212, 126 | "exp": 1562191812 127 | } 128 | ``` 129 | 130 | ### 请求参数不合法,系统返回 131 | 132 | - 状态码 400 133 | - JSON 数据 134 | 135 | ``` 136 | { 137 | "error": "invalid request", 138 | "error_description": "请求类型不匹配", 139 | "error_uri_msg": "See the full API docs at https://github.com/cdk8s" 140 | } 141 | ``` 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | -------------------------------------------------------------------------------- /server/oauth-grant-type/common.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | ## Postman 接口集分享 5 | 6 | - 链接地址: 7 | - [Postman 导入 TKey 接口集方法(Gif 动图)](http://img.gitnavi.com/tkey/postman-import-link.gif) 8 | - [Postman 接口转 cURL 方法(Gif 动图)](http://img.gitnavi.com/tkey/postman-to-curl.gif) 9 | 10 | ------------------------------------------------------------------- 11 | 12 | 13 | ## 获取 access_token 对应的用户信息 14 | 15 | - **POST 请求** 16 | - 请求地址: 17 | - 参数方式 18 | - 请求头带有:`Authorization: Bearer AT-102-dJTLEsFLR2PbxU1l8GPx3CUS9O3Lhzdn` 19 | 20 | - **GET 请求** 21 | - 请求地址: 22 | 23 | 24 | ### 请求参数合法,系统返回 25 | 26 | - 状态码 200 27 | - JSON 数据(不带用户信息) 28 | 29 | ``` 30 | { 31 | "user_attribute": {}, 32 | "grant_type": "client_credentials", 33 | "iat": 1451602800, 34 | "exp": 1451606400, 35 | "client_id": "test_client_id_1" 36 | } 37 | ``` 38 | 39 | 40 | - JSON 数据(带用户信息) 41 | 42 | ``` 43 | { 44 | "user_attribute": { 45 | "email": "gitnavi@youmeek.com", 46 | "user_id": "7172", 47 | "username": "张三" 48 | }, 49 | "grant_type": "authorization_code", 50 | "iat": 1451602800, 51 | "exp": 1451606400, 52 | "client_id": "test_client_id_1" 53 | } 54 | 55 | ``` 56 | 57 | ### 请求参数不合法,系统返回 58 | 59 | - 状态码 400 60 | - JSON 数据 61 | 62 | ``` 63 | { 64 | "error": "invalid request", 65 | "error_description": "请求类型不匹配", 66 | "error_uri_msg": "See the full API docs at https://github.com/cdk8s" 67 | } 68 | ``` 69 | 70 | 71 | ------------------------------------------------------------------- 72 | 73 | ## 登出 74 | 75 | - **GET 请求** 76 | - 请求地址: 77 | 78 | 79 | ### 请求参数合法,系统返回 80 | 81 | - 状态码 302 82 | - Location 83 | 84 | ``` 85 | http://test1.cdk8s.com:9393/client-scribejava 86 | ``` 87 | 88 | 89 | ### 请求参数不合法,系统返回 90 | 91 | - 停留在登录页面或跳转到 error 页面 92 | 93 | 94 | ------------------------------------------------------------------- 95 | 96 | 97 | ## 通过 refresh_token,获取新的 access_token 98 | 99 | 100 | - **POST 请求** 101 | - 请求地址: 102 | - 参数: 103 | 104 | ``` 105 | grant_type: refresh_token 106 | refresh_token: RT-8aI3zHbArcmzT3ukHlBQ88AdMv2NB8Aa-103 107 | client_id: test_client_id_1 108 | client_secret: test_client_secret_1 109 | ``` 110 | 111 | ### cURL 112 | 113 | ``` 114 | curl -X POST \ 115 | http://sso.cdk8s.com:9091/sso/oauth/token \ 116 | -H 'Content-Type: application/x-www-form-urlencoded' \ 117 | -H 'cache-control: no-cache' \ 118 | -d 'grant_type=refresh_token&refresh_token=RT-8aI3zHbArcmzT3ukHlBQ88AdMv2NB8Aa-103&client_id=test_client_id_1&client_secret=test_client_secret_1' 119 | ``` 120 | 121 | 122 | ### 请求参数合法,系统返回 123 | 124 | - 状态码 200 125 | - JSON 数据 126 | 127 | ``` 128 | { 129 | "access_token": "AT-IDm312Our5Jti70BGE8RgO2qRK29blri", 130 | "token_type": "Bearer", 131 | "expires_in": 57600 132 | } 133 | ``` 134 | 135 | ### 请求参数不合法,系统返回 136 | 137 | - 状态码 400 138 | - JSON 数据 139 | 140 | ``` 141 | { 142 | "error": "invalid request", 143 | "error_description": "请求类型不匹配", 144 | "error_uri_msg": "See the full API docs at https://github.com/cdk8s" 145 | } 146 | ``` 147 | 148 | 149 | ------------------------------------------------------------------- 150 | 151 | 152 | ## 验证 access_token / refresh_token 153 | 154 | 155 | - **POST 请求** 156 | - 请求地址: 157 | - 参数: 158 | 159 | ``` 160 | client_id: test_client_id_1 161 | client_secret: test_client_secret_1 162 | token: AT-3KGHVaANf4Ppi1IhrlHTF9IKSsV7fuzY-109 163 | token_type_hint: access_token 164 | ``` 165 | 166 | - token_type_hint,可选值 167 | - `access_token` 168 | - `refresh_token` 169 | 170 | ### 请求参数合法,系统返回 171 | 172 | - 状态码 200 173 | - JSON 数据 174 | 175 | ``` 176 | { 177 | "token_type": "Bearer", 178 | "grant_type": "client_credentials", 179 | "client_id": "test_client_id_1", 180 | "exp": 1561438626, 181 | "iat": 1561381026 182 | } 183 | ``` 184 | 185 | 186 | ###### 请求参数不合法,系统返回 187 | 188 | - 状态码 400 189 | - JSON 数据 190 | 191 | ``` 192 | { 193 | "error": "invalid request", 194 | "error_description": "请求类型不匹配", 195 | "error_uri_msg": "See the full API docs at https://github.com/cdk8s" 196 | } 197 | ``` 198 | 199 | ------------------------------------------------------------------- 200 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | # This file is inspired by https://github.com/alexkaratarakis/gitattributes 2 | # 3 | # Auto detect text files and perform LF normalization 4 | # http://davidlaing.com/2012/09/19/customise-your-gitattributes-to-become-a-git-ninja/ 5 | * text=auto 6 | 7 | # The above will handle all files NOT found below 8 | # These files are text and should be normalized (Convert crlf => lf) 9 | 10 | # Java sources 11 | *.java text diff=java 12 | *.gradle text diff=java 13 | *.gradle.kts text diff=java 14 | 15 | 16 | *.css text diff=css 17 | *.htm text diff=html 18 | *.html text diff=html 19 | *.xhtml text diff=html 20 | *.coffee text 21 | *.cql text 22 | *.df text 23 | *.ejs text 24 | *.js text 25 | *.jsx text 26 | *.json text 27 | *.less text 28 | *.properties text 29 | *.sass text 30 | *.scss text diff=css 31 | *.sh text eol=lf 32 | *.sql text 33 | *.txt text 34 | *.ts text 35 | *.tsx text 36 | *.xml text 37 | *.yaml text 38 | *.yml text 39 | *.jsp text 40 | *.jspf text 41 | *.jspx text 42 | *.tld text 43 | *.tag text 44 | *.tagx text 45 | *.inc text 46 | *.ini text 47 | 48 | # Documents 49 | *.doc diff=astextplain 50 | *.DOC diff=astextplain 51 | *.docx diff=astextplain 52 | *.DOCX diff=astextplain 53 | *.dot diff=astextplain 54 | *.DOT diff=astextplain 55 | *.pdf diff=astextplain 56 | *.PDF diff=astextplain 57 | *.rtf diff=astextplain 58 | *.RTF diff=astextplain 59 | *.markdown text 60 | *.md text 61 | *.adoc text 62 | *.textile text 63 | *.mustache text 64 | *.csv text 65 | *.tab text 66 | *.tsv text 67 | *.txt text 68 | AUTHORS text 69 | CHANGELOG text 70 | CHANGES text 71 | CONTRIBUTING text 72 | COPYING text 73 | copyright text 74 | *COPYRIGHT* text 75 | INSTALL text 76 | license text 77 | LICENSE text 78 | NEWS text 79 | readme text 80 | *README* text 81 | TODO text 82 | 83 | # Graphics 84 | *.png binary 85 | *.jpg binary 86 | *.jpeg binary 87 | *.gif binary 88 | *.tif binary 89 | *.tiff binary 90 | *.ico binary 91 | 92 | # SVG treated as an asset (binary) by default. If you want to treat it as text, 93 | # comment-out the following line and uncomment the line after. 94 | *.svg binary 95 | #*.svg text 96 | *.eps binary 97 | 98 | # These files are binary and should be left untouched 99 | # (binary is a macro for -text -diff) 100 | *.class binary 101 | *.jar binary 102 | *.war binary 103 | *.dll binary 104 | *.ear binary 105 | *.so binary 106 | *.exe binary 107 | *.pyc binary 108 | 109 | ## LINTERS 110 | .csslintrc text 111 | .eslintrc text 112 | .jscsrc text 113 | .jshintrc text 114 | .jshintignore text 115 | .stylelintrc text 116 | 117 | ## CONFIGS 118 | *.conf text 119 | *.config text 120 | .editorconfig text 121 | .gitattributes text 122 | .gitconfig text 123 | .gitignore text 124 | .htaccess text 125 | *.npmignore text 126 | 127 | ## HEROKU 128 | Procfile text 129 | .slugignore text 130 | 131 | ## AUDIO 132 | *.kar binary 133 | *.m4a binary 134 | *.mid binary 135 | *.midi binary 136 | *.mp3 binary 137 | *.ogg binary 138 | *.ra binary 139 | 140 | ## VIDEO 141 | *.3gpp binary 142 | *.3gp binary 143 | *.as binary 144 | *.asf binary 145 | *.asx binary 146 | *.fla binary 147 | *.flv binary 148 | *.m4v binary 149 | *.mng binary 150 | *.mov binary 151 | *.mp4 binary 152 | *.mpeg binary 153 | *.mpg binary 154 | *.swc binary 155 | *.swf binary 156 | *.webm binary 157 | 158 | ## ARCHIVES 159 | *.7z binary 160 | *.7z binary 161 | *.gz binary 162 | *.rar binary 163 | *.tar binary 164 | *.zip binary 165 | 166 | ## FONTS 167 | *.ttf binary 168 | *.eot binary 169 | *.otf binary 170 | *.woff binary 171 | *.woff2 binary 172 | 173 | 174 | *.bash text eol=lf 175 | *.bat text eol=crlf 176 | *.cmd text eol=crlf 177 | 178 | 179 | *.php text diff=php 180 | *.py text diff=python 181 | *.rb text diff=ruby 182 | 183 | # Docker 184 | *.dockerignore text 185 | Dockerfile text 186 | 187 | 188 | -------------------------------------------------------------------------------- /faq/README.md: -------------------------------------------------------------------------------- 1 | 2 | ## TKey SSO Server 3 | 4 | 5 | - 大部分场景下的设计都是有原因,我说说我们的考虑 6 | 7 | 8 | ## 关于 Token 命名与格式 9 | 10 | - 在命名上借鉴了 CAS,比如:AT-,RT-,OC-,TGC 这类都是来源 CAS。 11 | - OAuth 2.0 没有规定 token 的命名,你如果不喜欢也可以自己改造下。 12 | - 关于 Bearer 和 Authorization 这两个关键字,规范中没有明确要求要不要区分大小写。但是从业界使用情况看,我们一般都建议首字母大写。TKey 虽然在大小写上也做了兼容,但是建议大家还是首字母大写。 13 | 14 | 15 | ## 为什么用户认证是通过 REST API 而不是数据库 16 | 17 | 会 Spring Boot 的人自己加个 Mapper 之后去查数据库,这个真的不难吧。 18 | 19 | 但是我这样设计是有原因的。 20 | 21 | 有很多企业的用户体系其实起步已经很早了,可能是用 Oracle、MSSQL、LDAP 等等,如果你很幸运,刚好是 MySQL 那确实稍微改一下就可以了。 22 | 23 | 可是现实中很多企业不是,而我又不想 TKey 引入太多内容,所以我建议是那些老系统开放出 REST API,TKey 通过内网方式调用老系统验证用户信息。 24 | 25 | ## 为什么 code 只能用一次 26 | 27 | 标准虽然没有强制规定 code 能用多少次,但是从安全角度来讲,以及业界大家使用上目前都是 code 只能被使用一次。 28 | 29 | 如果你们对此有需求可以在:`OauthCodeToTokenStrategy.java` 中找到该代码进行调整: 30 | 31 | ``` 32 | codeRedisService.delete(oauthTokenParam.getCode()); 33 | ``` 34 | 35 | 36 | ## 为什么引入 Redis 37 | 38 | 大家如果看过 TKey 的压力测试文档内容,会知道目前主要的瓶颈开销在 Redis 连接和存取上。 39 | 40 | 可是,我是坚定要上存储介质的,可以不是 Redis,可以换成:LevelDB、SSDB、RocksDB、Memcached 等等。但是必然要有一个存储介质来存储 Token 信息。不然无法解决任意横向扩展 TKey 服务这件事。 41 | 42 | 也因为引入了 Redis,所以 TKey 的维护就变成异常简单,因为它无状态,想停就停,想启动就启动。我们只要维护好:Redis 的高可用,保持好网络通畅。 43 | 44 | 小公司自己维护 Redis 没什么问题,因为量不大。如果公司已经成规模,建议直接采用云上 Redis,尽可能保住高可用。 45 | 46 | 47 | ## OAuth 2.0 Token 请求参数的 3 种方式 48 | 49 | 按 OAuth 2.0 的标准,要使用 Token 有 3 种方式: 50 | 51 | - 使用 HTTP Authorization 头部(优先推荐) 52 | - 使用表单格式的请求体参数 53 | - 使用 URL 编码的查询参数 54 | 55 | 优先推荐请求头方式或 POST 表单,因为 URL 比较容易被日志监控中拿到。 56 | 57 | 如果我部分文档或测试采用 URL 方式,那只有一个原因:为了方便。大家不要学习这种行为。 58 | 59 | 目前 3 种模式我都做了支持,但是优先推荐请求头。 60 | 61 | 62 | ## 刷新 Token 接口的返回 JSON 内容 63 | 64 | 刷新 Token 接口目前 TKey 返回内容格式是这样的: 65 | 66 | ``` 67 | { 68 | "access_token": "AT-101-IDm312Our5Jti70BGE8RgO2qRK29blri", 69 | "token_type": "Bearer", 70 | "expires_in": 57600 71 | } 72 | ``` 73 | 74 | 但是,业界还有一种玩法,在给了新 AccessToken 之后,重新给你一个新的 RefreshToken,我个人是觉得没必要,所以不对这种玩法进行支持。 75 | 76 | ``` 77 | { 78 | "access_token": "AT-IDm312Our5Jti70BGE8RgO2qRK29blri-101", 79 | "refresh_token": "RT-8aI3zHbArcmzT3ukHlBQ88AdMv2NB8Aa-103", 80 | "token_type": "Bearer", 81 | "expires_in": 57600 82 | } 83 | ``` 84 | 85 | ## 功能开关 86 | 87 | - 由于目前功能相对单一,所以暂时不设置任何功能开关,后期版本迭代多了必然要上功能开关。 88 | - 同时也建议在开发系统的时候注重这一块的设计,不然维护起来成本会大很多。 89 | 90 | ## 为什么选择 Prometheus 91 | 92 | - InfluxDB 挺好的 93 | - 但是,后面要上 K8S,不想扩展出多个时序库,所以就选择了 Prometheus 94 | 95 | ## Actuator 96 | 97 | Spring Boot 可以借用 Spring Security 来实现 Actuator 的访问认证,但是为了方便 Prometheus 拉取数据,这里并没有这样设计。所以目前 actuator 是完全裸奔的。 98 | 99 | 建议是不对外开放 IP 访问,或者在 Nginx 配置上该路径的 Basic Auth,避免信息泄露。 100 | 101 | 102 | ## TKey 的 userinfo 接口返回的用户信息为何冗余 103 | 104 | 105 | 在每个系统中,用户唯一主键叫什么名字都是不一样的,有人叫:id,userid,user_id,id_ 等等等 106 | 107 | 而用户信息根对象中必须要有一个主键,我这里借鉴了 Spring Security 的 FixedPrincipalExtractor.java 类。它限定了这几个:`user`、`username`、`userid`、`user_id`、`login`、`id`、`name`。所以我也为了做兼容冗余了部分字段。 108 | 109 | 110 | ## ApplicationTestDataInitRunner.java 的作用 111 | 112 | 113 | 为了方便测试,我会在该类有一个初始化预设几个 code 和 token 的动作,虽然已经在开头限制了:`@Profile({"dev", "gatling", "test", "junit"})` 114 | 115 | 但是,还是提醒大家上生产的时候要注意这个细节。 116 | 117 | ## 为什么没有 scope 设计 118 | 119 | OAuth 很核心的点就是 scope,但是我在这个版本没有考虑。因为我目的很明确,就是为了做单点登录,并且初期还不是开放平台方式的那种单点登录。所以,如果加上 scope 设计,整个登录过程会过于冗余。 120 | 121 | 当然,我们也可以设计该功能,然后做上开关。只是暂时不是我们的优先级。 122 | 123 | 内部系统的授权一般建议交给 API 网关统一处理。 124 | 125 | 如果你目前就有scope 的需求,那我建议你自行先改造。按 OAuth 2.0 规范,scope 的设计是用空格隔开的,比如:`read write delete` 126 | 127 | ## 为什么没有 找回密码、修改密码功能 128 | 129 | 找回密码和修改密码是 UPMS 管的,不应该是 SSO 的事情,只是登录页面可以放个链接跳转到 UPMS 系统去而已。 130 | 131 | 132 | ## 为什么没有单点登出 133 | 134 | 单点登出分两种业务场景: 135 | 136 | - 1. 从某个业务系统登出,其他已经登录过的业务系统不做变更,要访问的新系统则需要重新登录 137 | - 2. 从某个业务系统登出,其他已经登录过的业务系统也跟着退出 138 | 139 | 第一种业务场景比较好理解。 140 | 141 | 第二种业务场景又可以分为两种情况: 142 | 143 | - 1. 有 API 网关 144 | - 2. 没有 API 网关 145 | 146 | 如果有 API 网关,在任何业务系统退出,本质就是网关上退出,那你下次访问任何业务系统肯定都是要重新登录 147 | 148 | 如果没有 API 网关,则这里就要引入 MQ 或则 RPC 通信。每个业务系统监听 TKey 的 MQ 通道,当发现各自的业务系统中有当前退出用户的 Token 则要自己进行销毁。但是这样的设计复杂度就上来了,不划算。所以,这里又一次提到了 API 网关,API 网关真的很重要。 149 | 150 | 还有一种适合小企业的办法。就是 TKey 和业务系统都用同一个 Redis,然后 TKey 再新增加维护一个新的 Key 规则:`userId : 所有业务系统生成过的 Token 集合`。这样,当某个业务系统退出,TKey 就可以通过 userId 找到所有 Token 进行删除。但是,感觉这样的企业应该很少,都要上单点登录了,应该规模还可以,不应该同用一个 Redis... 151 | 152 | 153 | 154 | ## 为什么 TKey SSO Client Java 那么多版本 155 | 156 | 考虑到有些业务系统已经用 Spring Security 的,为了使得改造成本尽可能减小,所以这里做了 demo 实例。 157 | 158 | 其中 Spring Security 在 4 和 5 版本上本身做了的大修改,所以我这边做了两个 demo 来区分开。 159 | 160 | - 在 Spring Boot 1.5.x 中使用的是 Spring Security 4 161 | - 在 Spring Boot 2.1.x 中使用的是 Spring Security 5 162 | 163 | 但是,如果觉得不管怎么改造都有成本,那我建议参考我自己写 REST Client demo,这有助于你后期各种需求下的玩法。 164 | 165 | 166 | ## 前后端分离要注意什么 167 | 168 | 前后端分离分为两种场景: 169 | 170 | - 1. 前后端的域名只是二级目录不一致,或者三级域名不一致 171 | - 2. 前后端的域名完全不一致 172 | 173 | 第一种情况还可以采用 Cookie、Session 的方式维护,虽然不推荐,但是确实是可以这样做的。 174 | 175 | 第二种情况 Cookie、Session 是完全用不了的,只能把 Token 信息交给前端存储在 LocalStorage、SessionStorage 中,请求的时候带上请求头。推荐大家使用这种。 176 | 177 | 但是这里有一个小细节,如果使用我们的 TKey Client,则 `enable-code-callback-to-front: true` 必须是 true。表示 code 的回调在前端接收,然后前端再交给业务后端去调用 TKey,不然整个过程,你前端与后端是没有任何交流的,也就拿不到最后业务后端的 Token。所以才有这一步的设计。但是我个人觉得不够优雅,如果大家有跟优雅的方式,赶紧联系我们~ 178 | 179 | 180 | ## 密码模式的常用场景分析 181 | 182 | - 默认是采用授权码模式,要来回跳转。虽然这样会安全一点,但是有些环境可能不需要那么安全,只要方便就行,比如小程序、APP 那我推荐使用密码模式。 183 | - 假设场景如下:这类前端一般都有自己的登录页面,页面上用户和密码是传给业务系统,业务系统采用密码模式调用 TKey Server 获取到 Token 信息,然后返回 JSON 信息给前端,前端可以存储到 Session Storage 中。 184 | 185 | 186 | ## 刷新 Token 如何使用 187 | 188 | 如果你们的业务系统都是在 PC 上,那其实我觉得可以不考虑,因为 TGC 的有效期很长,特别是勾选了记住我之后,默认有 7 天的时间,在这个过程中,只要用户不清除缓存、Cookie,则每次访问业务系统都会生成新的 AccessToken。 189 | 190 | 这时候用不用 RefreshToken 都无所谓了。 191 | 192 | 但是如果你们有移动端的业务场景,那就需要考虑移动端用户通过 RefreshToken 自动帮用户刷新的 Token 进行使用。 193 | 194 | 195 | 196 | 197 | 198 | 199 | 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 209 | 210 | 211 | 212 | 213 | 214 | 215 | -------------------------------------------------------------------------------- /share-file/playbook/3-maven-playbook.yml: -------------------------------------------------------------------------------- 1 | - hosts: all 2 | remote_user: root 3 | vars: 4 | maven_install_folder: /usr/local 5 | file_name: apache-maven-3.6.3-bin.zip 6 | tasks: 7 | - name: copy maven 8 | copy: 9 | src=/opt/{{ file_name }} 10 | dest={{ maven_install_folder }} 11 | 12 | - name: unzip maven 13 | shell: 14 | chdir={{ maven_install_folder }} 15 | unzip {{ file_name }} 16 | 17 | - name: set MAVEN_HOME 18 | blockinfile: 19 | path: /root/.zshrc 20 | marker: "#{mark} MAVEN ENV" 21 | block: | 22 | MAVEN_HOME={{ maven_install_folder }}/apache-maven-3.6.3 23 | M3_HOME={{ maven_install_folder }}/apache-maven-3.6.3 24 | M2_HOME={{ maven_install_folder }}/apache-maven-3.6.3 25 | PATH=$PATH:$M3_HOME/bin 26 | MAVEN_OPTS="-Xms256m -Xmx356m" 27 | export M3_HOME 28 | export M2_HOME 29 | export MAVEN_HOME 30 | export PATH 31 | export MAVEN_OPTS 32 | 33 | - name: source zshrc 34 | shell: source /root/.zshrc 35 | 36 | - name: remove zip file 37 | file: 38 | path: "{{ maven_install_folder }}/{{ file_name }}" 39 | state: absent 40 | 41 | - name: create local_maven_repository directory 42 | file: 43 | path: /opt/local_maven_repository 44 | state: directory 45 | 46 | - name: remove old settings.xml 47 | file: 48 | path: "{{ maven_install_folder }}/apache-maven-3.6.3/conf/settings.xml" 49 | state: absent 50 | 51 | - name: create settings.xml file 52 | file: 53 | path="{{ maven_install_folder }}/apache-maven-3.6.3/conf/{{ item }}" 54 | state=touch 55 | mode=777 56 | with_items: 57 | - settings.xml 58 | 59 | - name: set settings.xml aliyun 60 | blockinfile: 61 | path: "{{ maven_install_folder }}/apache-maven-3.6.3/conf/settings.xml" 62 | marker: "" 63 | block: | 64 | 65 | 68 | 69 | 70 | /opt/local_maven_repository 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | aliyun 84 | 85 | 86 | aliyun 87 | http://maven.aliyun.com/nexus/content/groups/public/ 88 | 89 | true 90 | 91 | 92 | true 93 | 94 | 95 | 96 | 97 | 98 | aliyun 99 | http://maven.aliyun.com/nexus/content/groups/public/ 100 | 101 | true 102 | 103 | 104 | true 105 | 106 | 107 | 108 | 109 | 110 | maven 111 | 112 | 113 | maven 114 | https://repo.maven.apache.org/maven2/ 115 | 116 | true 117 | 118 | 119 | true 120 | 121 | 122 | 123 | 124 | 125 | maven 126 | https://repo.maven.apache.org/maven2/ 127 | 128 | true 129 | 130 | 131 | true 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | aliyun 140 | 141 | 142 | 143 | -------------------------------------------------------------------------------- /share-file/playbook/7-nginx-playbook.yml: -------------------------------------------------------------------------------- 1 | - hosts: all 2 | remote_user: root 3 | tasks: 4 | - name: install nginx 5 | yum: 6 | name: nginx 7 | 8 | - name: create conf file 9 | file: 10 | path="/etc/nginx/conf.d/{{ item }}" 11 | state=touch 12 | mode=777 13 | with_items: 14 | - http-redirect-https.conf 15 | - api.conf 16 | - admin-front.conf 17 | - h5-web-front.conf 18 | - pc-web-front.conf 19 | 20 | - name: set http-redirect-https.conf 21 | blockinfile: 22 | path: /etc/nginx/conf.d/http-redirect-https.conf 23 | marker: "" 24 | block: | 25 | server { 26 | listen 80; 27 | server_name www.cdk8s.com cdk8s.com api.cdk8s.com; 28 | return 301 https://$server_name$request_uri; 29 | } 30 | 31 | - name: set api.conf 32 | blockinfile: 33 | path: /etc/nginx/conf.d/api.conf 34 | marker: "" 35 | block: | 36 | server { 37 | charset utf-8; 38 | client_max_body_size 128M; 39 | 40 | #listen 80; 41 | listen 443 ssl; 42 | 43 | ssl_certificate /opt/jar/ssl/server.crt; 44 | ssl_certificate_key /opt/jar/ssl/server.key; 45 | 46 | ssl_session_timeout 5m; 47 | ssl_protocols TLSv1 TLSv1.1 TLSv1.2; 48 | ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:HIGH:!aNULL:!MD5:!RC4:!DHE; 49 | ssl_prefer_server_ciphers on; 50 | 51 | server_name www.cdk8s.com cdk8s.com api.cdk8s.com; 52 | 53 | location ^~ /upload { 54 | root /home/jenkins/sculptor-boot-backend-upload-dir; 55 | autoindex on; 56 | autoindex_exact_size off; 57 | autoindex_localtime on; 58 | } 59 | 60 | location ^~ /sculptor-boot-backend/ { 61 | proxy_pass http://127.0.0.1:9091; 62 | proxy_redirect off; 63 | proxy_set_header Host $host; 64 | proxy_set_header X-Real-IP $remote_addr; 65 | proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; 66 | proxy_set_header X-Forwarded-Proto $scheme; 67 | } 68 | 69 | location ^~ /logs { 70 | root /home/jenkins/workspace/sculptor-boot-backend; 71 | autoindex on; 72 | autoindex_exact_size off; 73 | autoindex_localtime on; 74 | } 75 | } 76 | 77 | - name: set admin-front.conf 78 | blockinfile: 79 | path: /etc/nginx/conf.d/admin-front.conf 80 | marker: "" 81 | block: | 82 | server { 83 | charset utf-8; 84 | client_max_body_size 128M; 85 | 86 | #listen 80; 87 | listen 443 ssl; 88 | 89 | ssl_certificate /opt/jar/ssl/server.crt; 90 | ssl_certificate_key /opt/jar/ssl/server.key; 91 | 92 | ssl_session_timeout 5m; 93 | ssl_protocols TLSv1 TLSv1.1 TLSv1.2; 94 | ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:HIGH:!aNULL:!MD5:!RC4:!DHE; 95 | ssl_prefer_server_ciphers on; 96 | 97 | server_name admin-front.cdk8s.com; 98 | 99 | location ^~ /rcxt-react { 100 | root /home/jenkins/workspace/rcxt-react; 101 | index index.html; 102 | try_files $uri /rcxt-react/index.html; 103 | } 104 | } 105 | 106 | - name: set h5-web-front.conf 107 | blockinfile: 108 | path: /etc/nginx/conf.d/h5-web-front.conf 109 | marker: "" 110 | block: | 111 | server { 112 | charset utf-8; 113 | client_max_body_size 128M; 114 | 115 | #listen 80; 116 | listen 443 ssl; 117 | 118 | ssl_certificate /opt/jar/ssl/server.crt; 119 | ssl_certificate_key /opt/jar/ssl/server.key; 120 | 121 | ssl_session_timeout 5m; 122 | ssl_protocols TLSv1 TLSv1.1 TLSv1.2; 123 | ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:HIGH:!aNULL:!MD5:!RC4:!DHE; 124 | ssl_prefer_server_ciphers on; 125 | 126 | server_name h5.cdk8s.com; 127 | 128 | location / { 129 | root /home/jenkins/workspace/rcxt-web-online; 130 | index index.html index.htm; 131 | } 132 | } 133 | 134 | - name: set pc-web-front.conf 135 | blockinfile: 136 | path: /etc/nginx/conf.d/pc-web-front.conf 137 | marker: "" 138 | block: | 139 | server { 140 | charset utf-8; 141 | client_max_body_size 128M; 142 | 143 | #listen 80; 144 | listen 443 ssl; 145 | 146 | ssl_certificate /opt/jar/ssl/server.crt; 147 | ssl_certificate_key /opt/jar/ssl/server.key; 148 | 149 | ssl_session_timeout 5m; 150 | ssl_protocols TLSv1 TLSv1.1 TLSv1.2; 151 | ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:HIGH:!aNULL:!MD5:!RC4:!DHE; 152 | ssl_prefer_server_ciphers on; 153 | 154 | server_name www.cdk8s.com; 155 | 156 | location / { 157 | root /home/jenkins/workspace/rcxt-web; 158 | index index.html index.htm; 159 | } 160 | } 161 | 162 | - name: insert gzip config 163 | blockinfile: 164 | path: /etc/nginx/nginx.conf 165 | marker: " " 166 | insertafter: "^http {" 167 | block: | 168 | gzip on; 169 | gzip_buffers 8 16k; 170 | gzip_min_length 512; 171 | gzip_disable "MSIE [1-6]\.(?!.*SV1)"; 172 | gzip_http_version 1.1; 173 | gzip_types text/plain text/css application/javascript application/x-javascript application/json application/xml; 174 | 175 | - name: enable nginx 176 | shell: "{{ item }}" 177 | with_items: 178 | - systemctl enable nginx 179 | - systemctl restart nginx 180 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | ## Git 3 | 4 | - Github: 5 | - Gitee: 6 | - Gitbook: 7 | 8 | ## Hosts 9 | 10 | ``` 11 | 127.0.0.1 sso.cdk8s.com 12 | 127.0.0.1 test1.cdk8s.com 13 | 127.0.0.1 test2.cdk8s.com 14 | 127.0.0.1 redis.cdk8s.com 15 | 127.0.0.1 mysql.cdk8s.com 16 | 127.0.0.1 management.cdk8s.com 17 | 127.0.0.1 management-frontend.cdk8s.com 18 | ``` 19 | 20 | ## Architecture 21 | 22 | ![架构图](http://img.gitnavi.com/tkey/tkey-sso-architecture.jpg) 23 | 24 | - 上图的视频讲解:[B 站](https://www.bilibili.com/video/av65883281/)、[腾讯视频](https://v.qq.com/x/page/e0920wdqe7v.html) 25 | - OAuth2.0 授权码模式细节时序图可以查看:[点击我查看](http://img.gitnavi.com/tkey/tkey-oauth.png) 26 | 27 | ## Documentation 28 | 29 | - 我们统一了 TKey 项目的所有文档,方便大家查看 30 | - Github: 31 | - Gitee: 32 | - Gitbook: 33 | - **认识阶段 (必读)** 34 | - 单点登录系统认知与基础介绍:[Github](https://github.com/cdk8s/tkey-docs/blob/master/other/tkey-baisc.md)、[Gitee](https://gitee.com/cdk8s/tkey-docs/blob/master/other/tkey-baisc.md) 35 | - 故意设计点(常见问题):[Github](https://github.com/cdk8s/tkey-docs/blob/master/faq/README.md)、[Gitee](https://gitee.com/cdk8s/tkey-docs/blob/master/faq/README.md) 36 | - 项目结构与端口占用:[Github](https://github.com/cdk8s/tkey-docs/blob/master/other/project-structure.md)、[Gitee](https://gitee.com/cdk8s/tkey-docs/blob/master/other/project-structure.md) 37 | - OAuth2.0 四种模式:[Github](https://github.com/cdk8s/tkey-docs/blob/master/server/oauth-grant-type/README.md)、[Gitee](https://gitee.com/cdk8s/tkey-docs/blob/master/server/oauth-grant-type/README.md) 38 | - JAR 方式部署:[Github](https://github.com/cdk8s/tkey-docs/blob/master/deployment/jar-runapp.md)、[Gitee](https://gitee.com/cdk8s/tkey-docs/blob/master/deployment/jar-runapp.md) 39 | - Docker 方式部署:[Github](https://github.com/cdk8s/tkey-docs/blob/master/deployment/docker-runapp.md)、[Gitee](https://gitee.com/cdk8s/tkey-docs/blob/master/deployment/docker-runapp.md) 40 | - Docker Compose 方式部署:[Github](https://github.com/cdk8s/tkey-docs/blob/master/deployment/docker-compose-runapp.md)、[Gitee](https://gitee.com/cdk8s/tkey-docs/blob/master/deployment/docker-compose-runapp.md) 41 | - TKey Server 开发阶段 42 | - 开发改造引导:[Github](https://github.com/cdk8s/tkey-docs/blob/master/server/dev.md)、[Gitee](https://gitee.com/cdk8s/tkey-docs/blob/master/server/dev.md) 43 | - TKey Management 开发阶段(也是前后端分离的最佳实践示例) 44 | - 后端开发改造引导:[Github](https://github.com/cdk8s/tkey-docs/blob/master/management/dev-backend.md)、[Gitee](https://gitee.com/cdk8s/tkey-docs/blob/master/management/dev-backend.md) 45 | - 前端开发改造引导:[Github](https://github.com/cdk8s/tkey-docs/blob/master/management/dev-frontend.md)、[Gitee](https://gitee.com/cdk8s/tkey-docs/blob/master/management/dev-frontend.md) 46 | - TKey Client Java 开发阶段 47 | - 自己封装的 REST Client:[Github](https://github.com/cdk8s/tkey-docs/blob/master/client/dev-rest-client.md)、[Gitee](https://gitee.com/cdk8s/tkey-docs/blob/master/client/dev-rest-client.md) 48 | - Spring Security 支持:[Github](https://github.com/cdk8s/tkey-docs/blob/master/client/dev-spring-security-client.md)、[Gitee](https://gitee.com/cdk8s/tkey-docs/blob/master/client/dev-spring-security-client.md) 49 | - 测试阶段 50 | - 单元测试:[Github](https://github.com/cdk8s/tkey/blob/master/src/test/java/com/cdk8s/tkey/server/controller/AuthorizationCodeByFormTest.java)、[Gitee](https://gitee.com/cdk8s/tkey/blob/master/src/test/java/com/cdk8s/tkey/server/controller/AuthorizationCodeByFormTest.java) 51 | - 压力测试:[Github](https://github.com/cdk8s/tkey-docs/blob/master/test/performance.md)、[Gitee](https://gitee.com/cdk8s/tkey-docs/blob/master/test/performance.md) 52 | - 部署阶段 53 | - 生产注意事项:[Github](https://github.com/cdk8s/tkey-docs/blob/master/deployment/production-environment.md)、[Gitee](https://gitee.com/cdk8s/tkey-docs/blob/master/deployment/production-environment.md) 54 | - 部署环境搭建:[Github](https://github.com/cdk8s/tkey-docs/blob/master/deployment/deployment-core.md)、[Gitee](https://gitee.com/cdk8s/tkey-docs/blob/master/deployment/deployment-core.md) 55 | - 监控阶段 56 | - Spring Boot Micrometer:[Github](https://github.com/cdk8s/tkey-docs/blob/master/deployment/micrometer.md)、[Gitee](https://gitee.com/cdk8s/tkey-docs/blob/master/deployment/micrometer.md) 57 | - 其他工具全在 `部署环境搭建`,请自行查看 58 | - 线上问题诊断 59 | - [Actuator 在线修改 log 输出级别(Gif 动图)](http://img.gitnavi.com/tkey/actuator-update-log-level.gif) 60 | - [Arthas 诊断 Docker 应用](https://alibaba.github.io/arthas/docker.html#dockerjava) 61 | - 夜间开放端口,挑选流量远程 Debug:[Github](https://github.com/cdk8s/tkey-docs/blob/master/server/remote-debug.md)、[Gitee](https://gitee.com/cdk8s/tkey-docs/blob/master/server/remote-debug.md) 62 | 63 | 64 | ## TKey Client 65 | 66 | - Java 前后端分离最佳实践 67 | - TKey SSO Client Management Backend:[Github](https://github.com/cdk8s/tkey-management)、[Gitee](https://gitee.com/cdk8s/tkey-management) 68 | - TKey SSO Client Management Frontend:[Github](https://github.com/cdk8s/tkey-management-frontend)、[Gitee](https://gitee.com/cdk8s/tkey-management) 69 | - Angular、Vue 的前后端分离版本会在稍后几周发出来 70 | - Java REST API 客户端:[Github](https://github.com/cdk8s/tkey-client-java)、[Gitee](https://gitee.com/cdk8s/tkey-client-java) 71 | - Java Spring Security 客户端:[Github](https://github.com/cdk8s/tkey-client-java-spring-security)、[Gitee](https://gitee.com/cdk8s/tkey-client-java-spring-security) 72 | - C#(暂缺) 73 | - GO(暂缺) 74 | - PHP(暂缺) 75 | - Python(暂缺) 76 | - Ruby(暂缺) 77 | - Node.js(暂缺) 78 | 79 | ## Share 80 | 81 | - Grafana Dashboard:[Github](https://github.com/cdk8s/tkey-docs/blob/master/share-file/grafana/dashboard.json)、[Gitee](https://gitee.com/cdk8s/tkey-docs/blob/master/share-file/grafana/dashboard.json) 82 | - Postman API:[Github](https://github.com/cdk8s/tkey-docs/blob/master/share-file/postman/tkey-sso-server-api_collection_2.1_format.json)、[Gitee](https://gitee.com/cdk8s/tkey-docs/blob/master/share-file/postman/tkey-sso-server-api_collection_2.1_format.json) 83 | - Run JAR Shell:[Github](https://github.com/cdk8s/tkey-docs/blob/master/share-file/shell/runapp.sh)、[Gitee](https://gitee.com/cdk8s/tkey-docs/blob/master/share-file/shell/runapp.sh) 84 | 85 | 86 | ## Roadmap 87 | 88 | - 规划版本:[Github](https://github.com/cdk8s/tkey-docs/blob/master/roadmap/README.md)、[Gitee](https://gitee.com/cdk8s/tkey-docs/blob/master/roadmap/README.md) 89 | 90 | ## Changelog 91 | 92 | - 版本更新:[Github](https://github.com/cdk8s/tkey-docs/blob/master/changelog/README.md)、[Gitee](https://gitee.com/cdk8s/tkey-docs/blob/master/changelog/README.md) 93 | 94 | 95 | ## Issues 96 | 97 | - 目前只开放了一个 issues 入口,集中问题,可以方便大家检索。 98 | - 去提问:[Github](https://github.com/cdk8s/tkey-issues)、[Gitee](https://gitee.com/cdk8s/tkey-issues) 99 | 100 | ## Contributors 101 | 102 | - 暂无 103 | - 欢迎 pull request 104 | 105 | ## Adopters 106 | 107 | - 去申请:[Github](https://github.com/cdk8s/tkey-issues/issues/1)、[Gitee](https://gitee.com/cdk8s/tkey-issues/issues/1) 108 | 109 | ## Sponsors 110 | 111 | - 暂无 112 | 113 | ## Backer 114 | 115 | - [我要喝喜茶 Orz..](http://www.youmeek.com/donate/) 116 | 117 | 118 | ## Join 119 | 120 | - 邮箱:`cdk8s#qq.com` 121 | - 博客: 122 | - Github: 123 | - Gitee: 124 | - 公众号 125 | 126 | ![公众号](http://img.gitnavi.com/markdown/cdk8s_qr_300px.png) 127 | 128 | 129 | ## Jobs 130 | 131 | - 我们在广州 132 | - 有广州或深圳的合作、Offer 欢迎联系我们 133 | - 邮箱:`cdk8s#qq.com` 134 | - 公众号:`联系我们` 135 | 136 | ## Thanks 137 | 138 | - [IntelliJ IDEA](https://www.jetbrains.com/idea/) 139 | - [CAS](https://github.com/apereo/cas) 140 | - [Okta](https://www.okta.com/) 141 | 142 | 143 | ## Copyright And License 144 | 145 | - Copyright (c) CDK8S. All rights reserved. 146 | - Licensed under the **MIT** license. 147 | - **再次强调: 因为是 MIT 协议,大家有不满意的,除了 PR 也可以 fork 后自己尽情改造!** 148 | 149 | 150 | 151 | -------------------------------------------------------------------------------- /other/tkey-baisc.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | ## 个人认知 4 | 5 | - 在稍微大一点点的公司中,有两个基础系统是必然有的:一个是:SSO(单点登录系统),一个是 UPMS(通用用户权限管理系统) 6 | - 而这两个系统都是很难完全地直接套用开源框架。因为,在这类规模公司中,基本已经有成气候的系统、用户,这部分用户体系,不可能说换就换。一般是要反过来设置:让新系统去适应现有的账号系统、权限管理体系。 7 | - 目前单点登录技术选型中,用得比较多的有:CAS、Keycloak、Spring Security OAuth2 8 | - 其中 Keycloak 除了认证还带各种授权玩法,整个体系的规划挺好的,适合业务的一开始阶段。如果是成规模之后再考虑要使用它,改造成本很大。 9 | - CAS 什么都好,支持了各种扩展接口,几百个可扩展的子模块。但是,这么大的项目现在就一个人维护,他既要开发又要写文档、写测试,实在是难为他了。记忆深刻 2017 年他嫌提问的人太 low、太麻烦,直接把 issues 关了,至今未开。而且这家伙非常喜欢用新版本,JDK、Spring Boot 动不动就升级。现在想起研究它的那段时间,简直了...Orz 10 | - Spring Security OAuth2 是 Spring Cloud 流行之后大家非常喜欢用的一个系统。目前来说真的没啥缺点,不管是可读性、可维护性、可变更性等方面上,大家都很喜欢。但是,不够灵活,业务上的灵活,特别是国内各种非工程化思维下的各种特殊要求。我不觉得老板们这些需求不合理,但是基于这些开源系统真的好难。 11 | - 所以,我写了 TKey,目标很明确:需求总是各种各样,我没办法帮大家做好扩展,那我就帮大家写好文档。你们自己知道怎么用,自己爱怎么改就怎么改。 12 | 13 | 14 | ## OAuth 核心(比较绕) 15 | 16 | - TKey 的接口是按照 OAuth 2.0 规范来,所以必须了解这个。 17 | - OAuth 2.0 是规范、是安全标准,不是框架。它的核心逻辑是:颁发 Token,使用 Token 18 | - OAuth 2.0 规范定义了授权协议,不是身份认证协议 19 | - OAuth 2.0 广泛用于各大开放平台,比如大家常接触的 QQ、微信等平台 20 | - 认证系统可以支持很多协议,比如 SAML、LDAP 等,OAuth 2.0 可以只是其中的一种。 21 | - 单单的 OAuth 2.0 协议是做不了一个认证系统 22 | - OpenID Connect 开放协议是建立在 OAuth 2.0 之上的,它就可以作为认证协议 23 | - 除了 OpenID Connect,基于 OAuth 2.0 构建的协议还有很多,UMA、HEART、iGov 等 24 | - TKey 作为认证系统的认证核心是: 25 | - 用户持有的 TGC 令牌(ID 令牌),它才是代表着用户信息,代表着认证系统的登录证明。用户与登录系统之间是用 TGC 来连接。TGC 生成方法:`oauthGenerateService.generateTgc();` 26 | - OAuth 所颁发的 Token 是让客户端系统(业务系统)与认证系统之间进行连接 27 | - TKey 基于 OAuth 2.0 进行设计的的最大好处在于它是通用标准,在让别人来对接我们登录系统的时候只要按照标准即可 28 | - 所以,可以把接入 TKey 过程理解成接入 QQ 开放平台、微信开放平台过程 29 | - 授权码模式时序图 30 | 31 | ![授权码模式时序图](http://img.gitnavi.com/tkey/tkey-oauth.png) 32 | 33 | 34 | ------------------------------------------------------------------- 35 | 36 | 37 | ## 常见登录系统 38 | 39 | - 最优秀登录系统:Google Accounts 40 | - 在 Google 那么多产品中,登录这件事是那么的经典而自然,永远的地方都是: 41 | - 较一般的:腾讯、阿里等 42 | - 阿里的淘宝和天猫是同一个用户体系,阿里云是另外一个体系。 43 | - 腾讯的 QQ 和微信各自独立 44 | - 百度普通用户和百度智能云用户也是两个用户体系 45 | - 类似 Okta 这类新玩法,当前国内 saas 丰富度还不够,暂时比较艰难 46 | 47 | ## 登录系统的几种场景 48 | 49 | - **最核心的点:** 对于业务系统来讲,有没有前置的 API 网关影响一生 50 | - **API 网关作用:** 路由、过滤、身份验证、鉴权、限流、熔断、重试、监控、负载、版本/灰度发布、缓存等等 51 | - API 网关是所有请求的第一道入口,如果你们公司刚好再做整体系统架构调整,要引入单点登录系统之前,我建议一同连同 API 网关一起调研了 52 | 53 | ## 开放平台的登录系统 54 | 55 | - 类似 QQ 第三方登录过程 56 | - 你需要找 QQ 开放平台先申请 AppId + AppKey 57 | - 也有人叫做:AppKey + AppSecret; ClientId + ClientSecret 58 | - OAuth 2.0 规范的标准叫法是:ClientId + ClientSecret,[具体点击查看](https://tools.ietf.org/html/rfc6749#section-11.2.2) 59 | - 采用授权码模式拿到 QQ 平台给你的 AccessToken 60 | - 这个 AccessToken 你只能获取到用户基本信息 61 | - 在你调用 QQ 平台的所有接口过程中,必须带上该 AccessToken,不然它不知道是谁在调用 62 | - 你只能跟 QQ 开放平台打交道,你不能拿着这个 AccessToken 去调用微信开放平台 63 | 64 | 65 | ## 有 API 网关的同构业务系统 66 | 67 | - 比如 Spring 的 Spring Cloud 体系 68 | - 对身份进行认证全部交给 Gateway、Zuul,内部的业务系统只要管理好自己的 API 服务即可 69 | - 在 Spring Cloud 体系中,内部的服务都是在内网中,都是设定彼此之间是安全的 70 | 71 | 72 | ## 有 API 网关的异构业务系统 73 | 74 | - 有的公司有好几个研发中心、研发部门,各自采用各自的业务系统架构(历史原因) 75 | - 引入 Kong、Tyk、OpenResty + Lua 等 API 网关之后,各个业务系统在网关后面,身份验证也是交给网关 76 | 77 | 78 | ## 无 API 网关的同构 / 异构系统 79 | 80 | - **这种场景在中型公司转型过程中基本都要遇到,我个人建议是 API 网关和单点登录一起抓** 81 | - 这里说下在有单点登录系统情况下,但没有 API 网关的跨系统调用 82 | - 业务系统 A 在单点登录系统登录成功后拿到属于自己的 Token-A 83 | - 当同一个浏览器访问业务系统 B 的时候,B 系统也是需要登录的,但是因为单点登录系统已经知道当前浏览器是谁在用,所以直接给业务系统 B 颁发了 Token-B。这个过程用户无需重新登录,也就单点登录了 84 | - 业务系统 A 自己维 Session-A 与 Token-A 之间的关系 85 | - 业务系统 B 自己维 Session-B 与 Token-B 之间的关系 86 | - 这时候业务系统 A 要调用业务系统 B,必须拿着 Token-A 去找业务系统 B 87 | - 业务系统 B 拿到请求中的 Token-A 会找单点系统询问该 Token-A 是否有效,以及 Token-A 对应用户信息是谁 88 | - 业务系统 B 知道当前请求是谁之后就会放开请求 89 | - 这个过程是一个瓶颈 90 | - 如果业务系统 B 自己不存储这些 Token-A,则每次都要询问单点登录系统,单点登录系统压力会很大 91 | - 如果业务系统 B 自己存储这些 Token-A,则 Token-A 的时效性就有偏差 92 | 93 | 94 | ## OAuth 2.0 与 JWT 95 | 96 | - 现在有很多人喜欢用 Spring Security OAuth + JWT 构建登录系统 97 | - JWT 的自包含、防篡改的特点让很多人喜欢,可以省掉最让人烦的集中式的令牌,实现无状态。 98 | - 可是,这是有场景限制的。比如主动吊销 Token 要如何处理、有效时长如何动态控制、密钥如何动态切换。 99 | - 如果没有主动吊销 Token 的业务需求,那自包含的特点确实很有用,只是看大家的业务场景了。 100 | 101 | 102 | 103 | ------------------------------------------------------------------- 104 | 105 | ## 其他核心术语认知(提供了查询入口) 106 | 107 | > 架构设计 无状态 108 | 109 | - [Google 搜索](https://www.google.com/search?q=%E6%9E%B6%E6%9E%84%E8%AE%BE%E8%AE%A1%20%E6%97%A0%E7%8A%B6%E6%80%81) 110 | - [Baidu 搜索](https://www.baidu.com/baidu?wd=%E6%9E%B6%E6%9E%84%E8%AE%BE%E8%AE%A1%20%E6%97%A0%E7%8A%B6%E6%80%81) 111 | 112 | > 认证 与 授权 的区别 113 | 114 | - [Google 搜索](https://www.google.com/search?q=%E8%AE%A4%E8%AF%81%20%E4%B8%8E%20%E6%8E%88%E6%9D%83%20%E7%9A%84%E5%8C%BA%E5%88%AB) 115 | - [Baidu 搜索](https://www.baidu.com/baidu?wd=%E8%AE%A4%E8%AF%81%20%E4%B8%8E%20%E6%8E%88%E6%9D%83%20%E7%9A%84%E5%8C%BA%E5%88%AB) 116 | 117 | > HTTP 请求头:User-Agent 118 | 119 | - [Google 搜索](https://www.google.com/search?q=HTTP%20%E8%AF%B7%E6%B1%82%E5%A4%B4%EF%BC%9AUser-Agent) 120 | - [Baidu 搜索](https://www.baidu.com/baidu?wd=HTTP%20%E8%AF%B7%E6%B1%82%E5%A4%B4%EF%BC%9AUser-Agent) 121 | 122 | > HTTP 状态码:301 302 401 403 123 | 124 | - [Google 搜索](https://www.google.com/search?q=HTTP%20%E7%8A%B6%E6%80%81%E7%A0%81%EF%BC%9A301%20302%20401%20403) 125 | - [Baidu 搜索](https://www.baidu.com/baidu?wd=HTTP%20%E7%8A%B6%E6%80%81%E7%A0%81%EF%BC%9A301%20302%20401%20403) 126 | 127 | > 跨域 128 | 129 | - [Google 搜索](https://www.google.com/search?q=%E8%B7%A8%E5%9F%9F) 130 | - [Baidu 搜索](https://www.baidu.com/baidu?wd=%E8%B7%A8%E5%9F%9F) 131 | 132 | > 分布式 无状态 133 | 134 | - [Google 搜索](https://www.google.com/search?q=%E5%88%86%E5%B8%83%E5%BC%8F%20%E6%97%A0%E7%8A%B6%E6%80%81) 135 | - [Baidu 搜索](https://www.baidu.com/baidu?wd=%E5%88%86%E5%B8%83%E5%BC%8F%20%E6%97%A0%E7%8A%B6%E6%80%81) 136 | 137 | > 中间人攻击 138 | 139 | - [Google 搜索](https://www.google.com/search?q=%E4%B8%AD%E9%97%B4%E4%BA%BA%E6%94%BB%E5%87%BB) 140 | - [Baidu 搜索](https://www.baidu.com/baidu?wd=%E4%B8%AD%E9%97%B4%E4%BA%BA%E6%94%BB%E5%87%BB) 141 | 142 | > 重放攻击 143 | 144 | - [Google 搜索](https://www.google.com/search?q=%E9%87%8D%E6%94%BE%E6%94%BB%E5%87%BB) 145 | - [Baidu 搜索](https://www.baidu.com/baidu?wd=%E9%87%8D%E6%94%BE%E6%94%BB%E5%87%BB) 146 | 147 | > Session 与 Cookie 148 | 149 | - [Google 搜索](https://www.google.com/search?q=Session%20%E4%B8%8E%20Cookie) 150 | - [Baidu 搜索](https://www.baidu.com/baidu?wd=Session%20%E4%B8%8E%20Cookie) 151 | 152 | > Tomcat JSESSIONID 作用 153 | 154 | - [Google 搜索](https://www.google.com/search?q=Tomcat%20JSESSIONID%20%E4%BD%9C%E7%94%A8) 155 | - [Baidu 搜索](https://www.baidu.com/baidu?wd=Tomcat%20JSESSIONID%20%E4%BD%9C%E7%94%A8) 156 | 157 | > Cookie HttpOnly secure 158 | 159 | - [Google 搜索](https://www.google.com/search?q=Cookie%20HttpOnly%20secure) 160 | - [Baidu 搜索](https://www.baidu.com/baidu?wd=Cookie%20HttpOnly%20secure) 161 | 162 | > LocalStorage 与 SessionStorage 163 | 164 | - [Google 搜索](https://www.google.com/search?q=LocalStorage%20%E4%B8%8E%20SessionStorage) 165 | - [Baidu 搜索](https://www.baidu.com/baidu?wd=LocalStorage%20%E4%B8%8E%20SessionStorage) 166 | 167 | > Basic Auth Bearer Token 168 | 169 | - [Google 搜索](https://www.google.com/search?q=Basic%20Auth%20Bearer%20Token) 170 | - [Baidu 搜索](https://www.baidu.com/baidu?wd=Basic%20Auth%20Bearer%20Token) 171 | 172 | > OAuth 2.0 四种授权模式 173 | 174 | - [Google 搜索](https://www.google.com/search?q=OAuth%202.0%20%E5%9B%9B%E7%A7%8D%E6%8E%88%E6%9D%83%E6%A8%A1%E5%BC%8F) 175 | - [Baidu 搜索](https://www.baidu.com/baidu?wd=OAuth%202.0%20%E5%9B%9B%E7%A7%8D%E6%8E%88%E6%9D%83%E6%A8%A1%E5%BC%8F) 176 | - 授权码模式把步骤拆开,最核心的点:保证了是客户端本身进行的身份认证。简化模式就做不到,所以不推荐简化模式。 177 | 178 | > OAuth 2.0 state CSRF 179 | 180 | - [Google 搜索](https://www.google.com/search?q=OAuth%202.0%20state%20CSRF) 181 | - [Baidu 搜索](https://www.baidu.com/baidu?wd=OAuth%202.0%20state%20CSRF) 182 | 183 | > OAuth 2.0 redirect_uri 验证 184 | 185 | - [Google 搜索](https://www.google.com/search?q=OAuth%202.0%20redirect_uri%20%E9%AA%8C%E8%AF%81) 186 | - [Baidu 搜索](https://www.baidu.com/baidu?wd=OAuth%202.0%20redirect_uri%20%E9%AA%8C%E8%AF%81) 187 | 188 | > API 网关的作用 189 | 190 | - [Google 搜索](https://www.google.com/search?q=API%20%E7%BD%91%E5%85%B3%E7%9A%84%E4%BD%9C%E7%94%A8) 191 | - [Baidu 搜索](https://www.baidu.com/baidu?wd=API%20%E7%BD%91%E5%85%B3%E7%9A%84%E4%BD%9C%E7%94%A8) 192 | 193 | > UPMS 用户权限管理系统 194 | 195 | - [Google 搜索](https://www.google.com/search?q=UPMS%20%E7%94%A8%E6%88%B7%E6%9D%83%E9%99%90%E7%AE%A1%E7%90%86%E7%B3%BB%E7%BB%9F) 196 | - [Baidu 搜索](https://www.baidu.com/baidu?wd=UPMS%20%E7%94%A8%E6%88%B7%E6%9D%83%E9%99%90%E7%AE%A1%E7%90%86%E7%B3%BB%E7%BB%9F) 197 | 198 | 199 | 200 | -------------------------------------------------------------------------------- /share-file/postman/tkey-sso-server-api_collection_2.1_format.json: -------------------------------------------------------------------------------- 1 | { 2 | "info": { 3 | "_postman_id": "be664928-7ed2-41c3-994e-da8b4adde66a", 4 | "name": "tkey-sso-server-api", 5 | "schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json" 6 | }, 7 | "item": [ 8 | { 9 | "name": "tkey-sso-client-rest-demo", 10 | "item": [ 11 | { 12 | "name": "通用", 13 | "item": [ 14 | { 15 | "name": "刷新token", 16 | "request": { 17 | "method": "POST", 18 | "header": [ 19 | { 20 | "key": "Content-Type", 21 | "value": "application/x-www-form-urlencoded" 22 | } 23 | ], 24 | "body": { 25 | "mode": "urlencoded", 26 | "urlencoded": [ 27 | { 28 | "key": "grant_type", 29 | "value": "refresh_token", 30 | "type": "text" 31 | }, 32 | { 33 | "key": "refresh_token", 34 | "value": "RT-103-8aI3zHbArcmzT3ukHlBQ88AdMv2NB8Aa", 35 | "type": "text" 36 | }, 37 | { 38 | "key": "client_id", 39 | "value": "test_client_id_1", 40 | "type": "text" 41 | }, 42 | { 43 | "key": "client_secret", 44 | "value": "test_client_secret_1", 45 | "type": "text" 46 | } 47 | ] 48 | }, 49 | "url": { 50 | "raw": "http://sso.cdk8s.com:9091/sso/oauth/token", 51 | "protocol": "http", 52 | "host": [ 53 | "sso", 54 | "cdk8s", 55 | "com" 56 | ], 57 | "port": "9091", 58 | "path": [ 59 | "sso", 60 | "oauth", 61 | "token" 62 | ] 63 | } 64 | }, 65 | "response": [] 66 | }, 67 | { 68 | "name": "校验 AccessToken", 69 | "request": { 70 | "method": "POST", 71 | "header": [ 72 | { 73 | "key": "Content-Type", 74 | "value": "application/x-www-form-urlencoded" 75 | } 76 | ], 77 | "body": { 78 | "mode": "urlencoded", 79 | "urlencoded": [ 80 | { 81 | "key": "client_id", 82 | "value": "test_client_id_1", 83 | "type": "text" 84 | }, 85 | { 86 | "key": "client_secret", 87 | "value": "test_client_secret_1", 88 | "type": "text" 89 | }, 90 | { 91 | "key": "token", 92 | "value": "AT-102-dJTLEsFLR2PbxU1l8GPx3CUS9O3Lhzdn", 93 | "type": "text" 94 | }, 95 | { 96 | "key": "token_type_hint", 97 | "value": "access_token", 98 | "type": "text" 99 | } 100 | ] 101 | }, 102 | "url": { 103 | "raw": "http://sso.cdk8s.com:9091/sso/oauth/introspect", 104 | "protocol": "http", 105 | "host": [ 106 | "sso", 107 | "cdk8s", 108 | "com" 109 | ], 110 | "port": "9091", 111 | "path": [ 112 | "sso", 113 | "oauth", 114 | "introspect" 115 | ] 116 | } 117 | }, 118 | "response": [] 119 | }, 120 | { 121 | "name": "校验 RefreshToken", 122 | "request": { 123 | "method": "POST", 124 | "header": [ 125 | { 126 | "key": "Content-Type", 127 | "value": "application/x-www-form-urlencoded" 128 | } 129 | ], 130 | "body": { 131 | "mode": "urlencoded", 132 | "urlencoded": [ 133 | { 134 | "key": "client_id", 135 | "value": "test_client_id_1", 136 | "type": "text" 137 | }, 138 | { 139 | "key": "client_secret", 140 | "value": "test_client_secret_1", 141 | "type": "text" 142 | }, 143 | { 144 | "key": "token", 145 | "value": "RT-103-8aI3zHbArcmzT3ukHlBQ88AdMv2NB8Aa", 146 | "type": "text" 147 | }, 148 | { 149 | "key": "token_type_hint", 150 | "value": "refresh_token", 151 | "type": "text" 152 | } 153 | ] 154 | }, 155 | "url": { 156 | "raw": "http://sso.cdk8s.com:9091/sso/oauth/introspect", 157 | "protocol": "http", 158 | "host": [ 159 | "sso", 160 | "cdk8s", 161 | "com" 162 | ], 163 | "port": "9091", 164 | "path": [ 165 | "sso", 166 | "oauth", 167 | "introspect" 168 | ] 169 | } 170 | }, 171 | "response": [] 172 | }, 173 | { 174 | "name": "获取用户信息-POST", 175 | "request": { 176 | "method": "POST", 177 | "header": [ 178 | { 179 | "key": "Content-Type", 180 | "value": "application/x-www-form-urlencoded" 181 | } 182 | ], 183 | "body": { 184 | "mode": "urlencoded", 185 | "urlencoded": [ 186 | { 187 | "key": "access_token", 188 | "value": "RT-103-8aI3zHbArcmzT3ukHlBQ88AdMv2NB8Aa", 189 | "type": "text" 190 | } 191 | ] 192 | }, 193 | "url": { 194 | "raw": "http://sso.cdk8s.com:9091/sso/oauth/userinfo", 195 | "protocol": "http", 196 | "host": [ 197 | "sso", 198 | "cdk8s", 199 | "com" 200 | ], 201 | "port": "9091", 202 | "path": [ 203 | "sso", 204 | "oauth", 205 | "userinfo" 206 | ] 207 | } 208 | }, 209 | "response": [] 210 | }, 211 | { 212 | "name": "获取用户信息-GET", 213 | "request": { 214 | "method": "GET", 215 | "header": [], 216 | "url": { 217 | "raw": "http://sso.cdk8s.com:9091/sso/oauth/userinfo?access_token=AT-102-dJTLEsFLR2PbxU1l8GPx3CUS9O3Lhzdn", 218 | "protocol": "http", 219 | "host": [ 220 | "sso", 221 | "cdk8s", 222 | "com" 223 | ], 224 | "port": "9091", 225 | "path": [ 226 | "sso", 227 | "oauth", 228 | "userinfo" 229 | ], 230 | "query": [ 231 | { 232 | "key": "access_token", 233 | "value": "AT-102-dJTLEsFLR2PbxU1l8GPx3CUS9O3Lhzdn" 234 | } 235 | ] 236 | } 237 | }, 238 | "response": [] 239 | }, 240 | { 241 | "name": "登出", 242 | "request": { 243 | "method": "GET", 244 | "header": [], 245 | "url": { 246 | "raw": "http://sso.cdk8s.com:9091/sso/oauth/logout?redirect_uri=http://www.gitnavi.com", 247 | "protocol": "http", 248 | "host": [ 249 | "sso", 250 | "cdk8s", 251 | "com" 252 | ], 253 | "port": "9091", 254 | "path": [ 255 | "sso", 256 | "oauth", 257 | "logout" 258 | ], 259 | "query": [ 260 | { 261 | "key": "redirect_uri", 262 | "value": "http://www.gitnavi.com" 263 | } 264 | ] 265 | } 266 | }, 267 | "response": [] 268 | } 269 | ], 270 | "event": [ 271 | { 272 | "listen": "prerequest", 273 | "script": { 274 | "id": "0f576257-c509-4fba-8365-32522c551d70", 275 | "type": "text/javascript", 276 | "exec": [ 277 | "" 278 | ] 279 | } 280 | }, 281 | { 282 | "listen": "test", 283 | "script": { 284 | "id": "fb396949-c6f8-4969-8823-c3361694741a", 285 | "type": "text/javascript", 286 | "exec": [ 287 | "" 288 | ] 289 | } 290 | } 291 | ], 292 | "_postman_isSubFolder": true 293 | }, 294 | { 295 | "name": "简化模式", 296 | "item": [ 297 | { 298 | "name": "1.简化模式(使用浏览器访问)", 299 | "request": { 300 | "method": "GET", 301 | "header": [], 302 | "url": { 303 | "raw": "http://sso.cdk8s.com:9091/sso/oauth/authorize?response_type=token&client_id=test_client_id_1&redirect_uri=http://www.gitnavi.com", 304 | "protocol": "http", 305 | "host": [ 306 | "sso", 307 | "cdk8s", 308 | "com" 309 | ], 310 | "port": "9091", 311 | "path": [ 312 | "sso", 313 | "oauth", 314 | "authorize" 315 | ], 316 | "query": [ 317 | { 318 | "key": "response_type", 319 | "value": "token" 320 | }, 321 | { 322 | "key": "client_id", 323 | "value": "test_client_id_1" 324 | }, 325 | { 326 | "key": "redirect_uri", 327 | "value": "http://www.gitnavi.com" 328 | } 329 | ] 330 | } 331 | }, 332 | "response": [] 333 | }, 334 | { 335 | "name": "2.用户名、密码提交(用户触发的请求)", 336 | "request": { 337 | "method": "POST", 338 | "header": [ 339 | { 340 | "key": "Content-Type", 341 | "value": "application/x-www-form-urlencoded" 342 | } 343 | ], 344 | "body": { 345 | "mode": "urlencoded", 346 | "urlencoded": [ 347 | { 348 | "key": "username", 349 | "value": "myname", 350 | "type": "text" 351 | }, 352 | { 353 | "key": "password", 354 | "value": "123456", 355 | "type": "text" 356 | } 357 | ] 358 | }, 359 | "url": { 360 | "raw": "http://sso.cdk8s.com:9091/sso/oauth/authorize?response_type=token&client_id=test_client_id_1&redirect_uri=http://www.baidu.com", 361 | "protocol": "http", 362 | "host": [ 363 | "sso", 364 | "cdk8s", 365 | "com" 366 | ], 367 | "port": "9091", 368 | "path": [ 369 | "sso", 370 | "oauth", 371 | "authorize" 372 | ], 373 | "query": [ 374 | { 375 | "key": "response_type", 376 | "value": "token" 377 | }, 378 | { 379 | "key": "client_id", 380 | "value": "test_client_id_1" 381 | }, 382 | { 383 | "key": "redirect_uri", 384 | "value": "http://www.baidu.com" 385 | } 386 | ] 387 | } 388 | }, 389 | "response": [] 390 | } 391 | ], 392 | "_postman_isSubFolder": true 393 | }, 394 | { 395 | "name": "密码模式", 396 | "item": [ 397 | { 398 | "name": "密码模式", 399 | "request": { 400 | "method": "POST", 401 | "header": [ 402 | { 403 | "key": "Content-Type", 404 | "name": "Content-Type", 405 | "value": "application/x-www-form-urlencoded", 406 | "type": "text" 407 | } 408 | ], 409 | "body": { 410 | "mode": "urlencoded", 411 | "urlencoded": [ 412 | { 413 | "key": "grant_type", 414 | "value": "password", 415 | "type": "text" 416 | }, 417 | { 418 | "key": "client_id", 419 | "value": "test_client_id_1", 420 | "type": "text" 421 | }, 422 | { 423 | "key": "client_secret", 424 | "value": "test_client_secret_1", 425 | "type": "text" 426 | }, 427 | { 428 | "key": "username", 429 | "value": "admin", 430 | "type": "text" 431 | }, 432 | { 433 | "key": "password", 434 | "value": "123456", 435 | "type": "text" 436 | } 437 | ] 438 | }, 439 | "url": { 440 | "raw": "http://sso.cdk8s.com:9091/sso/oauth/token", 441 | "protocol": "http", 442 | "host": [ 443 | "sso", 444 | "cdk8s", 445 | "com" 446 | ], 447 | "port": "9091", 448 | "path": [ 449 | "sso", 450 | "oauth", 451 | "token" 452 | ] 453 | } 454 | }, 455 | "response": [] 456 | } 457 | ], 458 | "_postman_isSubFolder": true 459 | }, 460 | { 461 | "name": "客户端模式", 462 | "item": [ 463 | { 464 | "name": "客户端模式-GET", 465 | "request": { 466 | "method": "GET", 467 | "header": [], 468 | "url": { 469 | "raw": "http://sso.cdk8s.com:9091/sso/oauth/token?grant_type=client_credentials&client_id=test_client_id_1&client_secret=test_client_secret_1", 470 | "protocol": "http", 471 | "host": [ 472 | "sso", 473 | "cdk8s", 474 | "com" 475 | ], 476 | "port": "9091", 477 | "path": [ 478 | "sso", 479 | "oauth", 480 | "token" 481 | ], 482 | "query": [ 483 | { 484 | "key": "grant_type", 485 | "value": "client_credentials" 486 | }, 487 | { 488 | "key": "client_id", 489 | "value": "test_client_id_1" 490 | }, 491 | { 492 | "key": "client_secret", 493 | "value": "test_client_secret_1" 494 | } 495 | ] 496 | } 497 | }, 498 | "response": [] 499 | }, 500 | { 501 | "name": "客户端模式-POST", 502 | "request": { 503 | "method": "POST", 504 | "header": [ 505 | { 506 | "key": "Content-Type", 507 | "name": "Content-Type", 508 | "value": "application/x-www-form-urlencoded", 509 | "type": "text" 510 | } 511 | ], 512 | "body": { 513 | "mode": "urlencoded", 514 | "urlencoded": [ 515 | { 516 | "key": "grant_type", 517 | "value": "client_credentials", 518 | "type": "text" 519 | }, 520 | { 521 | "key": "client_id", 522 | "value": "test_client_id_1", 523 | "type": "text" 524 | }, 525 | { 526 | "key": "client_secret", 527 | "value": "test_client_secret_1", 528 | "type": "text" 529 | } 530 | ] 531 | }, 532 | "url": { 533 | "raw": "http://sso.cdk8s.com:9091/sso/oauth/token", 534 | "protocol": "http", 535 | "host": [ 536 | "sso", 537 | "cdk8s", 538 | "com" 539 | ], 540 | "port": "9091", 541 | "path": [ 542 | "sso", 543 | "oauth", 544 | "token" 545 | ] 546 | } 547 | }, 548 | "response": [] 549 | } 550 | ], 551 | "_postman_isSubFolder": true 552 | }, 553 | { 554 | "name": "授权码模式", 555 | "item": [ 556 | { 557 | "name": "1.登录页面(使用浏览器访问)", 558 | "request": { 559 | "method": "GET", 560 | "header": [], 561 | "url": { 562 | "raw": "http://sso.cdk8s.com:9091/sso/oauth/authorize?response_type=code&client_id=test_client_id_1&redirect_uri=http://test1.cdk8s.com:9094/client-rest/codeCallback/aHR0cDovL3Rlc3QxLmNkazhzLmNvbTo5MzkzL2NsaWVudC1zY3JpYmVqYXZhL3VzZXI_aWQ9MTIzNDU2Jm5hbWU9Y2RrOHM", 563 | "protocol": "http", 564 | "host": [ 565 | "sso", 566 | "cdk8s", 567 | "com" 568 | ], 569 | "port": "9091", 570 | "path": [ 571 | "sso", 572 | "oauth", 573 | "authorize" 574 | ], 575 | "query": [ 576 | { 577 | "key": "response_type", 578 | "value": "code" 579 | }, 580 | { 581 | "key": "client_id", 582 | "value": "test_client_id_1" 583 | }, 584 | { 585 | "key": "redirect_uri", 586 | "value": "http://test1.cdk8s.com:9094/client-rest/codeCallback/aHR0cDovL3Rlc3QxLmNkazhzLmNvbTo5MzkzL2NsaWVudC1zY3JpYmVqYXZhL3VzZXI_aWQ9MTIzNDU2Jm5hbWU9Y2RrOHM" 587 | } 588 | ] 589 | } 590 | }, 591 | "response": [] 592 | }, 593 | { 594 | "name": "2.用户名、密码提交(用户触发的请求)", 595 | "request": { 596 | "method": "POST", 597 | "header": [ 598 | { 599 | "key": "Content-Type", 600 | "value": "application/x-www-form-urlencoded" 601 | } 602 | ], 603 | "body": { 604 | "mode": "urlencoded", 605 | "urlencoded": [ 606 | { 607 | "key": "username", 608 | "value": "myname", 609 | "type": "text" 610 | }, 611 | { 612 | "key": "password", 613 | "value": "123456", 614 | "type": "text" 615 | } 616 | ] 617 | }, 618 | "url": { 619 | "raw": "http://sso.cdk8s.com:9091/sso/oauth/authorize?response_type=code&client_id=test_client_id_1&redirect_uri=http://test1.cdk8s.com:9094/client-rest/codeCallback/aHR0cDovL3Rlc3QxLmNkazhzLmNvbTo5MzkzL2NsaWVudC1zY3JpYmVqYXZhL3VzZXI_aWQ9MTIzNDU2Jm5hbWU9Y2RrOHM", 620 | "protocol": "http", 621 | "host": [ 622 | "sso", 623 | "cdk8s", 624 | "com" 625 | ], 626 | "port": "9091", 627 | "path": [ 628 | "sso", 629 | "oauth", 630 | "authorize" 631 | ], 632 | "query": [ 633 | { 634 | "key": "response_type", 635 | "value": "code" 636 | }, 637 | { 638 | "key": "client_id", 639 | "value": "test_client_id_1" 640 | }, 641 | { 642 | "key": "redirect_uri", 643 | "value": "http://test1.cdk8s.com:9094/client-rest/codeCallback/aHR0cDovL3Rlc3QxLmNkazhzLmNvbTo5MzkzL2NsaWVudC1zY3JpYmVqYXZhL3VzZXI_aWQ9MTIzNDU2Jm5hbWU9Y2RrOHM" 644 | } 645 | ] 646 | } 647 | }, 648 | "response": [] 649 | }, 650 | { 651 | "name": "3.code 换取 token", 652 | "request": { 653 | "method": "POST", 654 | "header": [ 655 | { 656 | "key": "Content-Type", 657 | "value": "application/x-www-form-urlencoded" 658 | } 659 | ], 660 | "body": { 661 | "mode": "urlencoded", 662 | "urlencoded": [ 663 | { 664 | "key": "grant_type", 665 | "value": "authorization_code", 666 | "type": "text" 667 | }, 668 | { 669 | "key": "code", 670 | "value": "OC-101-b2XiPTubgiOkyNYlM9n48XvoVIY9BxtF", 671 | "type": "text" 672 | }, 673 | { 674 | "key": "redirect_uri", 675 | "value": "http://test1.cdk8s.com:9094/client-rest/codeCallback/aHR0cDovL3Rlc3QxLmNkazhzLmNvbTo5MzkzL2NsaWVudC1zY3JpYmVqYXZhL3VzZXI_aWQ9MTIzNDU2Jm5hbWU9Y2RrOHM", 676 | "type": "text" 677 | }, 678 | { 679 | "key": "client_id", 680 | "value": "test_client_id_1", 681 | "type": "text" 682 | }, 683 | { 684 | "key": "client_secret", 685 | "value": "test_client_secret_1", 686 | "type": "text" 687 | } 688 | ] 689 | }, 690 | "url": { 691 | "raw": "http://sso.cdk8s.com:9091/sso/oauth/token", 692 | "protocol": "http", 693 | "host": [ 694 | "sso", 695 | "cdk8s", 696 | "com" 697 | ], 698 | "port": "9091", 699 | "path": [ 700 | "sso", 701 | "oauth", 702 | "token" 703 | ] 704 | } 705 | }, 706 | "response": [] 707 | } 708 | ], 709 | "_postman_isSubFolder": true 710 | }, 711 | { 712 | "name": "其他", 713 | "item": [ 714 | { 715 | "name": "Actuator-修改 log 输出级别", 716 | "request": { 717 | "auth": { 718 | "type": "noauth" 719 | }, 720 | "method": "POST", 721 | "header": [ 722 | { 723 | "key": "Content-Type", 724 | "value": "application/json" 725 | } 726 | ], 727 | "body": { 728 | "mode": "raw", 729 | "raw": "{\"configuredLevel\": \"INFO\"}" 730 | }, 731 | "url": { 732 | "raw": "http://sso.cdk8s.com:19091/tkey-actuator/actuator/loggers/com.cdk8s", 733 | "protocol": "http", 734 | "host": [ 735 | "sso", 736 | "cdk8s", 737 | "com" 738 | ], 739 | "port": "19091", 740 | "path": [ 741 | "tkey-actuator", 742 | "actuator", 743 | "loggers", 744 | "com.cdk8s" 745 | ] 746 | } 747 | }, 748 | "response": [] 749 | } 750 | ], 751 | "_postman_isSubFolder": true 752 | } 753 | ] 754 | } 755 | ] 756 | } -------------------------------------------------------------------------------- /deployment/deployment-core.md: -------------------------------------------------------------------------------- 1 | 2 | # TKey 环境 3 | 4 | - CentOS 7.5 x64 5 | 6 | ## 修改 SSH 端口 7 | 8 | - 配置文件介绍(记得先备份):`sudo vim /etc/ssh/sshd_config` 9 | - 打开这一行注释:Port 22 10 | - 自定义端口选择建议在万位的端口,如:10000-65535之间,假设这里我改为 52221 11 | - CentOS 7:添加端口:`firewall-cmd --zone=public --add-port=52221/tcp --permanent` 12 | - 重启防火墙:`firewall-cmd --reload` 13 | - CentOS 7 命令:`systemctl restart sshd.service` 14 | 15 | ## 安装后的检测 16 | 17 | ``` 18 | docker --version && docker-compose --version && java -version && mvn -v && mysql --version && redis-server --version && node -v && npm -v && nginx -V 19 | ``` 20 | 21 | 22 | ## 设置免密登录 23 | 24 | - 在 A 机器上输入命令:`ssh-keygen` 25 | - 根据提示回车,共有三次交互提示,都回车即可。 26 | - 生成的密钥目录在:**/root/.ssh** 27 | - 写入:`cat /root/.ssh/id_rsa.pub >> /root/.ssh/authorized_keys` 28 | - 测试:`ssh localhost` 29 | 30 | ## 安装 ansible 31 | 32 | - CentOS:`sudo yum install -y ansible` 33 | - 查看版本:`ansible --version` 34 | - 编辑配置文件:`vim /etc/ansible/hosts`,在文件尾部添加: 35 | - 查看自己的内网 ip:`ifconfig`,假设是:172.16.16.4 36 | 37 | ``` 38 | [local] 39 | 172.16.16.4 ansible_ssh_port=52221 40 | ``` 41 | 42 | - 让远程所有主机都执行 `ps` 命令,输出如下 43 | 44 | ``` 45 | ansible all -a 'ps' 46 | ``` 47 | 48 | 49 | ## 基础设置 50 | 51 | - 禁用 52 | - firewalld 53 | - selinux 54 | - swap 55 | - 安装 56 | - zip unzip lrzsz git wget htop deltarpm 57 | - zsh vim 58 | - docker docker-compose 59 | 60 | - 创建脚本文件:`vim /opt/1-install-basic-playbook.yml` 61 | 62 | ``` 63 | - hosts: all 64 | remote_user: root 65 | tasks: 66 | - name: Disable SELinux at next reboot 67 | selinux: 68 | state: disabled 69 | 70 | - name: disable firewalld 71 | shell: "{{ item }}" 72 | with_items: 73 | - systemctl stop firewalld 74 | - systemctl disable firewalld 75 | - echo "vm.swappiness = 0" >> /etc/sysctl.conf 76 | - swapoff -a 77 | - sysctl -w vm.swappiness=0 78 | 79 | - name: install-epel 80 | shell: "{{ item }}" 81 | with_items: 82 | - yum install -y epel-release 83 | 84 | - name: install-basic 85 | shell: "{{ item }}" 86 | with_items: 87 | - yum install -y zip unzip lrzsz git wget htop deltarpm 88 | 89 | - name: install zsh oh-my-zsh 90 | shell: "{{ item }}" 91 | with_items: 92 | - yum install -y zsh 93 | - wget https://gitee.com/mirrors/oh-my-zsh/raw/master/tools/install.sh -O - | sh 94 | - chsh -s /bin/zsh root 95 | 96 | - name: install-vim 97 | shell: "{{ item }}" 98 | with_items: 99 | - yum install -y vim 100 | - curl https://gitee.com/cdk8s_org/vim-for-server/raw/master/vimrc > ~/.vimrc 101 | 102 | - name: install-docker 103 | shell: "{{ item }}" 104 | with_items: 105 | - yum install -y yum-utils device-mapper-persistent-data lvm2 106 | - yum-config-manager --add-repo http://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo 107 | - yum makecache fast 108 | - yum install -y docker-ce docker-ce-cli containerd.io 109 | - systemctl start docker.service 110 | 111 | - name: create /etc/docker directory 112 | file: 113 | path: /etc/docker 114 | state: directory 115 | 116 | - name: create daemon.json file 117 | file: 118 | path=/etc/docker/{{ item }} 119 | state=touch 120 | mode=777 121 | with_items: 122 | - daemon.json 123 | 124 | - name: set docker registry mirrors 125 | blockinfile: 126 | path: /etc/docker/daemon.json 127 | marker: "" 128 | block: | 129 | { 130 | "registry-mirrors": [ 131 | "https://ldhc17y9.mirror.aliyuncs.com", 132 | "https://hub-mirror.c.163.com", 133 | "https://mirror.baidubce.com", 134 | "https://docker.mirrors.ustc.edu.cn" 135 | ] 136 | } 137 | 138 | - name: restart docekr 139 | shell: "{{ item }}" 140 | with_items: 141 | - systemctl daemon-reload 142 | - systemctl restart docker 143 | 144 | - name: install-docker-compose 145 | shell: "{{ item }}" 146 | with_items: 147 | - curl -L https://get.daocloud.io/docker/compose/releases/download/1.26.2/docker-compose-`uname -s`-`uname -m` > /usr/local/bin/docker-compose 148 | - chmod +x /usr/local/bin/docker-compose 149 | - docker-compose --version 150 | - systemctl restart docker.service 151 | - systemctl enable docker.service 152 | ``` 153 | 154 | - docker compose 最新版本好可以看: 155 | - 执行:`ansible-playbook /opt/1-install-basic-playbook.yml` 156 | 157 | ## 离线安装 jdk 158 | 159 | - 下载 jdk 到 /opt 目录下 160 | - 创建脚本文件:`vim /opt/2-jdk8-playbook.yml` 161 | 162 | ``` 163 | - hosts: all 164 | remote_user: root 165 | vars: 166 | java_install_folder: /usr/local 167 | file_name: jdk-8u261-linux-x64.tar.gz 168 | tasks: 169 | - name: copy jdk 170 | copy: 171 | src=/opt/{{ file_name }} 172 | dest={{ java_install_folder }} 173 | 174 | - name: tar jdk 175 | shell: 176 | chdir={{ java_install_folder }} 177 | tar zxf {{ file_name }} 178 | 179 | - name: set JAVA_HOME 180 | blockinfile: 181 | path: /root/.zshrc 182 | marker: "#{mark} JDK ENV" 183 | block: | 184 | JAVA_HOME={{ java_install_folder }}/jdk1.8.0_261 185 | JRE_HOME=$JAVA_HOME/jre 186 | PATH=$PATH:$JAVA_HOME/bin 187 | CLASSPATH=.:$JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar 188 | export JAVA_HOME 189 | export JRE_HOME 190 | export PATH 191 | export CLASSPATH 192 | 193 | - name: source zshrc 194 | shell: source /root/.zshrc 195 | 196 | - name: remove tar.gz file 197 | file: 198 | state: absent 199 | path: "{{ java_install_folder }}/{{ file_name }}" 200 | ``` 201 | 202 | 203 | - 执行命令:`ansible-playbook /opt/2-jdk8-playbook.yml` 204 | 205 | 206 | 207 | ## 安装 maven 208 | 209 | 210 | - 把 maven 放到 /opt 目录下 211 | - 创建脚本文件:`vim /opt/3-maven-playbook.yml` 212 | 213 | ``` 214 | - hosts: all 215 | remote_user: root 216 | vars: 217 | maven_install_folder: /usr/local 218 | file_name: apache-maven-3.6.3-bin.zip 219 | tasks: 220 | - name: copy maven 221 | copy: 222 | src=/opt/{{ file_name }} 223 | dest={{ maven_install_folder }} 224 | 225 | - name: unzip maven 226 | shell: 227 | chdir={{ maven_install_folder }} 228 | unzip {{ file_name }} 229 | 230 | - name: set MAVEN_HOME 231 | blockinfile: 232 | path: /root/.zshrc 233 | marker: "#{mark} MAVEN ENV" 234 | block: | 235 | MAVEN_HOME={{ maven_install_folder }}/apache-maven-3.6.3 236 | M3_HOME={{ maven_install_folder }}/apache-maven-3.6.3 237 | M2_HOME={{ maven_install_folder }}/apache-maven-3.6.3 238 | PATH=$PATH:$M3_HOME/bin 239 | MAVEN_OPTS="-Xms256m -Xmx356m" 240 | export M3_HOME 241 | export M2_HOME 242 | export MAVEN_HOME 243 | export PATH 244 | export MAVEN_OPTS 245 | 246 | - name: source zshrc 247 | shell: source /root/.zshrc 248 | 249 | - name: remove zip file 250 | file: 251 | path: "{{ maven_install_folder }}/{{ file_name }}" 252 | state: absent 253 | 254 | - name: create local_maven_repository directory 255 | file: 256 | path: /opt/local_maven_repository 257 | state: directory 258 | 259 | - name: remove old settings.xml 260 | file: 261 | path: "{{ maven_install_folder }}/apache-maven-3.6.3/conf/settings.xml" 262 | state: absent 263 | 264 | - name: create settings.xml file 265 | file: 266 | path="{{ maven_install_folder }}/apache-maven-3.6.3/conf/{{ item }}" 267 | state=touch 268 | mode=777 269 | with_items: 270 | - settings.xml 271 | 272 | - name: set settings.xml aliyun 273 | blockinfile: 274 | path: "{{ maven_install_folder }}/apache-maven-3.6.3/conf/settings.xml" 275 | marker: "" 276 | block: | 277 | 278 | 281 | 282 | 283 | /opt/local_maven_repository 284 | 285 | 286 | 287 | 288 | 289 | 290 | 291 | 292 | 293 | 294 | 295 | 296 | aliyun 297 | 298 | 299 | aliyun 300 | http://maven.aliyun.com/nexus/content/groups/public/ 301 | 302 | true 303 | 304 | 305 | true 306 | 307 | 308 | 309 | 310 | 311 | aliyun 312 | http://maven.aliyun.com/nexus/content/groups/public/ 313 | 314 | true 315 | 316 | 317 | true 318 | 319 | 320 | 321 | 322 | 323 | maven 324 | 325 | 326 | maven 327 | https://repo.maven.apache.org/maven2/ 328 | 329 | true 330 | 331 | 332 | true 333 | 334 | 335 | 336 | 337 | 338 | maven 339 | https://repo.maven.apache.org/maven2/ 340 | 341 | true 342 | 343 | 344 | true 345 | 346 | 347 | 348 | 349 | 350 | 351 | 352 | aliyun 353 | 354 | 355 | 356 | ``` 357 | 358 | 359 | - 执行命令:`ansible-playbook /opt/3-maven-playbook.yml` 360 | 361 | 362 | ## 安装 node 363 | 364 | - 创建脚本文件:`vim /opt/4-node-playbook.yml` 365 | 366 | ``` 367 | - hosts: all 368 | remote_user: root 369 | tasks: 370 | - name: remove the nodejs 371 | yum: 372 | name: nodejs 373 | state: absent 374 | 375 | - name: remove the npm 376 | yum: 377 | name: npm 378 | state: absent 379 | 380 | - name: curl node 381 | shell: "curl --silent --location https://rpm.nodesource.com/setup_12.x | sudo bash -" 382 | 383 | - name: install node 384 | shell: "{{ item }}" 385 | with_items: 386 | - yum -y install nodejs 387 | 388 | - name: curl yarn 389 | shell: "curl --silent --location https://dl.yarnpkg.com/rpm/yarn.repo | sudo tee /etc/yum.repos.d/yarn.repo" 390 | 391 | - name: install yarn 392 | shell: "{{ item }}" 393 | with_items: 394 | - yum -y install yarn 395 | ``` 396 | 397 | 398 | - 执行命令:`ansible-playbook /opt/4-node-playbook.yml` 399 | 400 | ## 安装原生 MySQL 5.7(可选 Docker) 401 | 402 | - 创建脚本文件:`vim /opt/5-mysql-playbook.yml` 403 | 404 | ``` 405 | - hosts: all 406 | remote_user: root 407 | tasks: 408 | - name: remove the mariadb 409 | yum: 410 | name: mariadb 411 | state: absent 412 | 413 | - name: install mysql 1 414 | shell: "{{ item }}" 415 | with_items: 416 | - wget http://dev.mysql.com/get/mysql57-community-release-el7-11.noarch.rpm 417 | - yum localinstall -y mysql57-community-release-el7-11.noarch.rpm 418 | 419 | - name: install mysql 2 420 | yum: 421 | name: mysql-community-server 422 | 423 | - name: remove old /etc/my.cnf 424 | file: 425 | path: "/etc/my.cnf" 426 | state: absent 427 | 428 | - name: create my.cnf file 429 | file: 430 | path="/etc/{{ item }}" 431 | state=touch 432 | mode=777 433 | with_items: 434 | - my.cnf 435 | 436 | - name: set my.cnf 437 | blockinfile: 438 | path: /etc/my.cnf 439 | marker: "" 440 | block: | 441 | [mysql] 442 | default-character-set = utf8mb4 443 | [mysqld] 444 | max_connections = 500 445 | datadir = /var/lib/mysql 446 | socket = /var/lib/mysql/mysql.sock 447 | bind-address = 127.0.0.1 448 | symbolic-links=0 449 | log-error=/var/log/mysqld.log 450 | pid-file=/var/run/mysqld/mysqld.pid 451 | default-storage-engine = InnoDB 452 | collation-server = utf8mb4_unicode_520_ci 453 | init_connect = 'SET NAMES utf8mb4' 454 | character-set-server = utf8mb4 455 | lower_case_table_names = 1 456 | max_allowed_packet = 50M 457 | sql_mode=STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION 458 | 459 | - name: enable mysql 460 | shell: "{{ item }}" 461 | with_items: 462 | - systemctl enable mysqld.service 463 | - systemctl restart mysqld.service 464 | ``` 465 | 466 | - 执行命令:`ansible-playbook /opt/5-mysql-playbook.yml` 467 | 468 | 469 | 470 | ## 安装原生 Redis 5(可选 Docker) 471 | 472 | 473 | 474 | - 创建脚本文件:`vim /opt/6-redis-playbook.yml` 475 | 476 | ``` 477 | - hosts: all 478 | remote_user: root 479 | tasks: 480 | - name: install redis 481 | yum: 482 | name: redis 483 | 484 | - name: remove old /etc/redis.conf 485 | file: 486 | path: "/etc/redis.conf" 487 | state: absent 488 | 489 | - name: create /etc/redis.conf file 490 | file: 491 | path="/etc/{{ item }}" 492 | state=touch 493 | mode=777 494 | with_items: 495 | - redis.conf 496 | 497 | - name: set redis.conf 498 | blockinfile: 499 | path: /etc/redis.conf 500 | marker: "" 501 | block: | 502 | bind 0.0.0.0 503 | requirepass adgredis123456 504 | protected-mode yes 505 | port 6379 506 | tcp-backlog 511 507 | timeout 0 508 | tcp-keepalive 300 509 | daemonize no 510 | supervised no 511 | pidfile /var/run/redis_6379.pid 512 | loglevel notice 513 | logfile /var/log/redis/redis.log 514 | databases 16 515 | save 900 1 516 | save 300 10 517 | save 60 10000 518 | stop-writes-on-bgsave-error yes 519 | rdbcompression yes 520 | rdbchecksum yes 521 | dbfilename dump.rdb 522 | dir /var/lib/redis 523 | slave-serve-stale-data yes 524 | slave-read-only yes 525 | repl-diskless-sync no 526 | repl-diskless-sync-delay 5 527 | repl-disable-tcp-nodelay no 528 | slave-priority 100 529 | appendonly no 530 | appendfilename "appendonly.aof" 531 | appendfsync everysec 532 | no-appendfsync-on-rewrite no 533 | auto-aof-rewrite-percentage 100 534 | auto-aof-rewrite-min-size 64mb 535 | aof-load-truncated yes 536 | lua-time-limit 5000 537 | slowlog-log-slower-than 10000 538 | slowlog-max-len 128 539 | latency-monitor-threshold 0 540 | notify-keyspace-events "" 541 | hash-max-ziplist-entries 512 542 | hash-max-ziplist-value 64 543 | list-max-ziplist-size -2 544 | list-compress-depth 0 545 | set-max-intset-entries 512 546 | zset-max-ziplist-entries 128 547 | zset-max-ziplist-value 64 548 | hll-sparse-max-bytes 3000 549 | activerehashing yes 550 | client-output-buffer-limit normal 0 0 0 551 | client-output-buffer-limit slave 256mb 64mb 60 552 | client-output-buffer-limit pubsub 32mb 8mb 60 553 | hz 10 554 | aof-rewrite-incremental-fsync yes 555 | 556 | - name: enable redis 557 | shell: "{{ item }}" 558 | with_items: 559 | - systemctl enable redis 560 | - systemctl restart redis 561 | ``` 562 | 563 | - 执行命令:`ansible-playbook /opt/6-redis-playbook.yml` 564 | 565 | 566 | ------------------------------------------------------------------- 567 | 568 | ## 安装 Jenkins 569 | 570 | - 创建脚本文件:`vim /opt/jenkins-playbook.yml` 571 | 572 | ``` 573 | - hosts: all 574 | remote_user: root 575 | tasks: 576 | - name: wget 577 | shell: wget -O /etc/yum.repos.d/jenkins.repo https://pkg.jenkins.io/redhat-stable/jenkins.repo 578 | 579 | - name: rpm import 580 | shell: rpm --import https://pkg.jenkins.io/redhat-stable/jenkins.io.key 581 | 582 | - name: install 583 | shell: yum install -y jenkins 584 | ``` 585 | 586 | - 执行命令:`ansible-playbook /opt/jenkins-playbook.yml` 587 | - 在安装完默认推荐的插件后还需要额外安装: 588 | - `Maven Integration` 589 | - 设置 `全局工具配置` [点击我查看设置方法](https://upload-images.jianshu.io/upload_images/19119711-17eac75f51516b69.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) 590 | 591 | ------------------------------------------------------------------- 592 | 593 | ## 安装 Redis 5.x(Docker) 594 | 595 | ``` 596 | mkdir -p /data/docker/redis/conf /data/docker/redis/db 597 | chmod -R 777 /data/docker/redis 598 | ``` 599 | 600 | ``` 601 | 创建配置文件: 602 | vim /data/docker/redis/conf/redis.conf 603 | 604 | 605 | 606 | bind 0.0.0.0 607 | requirepass 123456 608 | protected-mode yes 609 | 610 | port 6379 611 | tcp-backlog 511 612 | timeout 0 613 | tcp-keepalive 300 614 | daemonize no 615 | supervised no 616 | pidfile /data/redis_6379.pid 617 | loglevel notice 618 | logfile "" 619 | databases 16 620 | always-show-logo yes 621 | save 900 1 622 | save 300 10 623 | save 60 10000 624 | stop-writes-on-bgsave-error yes 625 | rdbcompression yes 626 | rdbchecksum yes 627 | dbfilename dump.rdb 628 | dir /data 629 | replica-serve-stale-data yes 630 | replica-read-only yes 631 | repl-diskless-sync no 632 | repl-diskless-sync-delay 5 633 | repl-disable-tcp-nodelay no 634 | replica-priority 100 635 | lazyfree-lazy-eviction no 636 | lazyfree-lazy-expire no 637 | lazyfree-lazy-server-del no 638 | replica-lazy-flush no 639 | appendonly no 640 | appendfilename "appendonly.aof" 641 | appendfsync everysec 642 | no-appendfsync-on-rewrite no 643 | auto-aof-rewrite-percentage 100 644 | auto-aof-rewrite-min-size 64mb 645 | aof-load-truncated yes 646 | aof-use-rdb-preamble yes 647 | lua-time-limit 5000 648 | slowlog-log-slower-than 10000 649 | slowlog-max-len 128 650 | latency-monitor-threshold 0 651 | notify-keyspace-events "" 652 | hash-max-ziplist-entries 512 653 | hash-max-ziplist-value 64 654 | list-max-ziplist-size -2 655 | list-compress-depth 0 656 | set-max-intset-entries 512 657 | zset-max-ziplist-entries 128 658 | zset-max-ziplist-value 64 659 | hll-sparse-max-bytes 3000 660 | stream-node-max-bytes 4096 661 | stream-node-max-entries 100 662 | activerehashing yes 663 | client-output-buffer-limit normal 0 0 0 664 | client-output-buffer-limit replica 256mb 64mb 60 665 | client-output-buffer-limit pubsub 32mb 8mb 60 666 | hz 10 667 | dynamic-hz yes 668 | aof-rewrite-incremental-fsync yes 669 | rdb-save-incremental-fsync yes 670 | ``` 671 | 672 | - 启动镜像: 673 | 674 | ``` 675 | docker run \ 676 | --name cdk8s-redis \ 677 | --restart always \ 678 | -d -it -p 6379:6379 \ 679 | -v /data/docker/redis/conf/redis.conf:/etc/redis/redis.conf \ 680 | -v /data/docker/redis/db:/data \ 681 | redis:5 \ 682 | redis-server /etc/redis/redis.conf 683 | ``` 684 | 685 | ------------------------------------------------------------------- 686 | 687 | ## 安装 MySQL(Docker) 688 | 689 | ``` 690 | mkdir -p /data/docker/mysql/datadir /data/docker/mysql/conf /data/docker/mysql/log 691 | ``` 692 | 693 | ``` 694 | 创建配置文件: 695 | vim /data/docker/mysql/conf/mysql-1.cnf 696 | 697 | # 该编码设置是我自己配置的 698 | [mysql] 699 | default-character-set = utf8mb4 700 | 701 | # 下面内容是 docker mysql 默认的 start 702 | [mysqld] 703 | max_connections = 500 704 | pid-file = /var/run/mysqld/mysqld.pid 705 | socket = /var/run/mysqld/mysqld.sock 706 | datadir = /var/lib/mysql 707 | #log-error = /var/log/mysql/error.log 708 | # By default we only accept connections from localhost 709 | #bind-address = 127.0.0.1 710 | # Disabling symbolic-links is recommended to prevent assorted security risks 711 | symbolic-links=0 712 | # 上面内容是 docker mysql 默认的 end 713 | 714 | # 下面开始的内容就是我自己配置的 715 | log-error=/var/log/mysql/error.log 716 | default-storage-engine = InnoDB 717 | collation-server = utf8mb4_unicode_520_ci 718 | init_connect = 'SET NAMES utf8mb4' 719 | character-set-server = utf8mb4 720 | # 表名大小写敏感 0 是区分大小写,1 是不分区,全部采用小写 721 | lower_case_table_names = 1 722 | max_allowed_packet = 50M 723 | sql_mode=STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION 724 | 725 | # 避免在 dump 命令中加上密码后提示:Using a password on the command line interface can be insecure 726 | [mysqldump] 727 | user=root 728 | password=123456 729 | ``` 730 | 731 | ``` 732 | chmod -R 777 /data/docker/mysql/datadir /data/docker/mysql/log 733 | chown -R 0:0 /data/docker/mysql/conf 734 | ``` 735 | 736 | 737 | ``` 738 | docker run \ 739 | --name cdk8s-mysql \ 740 | --restart always \ 741 | -d \ 742 | -p 3306:3306 \ 743 | -v /data/docker/mysql/datadir:/var/lib/mysql \ 744 | -v /data/docker/mysql/log:/var/log/mysql \ 745 | -v /data/docker/mysql/conf:/etc/mysql/conf.d \ 746 | -e MYSQL_ROOT_PASSWORD=123456 \ 747 | mysql:5.7 748 | ``` 749 | 750 | ------------------------------------------------------------------- 751 | 752 | 753 | ## 安装 Prometheus(Docker) 754 | 755 | ``` 756 | 757 | 创建配置文件: 758 | mkdir -p /data/docker/prometheus/conf && vim /data/docker/prometheus/conf/prometheus.yml 759 | chmod -R 777 /data/docker/prometheus 760 | 761 | # my global config 762 | global: 763 | scrape_interval: 15s # Set the scrape interval to every 15 seconds. Default is every 1 minute. 764 | evaluation_interval: 15s # Evaluate rules every 15 seconds. The default is every 1 minute. 765 | # scrape_timeout is set to the global default (10s). 766 | 767 | # Alertmanager configuration 768 | alerting: 769 | alertmanagers: 770 | - static_configs: 771 | - targets: 772 | # - alertmanager:9093 773 | 774 | # Load rules once and periodically evaluate them according to the global 'evaluation_interval'. 775 | rule_files: 776 | # - "first_rules.yml" 777 | # - "second_rules.yml" 778 | 779 | 780 | scrape_configs: 781 | - job_name: 'cdk8s-sso' 782 | metrics_path: '/tkey-actuator/actuator/prometheus' 783 | static_configs: 784 | - targets: ['172.16.16.4:19091'] 785 | ``` 786 | 787 | 788 | - 启动 789 | 790 | ``` 791 | docker run \ 792 | -d \ 793 | --name cdk8s-prometheus \ 794 | --restart always \ 795 | -p 9090:9090 \ 796 | -v /data/docker/prometheus/conf/prometheus.yml:/etc/prometheus/prometheus.yml \ 797 | prom/prometheus 798 | ``` 799 | 800 | ------------------------------------------------------------------- 801 | 802 | 803 | ## 安装 Grafana(Docker) 804 | 805 | 806 | ``` 807 | mkdir -p /data/docker/grafana/data 808 | chmod -R 777 /data/docker/grafana/data 809 | 810 | docker run \ 811 | -d \ 812 | --name cdk8s-grafana \ 813 | --restart always \ 814 | -p 3000:3000 \ 815 | -v /data/docker/grafana/data:/var/lib/grafana \ 816 | grafana/grafana 817 | ``` 818 | 819 | - 820 | - 默认管理账号;admin,密码:admin,第一次登录后需要修改密码 821 | 822 | ------------------------------------------------------------------- 823 | 824 | ## 安装 Portainer(Docker) 825 | 826 | 827 | ``` 828 | mkdir -p /data/docker/portainer 829 | chmod -R 777 /data/docker/portainer 830 | ``` 831 | 832 | - 创建文件:`vim docker-compose.yml` 833 | 834 | ``` 835 | version: '3' 836 | services: 837 | portainer: 838 | container_name: portainer 839 | image: portainer/portainer 840 | volumes: 841 | - /data/docker/portainer:/data 842 | - /var/run/docker.sock:/var/run/docker.sock 843 | ports: 844 | - "9000:9000" 845 | ``` 846 | 847 | - 启动:`docker-compose up -d` 848 | - 浏览器访问访问: 849 | - 第一次启动会让你创建用户名和密码。第二步就是配置管理哪里的 docker 容器,我这里选择:local 850 | 851 | 852 | ------------------------------------------------------------------- 853 | 854 | 855 | ## 安装 Nginx(Docker) 856 | 857 | ``` 858 | mkdir -p /data/docker/nginx/logs /data/docker/nginx/conf /data/docker/nginx/html 859 | chmod -R 777 /data/docker/nginx 860 | ``` 861 | 862 | ``` 863 | 创建配置文件: 864 | vim /data/docker/nginx/conf/nginx.conf 865 | 866 | 867 | 868 | 869 | worker_processes 1; 870 | 871 | events { 872 | worker_connections 1024; 873 | } 874 | 875 | http { 876 | include mime.types; 877 | default_type application/octet-stream; 878 | 879 | sendfile on; 880 | keepalive_timeout 65; 881 | 882 | gzip on; 883 | gzip_buffers 8 16k; 884 | gzip_min_length 512; 885 | gzip_disable "MSIE [1-6]\.(?!.*SV1)"; 886 | gzip_http_version 1.1; 887 | gzip_types text/plain text/css application/javascript application/x-javascript application/json application/xml; 888 | 889 | server { 890 | listen 80; 891 | server_name localhost 127.0.0.1 191.112.221.203; 892 | 893 | location / { 894 | root /usr/share/nginx/html; 895 | index index.html index.htm; 896 | } 897 | } 898 | } 899 | ``` 900 | 901 | 902 | - 运行容器: 903 | 904 | ``` 905 | docker run \ 906 | -d \ 907 | --name cdk8s-nginx \ 908 | --restart always \ 909 | -p 80:80 \ 910 | -v /data/docker/nginx/logs:/var/log/nginx \ 911 | -v /data/docker/nginx/html:/data/html \ 912 | -v /data/docker/nginx/conf/nginx.conf:/etc/nginx/nginx.conf:ro \ 913 | nginx:1.17 914 | ``` 915 | 916 | - 重新启动服务:`docker restart cdk8s-nginx` 917 | 918 | ------------------------------------------------------------------- 919 | 920 | 921 | 922 | ## Jenkins pipeline (Docker 方式运行 tkey-sso-server) 923 | 924 | - **确保** 项目根目录有 Dockerfile 文件 925 | - 特别注意: 926 | 927 | ``` 928 | 这两个大写的名词来自 Jenkins 全局工具配置中相应配置的 name 中填写的内容 929 | jdk 'JDK8' 930 | maven 'MAVEN3' 931 | ``` 932 | 933 | ``` 934 | pipeline { 935 | agent any 936 | 937 | /*=======================================工具环境修改-start=======================================*/ 938 | tools { 939 | jdk 'JDK8' 940 | maven 'MAVEN3' 941 | } 942 | /*=======================================工具环境修改-end=======================================*/ 943 | 944 | options { 945 | timestamps() 946 | disableConcurrentBuilds() 947 | buildDiscarder(logRotator( 948 | numToKeepStr: '20', 949 | daysToKeepStr: '30', 950 | )) 951 | } 952 | 953 | /*=======================================常修改变量-start=======================================*/ 954 | 955 | environment { 956 | gitUrl = "https://github.com/cdk8s/tkey.git" 957 | branchName = "master" 958 | giteeCredentialsId = "cdk8s-github" 959 | projectWorkSpacePath = "${env.WORKSPACE}" 960 | projectBuildTargetPath = "${projectWorkSpacePath}/target" 961 | 962 | 963 | dockerImageName = "harbor.cdk8s.com/tkey/${env.JOB_NAME}:${env.BUILD_NUMBER}" 964 | dockerContainerName = "${env.JOB_NAME}" 965 | inHostPort = "9091" 966 | inHostPortByActuator = "19091" 967 | inDockerAndJavaPort = "9091" 968 | inDockerAndJavaPortByActuator = "19091" 969 | inHostLogPath = "/data/logs/${dockerContainerName}/${env.BUILD_NUMBER}" 970 | inDockerLogPath = "/logs" 971 | dockerRunParam = "--name=${dockerContainerName} --hostname=${dockerContainerName} -v /etc/hosts:/etc/hosts -v ${inHostLogPath}:${inDockerLogPath} --restart=always -p ${inHostPort}:${inDockerAndJavaPort} -p ${inHostPortByActuator}:${inDockerAndJavaPortByActuator} -e SPRING_PROFILES_ACTIVE=test -e SERVER_PORT=${inHostPort} -e SPRING_REDIS_HOST=redis.cdk8s.com -e SPRING_REDIS_PASSWORD=123456 -e TKEY_NODE_NUMBER=12" 972 | } 973 | 974 | /*=======================================常修改变量-end=======================================*/ 975 | 976 | stages { 977 | 978 | stage('Pre Env') { 979 | steps { 980 | echo "======================================项目名称 = ${env.JOB_NAME}" 981 | echo "======================================项目 URL = ${gitUrl}" 982 | echo "======================================项目分支 = ${branchName}" 983 | echo "======================================当前编译版本号 = ${env.BUILD_NUMBER}" 984 | echo "======================================项目空间文件夹路径 = ${projectWorkSpacePath}" 985 | echo "======================================项目 build 后 jar 路径 = ${projectBuildTargetPath}" 986 | echo "======================================Docker 镜像名称 = ${dockerImageName}" 987 | echo "======================================Docker 容器名称 = ${dockerContainerName}" 988 | } 989 | } 990 | 991 | stage('Git Clone'){ 992 | steps { 993 | git branch: "${branchName}", 994 | credentialsId: "${giteeCredentialsId}", 995 | url: "${gitUrl}" 996 | } 997 | } 998 | 999 | stage('Maven Clean') { 1000 | steps { 1001 | sh "mvn clean" 1002 | } 1003 | } 1004 | 1005 | stage('Maven Package') { 1006 | steps { 1007 | sh "mvn package -DskipTests" 1008 | } 1009 | } 1010 | 1011 | stage('构建 Docker 镜像') { 1012 | steps { 1013 | sh """ 1014 | cd ${projectWorkSpacePath} 1015 | 1016 | docker build -t ${dockerImageName} ./ 1017 | """ 1018 | } 1019 | } 1020 | 1021 | stage('运行 Docker 镜像') { 1022 | steps { 1023 | sh """ 1024 | docker stop ${dockerContainerName} | true 1025 | 1026 | docker rm -f ${dockerContainerName} | true 1027 | 1028 | docker run -d ${dockerRunParam} ${dockerImageName} 1029 | """ 1030 | } 1031 | } 1032 | 1033 | 1034 | } 1035 | } 1036 | ``` 1037 | 1038 | 1039 | 1040 | 1041 | 1042 | ## Jenkins pipeline (Docker 方式运行 tkey-sso-client-management 后端) 1043 | 1044 | - **确保** 项目根目录有 Dockerfile 文件 1045 | - 特别注意: 1046 | 1047 | ``` 1048 | 这两个大写的名词来自 Jenkins 全局工具配置中相应配置的 name 中填写的内容 1049 | jdk 'JDK8' 1050 | maven 'MAVEN3' 1051 | ``` 1052 | 1053 | ``` 1054 | pipeline { 1055 | agent any 1056 | 1057 | /*=======================================工具环境修改-start=======================================*/ 1058 | tools { 1059 | jdk 'JDK8' 1060 | maven 'MAVEN3' 1061 | } 1062 | /*=======================================工具环境修改-end=======================================*/ 1063 | 1064 | options { 1065 | timestamps() 1066 | disableConcurrentBuilds() 1067 | buildDiscarder(logRotator( 1068 | numToKeepStr: '20', 1069 | daysToKeepStr: '30', 1070 | )) 1071 | } 1072 | 1073 | /*=======================================常修改变量-start=======================================*/ 1074 | 1075 | environment { 1076 | gitUrl = "https://github.com/cdk8s/tkey-sso-client-management.git" 1077 | branchName = "master" 1078 | giteeCredentialsId = "cdk8s-github" 1079 | projectWorkSpacePath = "${env.WORKSPACE}" 1080 | projectBuildTargetPath = "${projectWorkSpacePath}/target" 1081 | 1082 | 1083 | dockerImageName = "harbor.cdk8s.com/tkey/${env.JOB_NAME}:${env.BUILD_NUMBER}" 1084 | dockerContainerName = "${env.JOB_NAME}" 1085 | inHostPort = "9095" 1086 | inHostPortByActuator = "19095" 1087 | inDockerAndJavaPort = "9095" 1088 | inDockerAndJavaPortByActuator = "19095" 1089 | inHostLogPath = "/data/logs/${dockerContainerName}/${env.BUILD_NUMBER}" 1090 | inDockerLogPath = "/logs" 1091 | dockerRunParam = "--name=${dockerContainerName} --hostname=${dockerContainerName} -v /etc/hosts:/etc/hosts -v ${inHostLogPath}:${inDockerLogPath} --restart=always -p ${inHostPort}:${inDockerAndJavaPort} -p ${inHostPortByActuator}:${inDockerAndJavaPortByActuator} -e SPRING_PROFILES_ACTIVE=test -e SERVER_PORT=${inHostPort} -e SPRING_REDIS_HOST=redis.cdk8s.com -e SPRING_REDIS_PASSWORD=123456" 1092 | } 1093 | 1094 | /*=======================================常修改变量-end=======================================*/ 1095 | 1096 | stages { 1097 | 1098 | stage('Pre Env') { 1099 | steps { 1100 | echo "======================================项目名称 = ${env.JOB_NAME}" 1101 | echo "======================================项目 URL = ${gitUrl}" 1102 | echo "======================================项目分支 = ${branchName}" 1103 | echo "======================================当前编译版本号 = ${env.BUILD_NUMBER}" 1104 | echo "======================================项目空间文件夹路径 = ${projectWorkSpacePath}" 1105 | echo "======================================项目 build 后 jar 路径 = ${projectBuildTargetPath}" 1106 | echo "======================================Docker 镜像名称 = ${dockerImageName}" 1107 | echo "======================================Docker 容器名称 = ${dockerContainerName}" 1108 | } 1109 | } 1110 | 1111 | stage('Git Clone'){ 1112 | steps { 1113 | git branch: "${branchName}", 1114 | credentialsId: "${giteeCredentialsId}", 1115 | url: "${gitUrl}" 1116 | } 1117 | } 1118 | 1119 | stage('Maven Clean') { 1120 | steps { 1121 | sh "mvn clean" 1122 | } 1123 | } 1124 | 1125 | stage('Maven Package') { 1126 | steps { 1127 | sh "mvn package -DskipTests" 1128 | } 1129 | } 1130 | 1131 | stage('构建 Docker 镜像') { 1132 | steps { 1133 | sh """ 1134 | cd ${projectWorkSpacePath} 1135 | 1136 | docker build -t ${dockerImageName} ./ 1137 | """ 1138 | } 1139 | } 1140 | 1141 | stage('运行 Docker 镜像') { 1142 | steps { 1143 | sh """ 1144 | docker stop ${dockerContainerName} | true 1145 | 1146 | docker rm -f ${dockerContainerName} | true 1147 | 1148 | docker run -d ${dockerRunParam} ${dockerImageName} 1149 | """ 1150 | } 1151 | } 1152 | 1153 | 1154 | } 1155 | } 1156 | ``` 1157 | 1158 | 1159 | 1160 | ## Jenkins pipeline (Docker 方式运行 tkey-sso-client-management 前端) 1161 | 1162 | 1163 | ``` 1164 | pipeline { 1165 | agent any 1166 | 1167 | options { 1168 | timestamps() 1169 | disableConcurrentBuilds() 1170 | buildDiscarder(logRotator( 1171 | numToKeepStr: '20', 1172 | daysToKeepStr: '30', 1173 | )) 1174 | } 1175 | 1176 | /*=======================================常修改变量-start=======================================*/ 1177 | 1178 | environment { 1179 | gitUrl = "https://github.com/cdk8s/tkey-sso-client-management-frontend.git" 1180 | branchName = "master" 1181 | giteeCredentialsId = "cdk8s-github" 1182 | projectBuildPath = "${env.WORKSPACE}/dist" 1183 | nginxHtmlRoot = "/data/docker/nginx/html/tkey-sso-client-management-frontend" 1184 | } 1185 | 1186 | /*=======================================常修改变量-end=======================================*/ 1187 | 1188 | stages { 1189 | 1190 | stage('Pre Env') { 1191 | steps { 1192 | echo "======================================项目名称 = ${env.JOB_NAME}" 1193 | echo "======================================项目 URL = ${gitUrl}" 1194 | echo "======================================项目分支 = ${branchName}" 1195 | echo "======================================当前编译版本号 = ${env.BUILD_NUMBER}" 1196 | echo "======================================项目 Build 文件夹路径 = ${projectBuildPath}" 1197 | echo "======================================项目 Nginx 的 ROOT 路径 = ${nginxHtmlRoot}" 1198 | } 1199 | } 1200 | 1201 | stage('Git Clone'){ 1202 | steps { 1203 | git branch: "${branchName}", 1204 | credentialsId: "${giteeCredentialsId}", 1205 | url: "${gitUrl}" 1206 | } 1207 | } 1208 | 1209 | stage('YARN Install') { 1210 | steps { 1211 | sh "yarn install" 1212 | } 1213 | } 1214 | 1215 | stage('YARN Build') { 1216 | steps { 1217 | sh "yarn build:test" 1218 | } 1219 | } 1220 | 1221 | stage('Nginx Deploy') { 1222 | steps { 1223 | sh "rm -rf ${nginxHtmlRoot}/" 1224 | sh "cp -r ${projectBuildPath}/ ${nginxHtmlRoot}/" 1225 | } 1226 | } 1227 | 1228 | 1229 | } 1230 | } 1231 | ``` 1232 | 1233 | ------------------------------------------------------------------- 1234 | 1235 | 1236 | ## GoAccess 1237 | 1238 | - GoAccess 建议用本地安装 1239 | - 安装步骤过长,请参考我们的这篇文章:[GoAccess](https://github.com/cdk8s/cdk8s-team-style/blob/master/os/linux/goaccess.md) 1240 | - 创建目录:`mkdir -p /data/docker/nginx/html/report` 1241 | - 手动运行 1242 | 1243 | ``` 1244 | goaccess -f /data/docker/nginx/logs/access.log --geoip-database=/opt/GeoLite2-City_20190820/GeoLite2-City.mmdb -p /etc/goaccess_log_conf_nginx.conf -o /data/docker/nginx/html/report/index.html 1245 | ``` 1246 | 1247 | - 实时运行 1248 | 1249 | ``` 1250 | goaccess -f /data/docker/nginx/logs/access.log --geoip-database=/opt/GeoLite2-City_20190820/GeoLite2-City.mmdb -p /etc/goaccess_log_conf_nginx.conf -o /data/docker/nginx/html/report/index.html --real-time-html --daemonize 1251 | ``` 1252 | 1253 | 1254 | ------------------------------------------------------------------- 1255 | 1256 | 1257 | 1258 | ## Nginx 最终配置 1259 | 1260 | - 因为 nginx 在 docker 里面,所以不能用 127.0.0.1 1261 | 1262 | ``` 1263 | 配置文件: 1264 | vim /data/docker/nginx/conf/nginx.conf 1265 | 1266 | 1267 | 1268 | worker_processes 1; 1269 | 1270 | events { 1271 | worker_connections 1024; 1272 | } 1273 | 1274 | http { 1275 | include mime.types; 1276 | default_type application/octet-stream; 1277 | 1278 | charset utf8; 1279 | 1280 | log_format main '$remote_addr - $remote_user [$time_local] "$request" ' 1281 | '$status $body_bytes_sent "$http_referer" ' 1282 | '"$http_user_agent" "$http_x_forwarded_for" "$request_time"'; 1283 | 1284 | access_log /var/log/nginx/access.log main; 1285 | error_log /var/log/nginx/error.log; 1286 | 1287 | 1288 | sendfile on; 1289 | keepalive_timeout 65; 1290 | 1291 | gzip on; 1292 | gzip_buffers 8 16k; 1293 | gzip_min_length 512; 1294 | gzip_disable "MSIE [1-6]\.(?!.*SV1)"; 1295 | gzip_http_version 1.1; 1296 | gzip_types text/plain text/css application/javascript application/x-javascript application/json application/xml; 1297 | 1298 | server { 1299 | listen 80; 1300 | server_name localhost 127.0.0.1 182.61.44.40; 1301 | 1302 | location /tkey-test { 1303 | return 601; 1304 | } 1305 | 1306 | location ^~ /upload { 1307 | root /home/root/sculptor-boot-backend-upload-dir; 1308 | autoindex on; 1309 | autoindex_exact_size off; 1310 | autoindex_localtime on; 1311 | } 1312 | 1313 | # 需要创建目录 /data/html/tkey-sso-client-management-frontend,里面存放 index.html 等静态文件 1314 | location ^~ /tkey-sso-client-management-frontend { 1315 | root /data/html; 1316 | index index.html; 1317 | try_files $uri /tkey-sso-client-management-frontend/index.html; 1318 | } 1319 | 1320 | location ^~ /sso-client-management/ { 1321 | proxy_pass http://172.16.16.4:9095; 1322 | proxy_redirect off; 1323 | proxy_set_header Host $host; 1324 | proxy_set_header X-Real-IP $remote_addr; 1325 | proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; 1326 | proxy_set_header X-Forwarded-Proto $scheme; 1327 | } 1328 | 1329 | location ^~ /sso/ { 1330 | proxy_pass http://172.16.16.4:9091; 1331 | proxy_redirect off; 1332 | proxy_set_header Host $host; 1333 | proxy_set_header X-Real-IP $remote_addr; 1334 | proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; 1335 | proxy_set_header X-Forwarded-Proto $scheme; 1336 | } 1337 | 1338 | 1339 | location ^~ /report { 1340 | root /data/html; 1341 | index index.html index.htm; 1342 | } 1343 | 1344 | location / { 1345 | root /usr/share/nginx/html; 1346 | index index.html index.htm; 1347 | } 1348 | } 1349 | } 1350 | 1351 | ``` 1352 | 1353 | ## hosts 配置 1354 | 1355 | 1356 | ``` 1357 | 172.16.16.4 sso.cdk8s.com 1358 | 172.16.16.4 test1.cdk8s.com 1359 | 172.16.16.4 test2.cdk8s.com 1360 | 172.16.16.4 redis.cdk8s.com 1361 | 172.16.16.4 mysql.cdk8s.com 1362 | 172.16.16.4 management.cdk8s.com 1363 | 172.16.16.4 tkey-sso-client-management 1364 | 172.16.16.4 tkey-sso 1365 | ``` --------------------------------------------------------------------------------