用中国漢語將以下句子重新表達一次(只需要一種選項):使用向量瓦片和 Azure AD 認證(使用 Node.js 創建伺服器)
首先
当向用户提供自己的矢量瓦片数据时,您会为数据添加何种认证?
我想在这里谈一谈我给矢量瓦片添加Azure AD身份验证的经验。虽然这项工作是一段时间之前完成的,但我想记录下我记得的内容以供分享。我觉得记录的重点不在于细节,而在于记录方针和有参考价值的代码位置。如果您有任何反馈、改进建议或指导意见,敬请告知!
顺便提一下,由于这项工作是在开发环境中完成的,所以还没有应用到真正的互联网上的公开服务器上。
为什么需要验证?
如果要公开自己创建的矢量瓦片,我认为不需要进行认证。然而,如果其中包含不想向大众公开的数据或者希望通过收费提供服务,就需要对访问者进行认证。在我处理的数据中,同事在使用数据时也考虑到了用户认证的必要性,所以我尝试了矢量瓦片的认证。
既有服务中的矢量瓦片访问限制等
在进行工作之前,我稍微查看了一下现有服务的访问限制情况。可能会有一些错误。
-
- ArcGSI Online
ArcGISサーバーでホストしているタイルのうち、一般に公開していないものを見てみました。ArcGISオンラインへのログイン後、ベクトルタイル地図を見ている様子を観察すると、ベクトルタイルのURLリクエストにクエリをつけて(?token=…)、アクセスを管理している様子。
MapBox
AccessTokenとURLによる制約ということでしょうか。TokenはJSON Web Tokensを使っているようです。
https://docs.mapbox.com/help/getting-started/access-tokens/
https://docs.mapbox.com/help/troubleshooting/how-to-use-mapbox-securely/
国土地理院のベクトルタイル
pbfタイルで提供されていますが、パスワードや認証などは必要なさそうです。
英国Ordnance Surveyのベクトルタイル
アカウントがないのでわからないのですが、OS Data Hubの文書をみると OAuth 2を使っていそうです。
https://osdatahub.os.uk/docs/vts/overview
我工作的條件
虽然每个矢量瓦片服务器的情况都可能不同,但我是通过nodejs/express服务器使用https协议来传送矢量瓦片。本次工作的主要要求是以下两点。
-
- nodejsでのサーバー構築が必要。これは、ベクトルデータのサイズが大きいためデータをmbtilesで格納しており、pbfタイルのリクエストに対して、nodejs/expressサーバーのルーティングと @mapbox/mbtiles というnpmモジュールで対応していたためです。unvt/onyxの仕組みを使います。
- 認証はAzure AD認証をつかう。
环境
-
- サーバーの環境:
RHEL 8.4
nodejs: ver12.21.0 (1年くらい前の作業で、mapbox/mbtilsの当時のバージョンが新しいnodejsで動かなかったため)
SSH/TLS: httpsのための認証は内部用のものをもらった
Azure AD Portalでの登録:ここは同僚が作業してくれて、テナントIDやシークレットをくれました。
过程
0. 第0步,在单页面应用程序教程中熟悉一下(可选)
由于我在这个领域没有经验,所以我首先尝试适应了Azure AD身份验证和使用msal包的机制。(注意:我使用的是MSAL(Microsoft Authentication Library),而不是ADAL(Azure Directory Authentication Library))
微软教程在这里:
https://docs.microsoft.com/zh-cn/azure/active-directory/develop/tutorial-v2-javascript-spa
https://github.com/Azure-Samples/ms-identity-node
我使用同事提供的客户ID、权限和客户密钥等信息,在内部环境中进行了实验。我对实验结果的理解大致如下。
(从这一步开始下面的内容大部分都是我个人的笔记,如果不需要的话请跳过阅读。)
-
- msalのconfig変数(auth(クライアントID、オーソリティ、クライアントシークレット)とsystem(ログのオプション))を作る。
https://github.com/Azure-Samples/ms-identity-node/blob/main/index.js#L13-L28
msal applicationオブジェクトの変数をつくる。前で作ったコンフィグ情報で、msalConfidentialClientApplication(作った変数) として、msal applicationオブジェクトの変数に代入する。
https://github.com/Azure-Samples/ms-identity-node/blob/main/index.js#L31
ルーティング。ルート(/)にきたリクエストを、{msal application オブジェクト}.getAuthCodeUrl(リダイレクトURLやスコープを持った変数)で得られるアドレスにリダイレクトする。(そのあとログインするとリダイレクトされると思われる。)
https://github.com/Azure-Samples/ms-identity-node/blob/main/index.js#L36-L46
redirectのアドレスに帰ってきたら(帰ってくるときのrequestにcodeがついている)、codeでtokenRequestの変数をつくって、(msal application オブジェクト).acquireTokenByCode(tokenRequest)として、トークンをとる。コードを使ってトークンをゲットしたということだろう。(サンプルコードではこのトークンをサーバー側で表示するようになっています。)
https://github.com/Azure-Samples/ms-identity-node/blob/main/index.js#L48-L62
简单来说,就是通过AuthCodeURL获取AuthCode并使用该代码登录,然后在重定向后使用AuthCode获取Token,是这样的吗?
当查询有关OAuth的说明时,我们得知idToken和AccessToken是不同的,但首先会返回代码和idToken,然后我们可以使用它们来获取accessToken和idToken。
第一步: 构建Nodejs的express应用程序
接着来说,当我搜索nodejs express和Azure AD 身份验证示例时,我找到了一个名为“使用 Microsoft Graph 构建 Node.js Express 应用程序”的教程。该教程演示了如何从 Microsoft Graph API 获取日历信息,并涉及到了 Azure AD 身份验证步骤,看起来很实用。我将通过 Graph API 仅获取用户名等基本信息。
按照教程的步骤,我们将建立一个Node.js Express服务器。在教程的GitHub存储库中的demo文件夹中,有教程的代码,我们可以从这里下载并开始操作。https://github.com/microsoftgraph/msgraph-training-nodeexpressapp/tree/main/demo/graph-tutorial
如果详细描述这部分内容,将涉及到有关MSAL而不是矢量瓦片的讨论,所以不需要深入探讨,但需要注意以下几点。
从这个步骤开始,下面半数以上的部分都像是我自己的笔记,如果不需要的话,请跳过阅读。
-
- msal application objectは、app.locals.msalClientに格納されている。
-
- サーバーではメモリストレージを使ってログインしたユーザーを保存している。デモなので、メモリ(app.locals)を使っている点には注意。本番環境では要検討。(これはPM2でクラスターモードで2以上にしても問題になる原因です。)
Step1と違って、認証関係のコードはroutes/auth.jsに書かれている。authのcallbackプロセスでは以下のようなことをやっていました。
トークンリクエストで帰ってきたresponseのresponse.account.homeAccountIdをreq.session.userIdとセッションに記録している。さらにgraphからかえってきたユーザーの詳細情報を情報を、ユーザーストレージに入れている(req.app.locals.users[req.session.userId])。そしてルートに(/)リダイレクトする。
そんな感じで、ユーザー情報をセッションに保存しているようでしたが、これを使って、どのようにアクセス管理をしているかは、calendar.jsをみてみました。ここにリクエストがくると、以下のような感じでした。
req.session.userIdがないと、ログインしなさいということで、ルートにリダイレクトされる。
req.session.userIdがあれば、変数userとしてreq.app.locals.users[req.session.userId]がとってこられる。そして、このuserやmsal application objectをつかってとってきたgraphの情報が返される。
尽管这与矢量瓦片无关,但看起来是以这种方式对用户进行身份验证。
此Microsoft教程在2021年4月更新至1.8版本,而基于先前版本参考而创建的开发环境矢量瓦片服务器是 https://github.com/un-vector-tile-toolkit/coesite。我们将其命名为coesite,表示即使在比unvt/onyx受限的环境下,也希望它能够努力。(虽然我不知道onyx的来源,但如果它表示SiO2的成分物质,那么在超高压下会变成coesite石。)
步骤2:将路线添加至矢量瓦片。
由于用户认证和登录服务器的形式已经建立起来,接下来要做的是设置到矢量瓦片的路由。
为了传送矢量瓦片,我们在路由(route)中创建了一个路由(route)。就像这样的图像(https://github.com/ubukawa/server-test-01/blob/main/routes/VT.js),我们在步骤2中添加了用户确认。虽然有点不完整,但我们在这里尝试了一下(https://github.com/un-vector-tile-toolkit/coesite/blob/main/routes/vtile-m.js)。然后,在app.js中加入var vtileMRouter = require(‘./routes/(created file name)’)和app.use(‘/(path)’,vtileMRouter)。
不要忘记在app.js中进行CORS设置。
第三步。转为HTTPS(并使用PM2运行)。
由于Microsoft的教程是通过本地主机的http进行托管的,所以我们需要在app.js中添加spdy模块来进行https化(请提前定义密钥路径和端口)。这样服务器就可以通过https进行操作了。为了在后台运行,我们需要使用PM2进行执行。
//for https
spdy.createServer({
key: fs.readFileSync(privkeyPath),
cert: fs.readFileSync(fullchainPath)
}, app).listen(port)
其他:PM2的有趣小事。
在config文件夹中创建一个名为default-0.hjson的空文件。
为了能够读取config/default.hjson文件中的对象,在config包中进行配置。但是当执行PM2时,出现了错误。我提前创建了一个名为空的default-0.hjson文件,然后它就能正常运行了。
集群模式
在执行pm2时,可以使用-i选项指定群集的数量。但是,由于用户信息存储在会话内存中,所以在另一个群集中无法访问内存,因此需要重新登录。在修复内存问题之前,我们将使用群集模式1。
问题
到目前为止,我已经成功创建了一个能够登录并查看矢量切片地图的服务器。然而,仍然存在一些问题,我正在进行解决。
跨出源的认证
目前,我们正在进行与跨域问题的调整。
如果没有认证,只需使用 app.use(cors()) 就可以从其他源使用矢量切片,但如果涉及跨域认证,可能需要进一步调整。
举个例子,请求方似乎需要在CORS中将凭据设置为include,而响应方似乎需要将Access-Control-Allow-Credentials设置为true(就像这个页面上的说明https://web.dev/cross-origin-resource-sharing/)。
因此,在服务器端我们不使用app.use(cors()),而是使用其他方式。
const corsOption = {
origin: '*',
credentials: true
}
app.use(cors(corsOption))
可能需要考虑年龄。
此外,地图库方面,我认为在transformRequest中也需要将credentials设置为’include’,无论是在Mapbox的请求参数还是在MapLibre的请求参数中,都需要以相同的方式进行操作。
但是,由于这些事情仍然没有取得良好的效果,所以我正在进行各种实验。
会话存储
由于当前将用户信息存储在会话内存中,我们计划为正式环境准备会话存储。
总结
我记录了我在添加身份验证到矢量切片服务器上的经历。
这个话题主要是关于如何在网页服务器中添加认证,所以与矢量瓦片没有太大关系。可能专业人士可以轻松完成,但作为初学者的尝试记录,希望能够得到温暖的眼光。
我在nodejs中完成了,但是如果传送的数据量不大的话,可以考虑使用经常使用的web服务器,比如apache或者nginx,这样参考资料也会更多,更容易操作。
感谢辞
我为与我一起合作的同事深表感激。(虽然你可能看不懂日语…)
可以参考的资料等
本文中附有链接。