mongodb 元数据
In June 2020, MongoDB finally released their first beta version of MongoDB Realm — a real time database technology that combined the backend of MongoDB with the front-end mobile technology of Realm.io. Over the last five years, Realm has proven to be an invaluable object database to store cached web data for virtually all cloud connected apps. Whether a developer was using their own backend server and REST API, or a backend as a service product like Firebase, Realm was the only cross platform solution for iOS and Android development for storing local data. In late 2017, Realm introduced a cloud synching technology of their own called Realm Cloud, which essentially provided client to client synching of local databases over a Realm Sync server. The primary advantage of the Realm Cloud solution over other backend end as a services, such as Google Firebase, was that application could still access the synchronized data as if were interfacing to a local database. Server-side synching was done in the background auto-magically, with very little effort on the part of the developer. Firebase did not preclude the use of Realm, in fact it was still necessary to use it for local caching, rather Realm Cloud did away with all the translation code between the local Realm and the server Firebase components within the application. In a sense, Realm Cloud made Firebase redundant.
2020年6月,MongoDB终于发布了他们的第一个Beta版MongoDB Realm —一种实时数据库技术,将MongoDB的后端与Realm.io的前端移动技术结合在一起。 在过去的五年中,事实证明Realm是一个非常有价值的对象数据库,用于存储几乎所有与云连接的应用程序的缓存Web数据。 无论开发人员是使用自己的后端服务器和REST API,还是像Firebase这样的后端即服务产品,Realm都是唯一用于存储本地数据的iOS和Android开发的跨平台解决方案。 2017年底,Realm推出了自己的云同步技术Realm Cloud,该技术本质上是通过Realm Sync服务器为客户端到客户端的本地数据库客户端同步提供技术。 与其他后端服务(例如Google Firebase)相比,Realm Cloud解决方案的主要优势在于,应用程序仍然可以访问同步数据,就像与本地数据库接口一样。 服务器端同步是在后台自动神奇地完成的,开发人员只需付出很少的努力即可。 Firebase并不排除使用Realm,实际上仍然需要将其用于本地缓存,而Realm Cloud取消了本地Realm与应用程序中服务器Firebase组件之间的所有转换代码。 从某种意义上说,Realm Cloud使Firebase成为冗余。
Although I was an early adopter and a big fan of Realm Cloud, I will confess that the server-side toolset for Realm Cloud was somewhat lacking when contrasted to Firebase. The bigger limitation with Realm Cloud was that the synching solution was primarily limited to mobile application development — making it very challenging to develop a web app that synced to the same Realm Cloud server database. Up until the release of MongoDB Realm in June, this was perhaps the primary reason to still choose Google Firebase over Realm Cloud. In April 2019, MongoDB acquired the Realm company with the express goal of blending the best features of MongoDB Atlas and Realm Cloud into a unified product. The release of MongoDB Realm beta this June is the result of that one-year development effort. The resulting product is impressive, and this is a major feat of software engineering, but there is a lot to digest. With the new product it is now possible to develop synching mobile and web apps within a unified database solution. Essentially, the entire Realm Cloud backend has been replaced with MongoDB Atlas. Today, I would definitely choose MongoDB Realm over Google Firebase as my preferred back end as a service.
尽管我是Realm Cloud的早期采用者和忠实拥护者,但我将承认与Firebase相比,Realm Cloud的服务器端工具集有些缺乏。 Realm Cloud的最大局限性在于,同步解决方案主要限于移动应用程序开发,这使得开发与同一个Realm Cloud服务器数据库同步的Web应用程序非常困难。 直到6月MongoDB Realm发行,这也许是仍然选择Google Firebase而非Realm Cloud的主要原因。 在2019年4月,MongoDB收购了Realm公司,其明确目标是将MongoDB Atlas和Realm Cloud的最佳功能融合到一个统一的产品中。 MongoDB Realm beta于今年6月发布是经过一年的开发努力的结果。 最终的产品令人印象深刻,这是软件工程的一项重大成就,但是还有很多需要消化的地方。 使用新产品,现在可以在统一数据库解决方案中开发移动和Web应用程序的同步。 本质上,整个Realm Cloud后端已被MongoDB Atlas取代。 今天,我肯定会选择MongoDB Realm而不是Google Firebase作为我首选的后端即服务。
I have written a series of articles about the new MongoDB Realm product. In this article, I will attempt to explain the difference between meta-data for a custom authentication provider (such as JWT) and custom user data in a Realm application. More specifically, I will show how to use custom user data to pass authentication provider metadata on to the client code. This is a fairly arcane subject, but understanding it is essential for successful Realm application development. In a subsequent article, I will explain how to configure custom user data for defining sync rules to control access to specific partitions or individual Realms within an application.
我写了一系列有关新MongoDB Realm产品的文章。 在本文中,我将尝试解释自定义身份验证提供程序(例如JWT)的元数据和Realm应用程序中的自定义用户数据之间的区别。 更具体地说,我将展示如何使用自定义用户数据将身份验证提供程序元数据传递给客户端代码。 这是一个相当神秘的主题,但是了解它对于成功开发Realm应用程序至关重要。 在随后的文章中,我将解释如何配置自定义用户数据以定义同步规则,以控制对应用程序中特定分区或各个领域的访问。
The new MongoDB Realm supports a number of authentication providers including email/password and a number of third-party providers such as Facebook, Google, or Custom JWT providers. The purpose of an authentication provider is to authenticate and verify the identity on behalf of the MongoDB application. As part of the authentication process and authentication provider can also collect and store data for each user it authenticates. Meta data is the mechanism through which an authentication provider passes user specific data onto a MongoDB application. In a simple scenario, this meta data might include the user’s first name, last name, and email address, but it could also include additional data such as phone number, avatar, birthday, etc… It is up to the developer to define the structure of the meta data that is passed in by a custom authentication provider.
新的MongoDB领域支持许多身份验证提供程序,包括电子邮件/密码,以及许多第三方提供程序,例如Facebook,Google或Custom JWT提供程序。 身份验证提供程序的目的是代表MongoDB应用程序对身份进行身份验证和验证。 作为身份验证过程的一部分,身份验证提供程序还可以为它进行身份验证的每个用户收集和存储数据。 元数据是身份验证提供程序将用户特定数据传递到MongoDB应用程序的机制。 在一个简单的场景中,此元数据可能包含用户的名字,姓氏和电子邮件地址,但也可能包含其他数据,例如电话号码,头像,生日等。由开发人员决定结构自定义身份验证提供程序传递的元数据的数量。
As a disclosure, our company Cosync has developed a custom JWT authentication provider for MongoDB Realm. For more information about this system, please consult our web site at https://cosync.io. Our authentication system is available both as a cloud service and as a self-hosted version. The code is open source and is distributed under the MongoDB Server Side Public License. The paid license to the source code, allows a developer to keep their own modifications to the authentication system without having to open source them to the public domain.
作为披露,我们公司Cosync已为MongoDB Realm开发了自定义JWT身份验证提供程序。 有关此系统的更多信息,请访问我们的网站https://cosync.io 。 我们的身份验证系统既可以作为云服务,也可以作为自托管版本。 该代码是开源的,并根据MongoDB服务器端公共许可证进行分发。 源代码的付费许可证允许开发人员保留自己对身份验证系统的修改,而不必将其开放给公共领域。
The Cosync JWT service, available through the portal https://cloud.cosync.net allows the developer to configure JWT authentication for each application he/she is developing. More importantly, it provides an interface to define the meta fields that are packaged with the JWT authentication token used to sign into a MongoDB Realm application. For example, if developer wanted to create meta-data fields to contain the user’s first name, last name, and email, the configuration screen in CosyncJWT would look as follows:
通过门户https://cloud.cosync.net可用的Cosync JWT服务允许开发人员为他/她正在开发的每个应用程序配置JWT身份验证。 更重要的是,它提供了一个接口,用于定义与用于登录MongoDB Realm应用程序的JWT身份验证令牌打包在一起的元字段。 例如,如果开发人员想要创建元数据字段以包含用户的名字,姓氏和电子邮件,则CosyncJWT中的配置屏幕如下所示:
In addition, the CosyncJWT service provides the developer with the ability to automatically configure the JWT provider for the MongoDB application. The developer simply needs to provide the Realm Application Id, the Project Id, and the Project API keys in Project Access Manager that host the MongoDB Realm application. This functionality is available through the MongoDB Realm tab in the CosyncJWT application portal.
此外,CosyncJWT服务使开发人员能够为MongoDB应用程序自动配置JWT提供程序。 开发人员只需在托管MongoDB Realm应用程序的Project Access Manager中提供Realm应用程序ID,Project ID和Project API密钥。 可通过CosyncJWT应用程序门户中的MongoDB领域选项卡使用此功能。
The CosyncJWT service provide a REST API to the client side application. One of the functions it provides is login. If passed the right credentials, the login function returns a JWT token that looks as follows:
CosyncJWT服务向客户端应用程序提供REST API。 它提供的功能之一是login 。 如果传递了正确的凭据,则登录功能将返回一个JWT令牌,其外观如下:
eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJhdWQiOiJ0ZXN0YXBwbGljYXRpb24teHpsd2oiLCJzdWIiOiJyY2tydWVnZXJAZ21haWwuY29tIiwiZXhwIjoxNjAwODkxODU0LCJlbWFpbCI6InJja3J1ZWdlckBnbWFpbC5jb20iLCJ1c2VyX2RhdGEiOnsibmFtZSI6eyJmaXJzdCI6IlJpY2hhcmQiLCJsYXN0IjoiS3J1ZWdlciJ9fSwiaWF0IjoxNjAwODA1NDU0fQ.f14RvGdYp8hX3Fqphpie1sOww3EGHPjRqnH-qwjCiI2Ta3ZcDrJb1hdiIcUwVxX97YrL-fkPn_Bygw4HHXqKbr7AhvgRt_vbl1Hdusb6bLTo5YqiOWD07wHmVo2t7wQQySJlQqs84E8_l1Kd5ODJKyG_9e23EJLPUsmzflnD0cDA6u6vpH97J0WeeKOXgJfgsxOKaPjVgQLhpaenFeh1BXxTGpg-3NfVWC5kBt2xzPSzmVTX23RJ92xmJvHJ__G0_hVSJXVeFoJDCzb_z0csye36fL200ah6-ppkoRCxNH-788t1Uoh0CAvjwjlBzU_8xBIXwfO8bOuFDopw-Recaw
This is hardly user friendly, but a decrypted version of this token can been had through the website https://jwt.io. The JWT payload is shown as follows:
这几乎不是用户友好的,但是可以通过https://jwt.io网站获得此令牌的解密版本。 JWT有效负载如下所示:
{
"aud": "testapplication-xzlwj",
"sub": "rckrueger@gmail.com",
"exp": 1600891854,
"email": "rckrueger@gmail.com",
"user_data": {
"name": {
"first": "Richard",
"last": "Krueger"
}
},
"iat": 1600805454
}
Ok, so the user’s meta-data is passed as part of the JWT authentication token, now what? How does the client side application actually access that data? The answer to that question has both good news and bad news. The good news is that you can define an authentication trigger in MongoDB Realm that can access the meta-data, the bad news is that there is no client side Realm API to access it. Of course, you could just crack open the JWT token on the client side, but that would be cheating. The authentication trigger runs as a super user, so naturally it has access to the meta-data. This is where Realm Custom User Data fits in to save the day.
好的,因此用户的元数据作为JWT身份验证令牌的一部分传递,现在呢? 客户端应用程序实际上如何访问该数据? 这个问题的答案既有好消息,也有坏消息。 好消息是您可以在MongoDB Realm中定义一个可以访问元数据的身份验证触发器,坏消息是没有客户端Realm API可以访问元数据。 当然,您可以只是在客户端打开JWT令牌,但这会作弊。 身份验证触发器以超级用户身份运行,因此自然可以访问元数据。 这是Realm自定义用户数据适合保存一天的地方。
The Custom User Data is a special collection in a MongoDB Atlas database that can be configured for a MongoDB Realm application to store pertinent information about the user. It is only accessible to the logged in user, meaning that no other user can access this data. In my opinion, the best practice is to make this data collection readable by the user, but only writable by the system user in system functions and/or triggers. Since the Custom User Data can contain lists of partition key values that control a user’s access to various partitions (or Realms), users should not be able to spoof the system by overwriting these lists. If the Custom User Data is writable by the user, this does present a security risk for the application. Lastly, user data that is generated by the user within the application should probably be saved to a separate collection with a partition key value set to the user id of the user, what used to be called a private user Realm in the old Realm Cloud system.
自定义用户数据是MongoDB Atlas数据库中的一个特殊集合,可以为MongoDB Realm应用程序配置它来存储有关用户的相关信息。 只有登录用户才能访问它,这意味着没有其他用户可以访问此数据。 在我看来,最佳实践是使用户可以读取此数据集合,但只能由系统用户在系统功能和/或触发器中写入。 由于“自定义用户数据”可以包含分区键值列表,这些值控制用户对各种分区(或领域)的访问,因此用户不应通过覆盖这些列表来欺骗系统。 如果用户可以写入“自定义用户数据”,则确实会对应用程序造成安全风险。 最后,应将用户在应用程序内生成的用户数据保存到一个单独的集合中,并将分区键值设置为该用户的用户ID,在旧的Realm Cloud系统中该用户过去称为私有用户。
The meta-data that is passed in as part JWT authentication process is precisely the type of information that should be set in the Custom User Data collection. It is data about the user that is set from outside of the application.
作为JWT身份验证过程的一部分传递的元数据正是应在“自定义用户数据”集合中设置的信息类型。 从应用程序外部设置的是有关用户的数据。
Enabling Custom User Data for a MongoDB Application is very easy. The first step should be to open the Atlas Cluster associated your MongoDB Realm application in the Compass desktop app. The first step should be to create a new data base and a collection for the Custom User Data. In our example, we create a database called CustomUserDB and a collection called CustomUserData.
为MongoDB应用程序启用自定义用户数据非常容易。 第一步应该是在Compass桌面应用程序中打开与您的MongoDB Realm应用程序关联的Atlas集群。 第一步应该是为自定义用户数据创建一个新的数据库和一个集合。 在我们的示例中,我们创建一个名为CustomUserDB的数据库和一个名为CustomUserData的集合。
The next step is to go the Users tab in the MongoDB Realm application portal and select Custom User Data. First, enable Custom User Data. Second, select the Cluster Name, this is usually mongodb-atlas. Third, select a Database Name, this is CustomUserDB. Fourth, select a Collection Name, this is CustomUserData. Lastly, enter a User ID Field, this is the field name in the collection that holds the user id of the logged in user, this is userId.
下一步是转到MongoDB Realm应用程序门户中的“用户”选项卡,然后选择“自定义用户数据” 。 首先,启用自定义用户数据。 其次,选择集群名称,通常是mongodb-atlas 。 第三,选择一个数据库名称,这是CustomUserDB 。 第四,选择一个集合名称,这是CustomUserData 。 最后,输入一个用户ID字段,这是集合中包含已登录用户的用户ID的字段名,即userId 。
Note: It is very important to create the database and the collection for the Custom User Data first in the Compass app before trying to enable Custom User Data. You will not be able to do it in the reverse order. Secondly, do not try to create the database and its associated collection under the Rules section. Unless you define a schema along with a partition key, it will generate a sync error.
注意:在尝试启用“自定义用户数据”之前,首先在Compass应用程序中创建数据库和“自定义用户数据”集合非常重要。 您将不能以相反的顺序进行操作。 其次,不要尝试在“规则”部分下创建数据库及其关联的集合。 除非您定义架构和分区键,否则它将生成同步错误。
Lastly the final step is to write a system level authentication trigger that copies the JWT metadata into the Custom User Data at the time of login. To accomplish this, you must create an authentication trigger for that purpose.
最后,最后一步是编写一个系统级身份验证触发器,该触发器将在登录时将JWT元数据复制到“自定义用户数据”中。 为此,您必须为此创建一个身份验证触发器。
First, go the Triggers tab in the left hand side of the MongoDB Application portal and click Add a Trigger. The Trigger Type should be set to Authentication. The name should be set to loginTrigger. The Action Type should be set to Login. The Provider(s) should be set to Custom Authentication. The Function should be + New Function. The Function Name should be loginTrigger. The function code should be set to the following:
首先,转到MongoDB应用程序门户左侧的触发器选项卡,然后单击添加触发器。 触发类型应设置为Authentication 。 名称应设置为loginTrigger 。 操作类型应设置为Login 。 提供者应设置为Custom Authentication 。 该功能应为+新功能。 函数名称应为loginTrigger 。 功能代码应设置为以下内容:
exports = function(authEvent) {
const user = authEvent.user
console.log("authEvent.user ", JSON.stringify(user));
const mongodb = context.services.get("mongodb-atlas");
const users = mongodb.db("CustomUserDB").collection("CustomUserData");
var newUser = { userId: user.id,
email: user.data.email,
firstName: user.data.firstName,
lastName: user.data.lastName }; users.updateOne({userId: user.id}, newUser, {upsert: true});};
The authEvent parameter that is passed to the loginTrigger contains a user object that contains a data object with all the meta data that is passed in through the JWT authentication service. This data however is passed in as a set of (field name, field value) tuples. This is where the Field Name in the meta data specification comes in. Even though the meta data is specified as a hierarchical JSON object, that data that is passed through uses the field names instead. If we console log the user object from the loginTrigger function, we get the following output.
传递给loginTrigger的authEvent参数包含一个用户对象,该用户对象包含一个数据对象,该数据对象包含所有通过JWT身份验证服务传递的元数据。 但是,此数据作为一组(字段名称,字段值)元组传递。 这就是元数据规范中字段名称的来源。即使将元数据指定为分层JSON对象,通过的数据也将使用字段名称。 如果我们从loginTrigger函数控制台记录用户对象,则会得到以下输出。
[
"authEvent.user {\"custom_data\":{},\"data\":{\"email\":\"rckrueger@gmail.com\",\"firstName\":\"Richard\",\"lastName\":\"Krueger\"},\"id\":\"5f6a5a7951ab37a8ffc1ae10\",\"identities\":[{\"id\":\"rckrueger@gmail.com\",\"provider_type\":\"custom-token\"}],\"type\":\"normal\"}"
]
We then modify the CustomUserData object for the logged in user using the updateOne() MongoDB function call. After we have logged in, we can see that the Custom User Data collection has been updated in the Compass App.
然后,我们使用updateOne() MongoDB函数调用为登录用户修改CustomUserData对象。 登录后,我们可以看到“指南针”应用程序中的“自定义用户数据”集合已更新。
From within your iOS Swift MongoDB Application,it is very easy to retrieve the Custom User Data. Given a valid JWT token, you would login as follows and extract the Custom User Data.
从您的iOS Swift MongoDB应用程序中,很容易检索自定义用户数据。 给定有效的JWT令牌,您将按以下方式登录并提取定制用户数据。
func login(_ jwt: String, onCompletion completion: @escaping (Error?) -> Void) { app.login(credentials: Credentials(jwt: jwt)) { (user, error) in guard error == nil else {
completion(RESTError.internalServerError)
return} if let user = user {
user.refreshCustomData() { (customData, error) in
guard error == nil else {
print("Failed to refresh custom data")
return} guard let customData = customData else { // This may happen if no custom data was set for user id.
// It could also be caused by not having custom data enabled
// and configured correctly! print("Custom data not set")
return} print("User custom data: \(String(describing: customData))")
}
} completion(nil)
}
}
The refreshCustomData() function call in necessary because without it, the client code will not capture the latest write by the loginTrigger to the Custom User Data collection.
必要时会调用refreshCustomData()函数,因为没有它,客户端代码将无法捕获loginTrigger对“自定义用户数据”集合的最新写入。
I hope that this article showed how easy it is to define Custom User Data within a MongoDB Realm application, and how to save the JWT meta data to it so that it can be accessed by the client code.
我希望这篇文章表明在MongoDB Realm应用程序中定义自定义用户数据有多么容易,以及如何将JWT元数据保存到其中,以便客户端代码可以访问它。
翻译自: https://medium.com/swlh/mongodb-realm-jwt-meta-data-and-custom-user-data-dc04d86bf542
mongodb 元数据