部署 IAM 程序
我们通过源码检出和 IDEA 来完整 IAM 程序的部署,目标是 Linux 的服务器。
配置文件
Git checkout 源码后默认是没有任何有效的配置文件,——除了一个application.yaml
演示文件,
位于profiles
目录下。我们在 profiles
目录中新建dev
、prod
、test
子目录,分别对应着开发、生产、测试环境。
如不满足还可以自定义更多的子目录。
把application.yaml
复制并改名application.yml
到具体的dev
、prod
、test
目录中,然后修改你具体的配置。
一键部署
如果你采用原始的 JAR 发布机制(而非 Jenkins/Docker/K8S),那么可以使用我们准备的“一键部署”。
技巧:你可以使用源码中/src/startup.sh
的 SHELL 脚本快速启动程序
划分域(Domain)来进行部署
首先 IAM 是一套中间件程序,这套程序也符合常规前后端分离的 Web 程序,即:
- 前端(Web)UI,纯 HTML/CSS/JS 程序,其实就是 IAM 的管理程序界面
- 后端 API 程序,SpringBoot 服务端程序
然后跟你的应用程序进行对接整合。具体整合通过 SDK 或者纯接口都可以。 但这里有一个特殊的程序需要与 IAM 在用一个域(Domain)下面部署,就是用户的登录页面。为什么登录页面要单独“拎”出来还要和 IAM 一起部署呢? 这是因为安装 OAuth/OIDC 规范,登录操作不能跨域的缘故,一句话就是为了安全起见的。同时,登录页面在 SSO 语境中通常也被认为是统一登录,即不单单为某个程序所使用,而是多个程序使用这一个登录入口。
由此,关于是否跨域,我们可以稍作整理一下:
- IAM 程序本身,前端后端固然在一个域下
- 业务系统的用户登录页面,与 IAM 在一个域下
- 业务系统,访问或者调用 IAM,不跟 IAM 一个域,即跨域调用(更多的是后端调用,于是是否跨域无所谓了)
理解好之后便不难写出 Nginx 配置了。
为 IAM 配置 Nginx
假设域名 iam.service.com 是为 IAM 所准备的。把登陆页面、IAM 管理 UI、IAM API 放置同一个域下面。
server {
listen 80;
server_name iam.service.com;
location / {
ssi on;
root html;
index index.html index.htm;
}
location /login/ { # 登录页面
alias D:/sp42/dev/nginx-1.29.0/login/;
autoindex on; # 可选,显示目录列表
}
location /iam/ { # IAM 管理页面
ssi on;
alias D:/sp42/code/ajaxjs/aj-iam/aj-iam-admin/; # 注意路径斜杠
index index.html index.htm; # 默认首页
try_files $uri $uri/ /index.html; # 支持单页应用(SPA)路由
}
location /iam_api/ { # IAM 后端 API
proxy_pass http://localhost:8082/; # 代理到后端 API
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}
当然 IAM 管理页面的登录也走统一一套的那个登录页面。
前端开发环境的跨域
如果是简单的 HTML 开发,那么很简单,通过 Nginx 轻松配置在一个域下。但是如果是复杂的前端开发,比如基于 Node 的 React/Vue 开发, 一般都是开启 Node 代理来避免跨域问题的。
前端工程vue.config.js
配置代理例子如下。
devServer: {
proxy: {
'/login': {
target: 'http://local.ajaxjs.com', // 登录页面的实际地址
changeOrigin: true, // 如果目标是一个域名而不是IP,请设置为true
pathRewrite: {
'^/login': '' // 重写路径,比如将 /api/v1/test -> /v1/test
}
},
'/api': {
target: 'http://local.ajaxjs.com/dataservice_api', // 后端服务的实际地址
changeOrigin: true,
pathRewrite: {
'^/api': ''
}
},
'/iam_api': {
target: 'http://local.ajaxjs.com/iam_api', // IAM 后端服务的实际地址
changeOrigin: true,
pathRewrite: {
'^/iam_api': ''
}
}
}
},
宏观上讲,这等于在 Nginx 代理上又套了一层 NodeJS 的代理。——没关系,请谨记,我们最终的 URL 是以 Node 所运行的 URL 为准, 也就是,我们把所有涉及 IAM 的 URL 都改为 NodeJS 的即可。
至于最终打包后的前端程序,无须 NodeJS 代理,那么就是普通的 HTML 程序,按照前面的方法部署一起即可。
多租户支持
IAM 支持多租户模式,即一个租户一个域,不论多少个租户呈现,但背后只有一套程序在运行——这有点像套马甲的样子。
租户
IAM 通过租户tenant
来区分用户体系。一个租户下的用户 id(login_id
)不能重复。涉及的租户的数据库表、API 接口均有保存tenant_id
的字段或入参。
怎么入参比较优雅呢(相对于调接口都要传参tenant_id
)?我们采用域名区分的方法来划分租户。
- 首先分配一个域名给某个租户,例如 bar.foo.com 但不是根据这个域名关联那个租户
- 在 Nginx 代理中加入自定义头
auth-tenant-id
,表示某个组件,这样就是能在每个接口中获取租户了