diff --git a/curriculum/challenges/chinese/05-apis-and-microservices/mongodb-and-mongoose/chain-search-query-helpers-to-narrow-search-results.chinese.md b/curriculum/challenges/chinese/05-apis-and-microservices/mongodb-and-mongoose/chain-search-query-helpers-to-narrow-search-results.chinese.md index 736b68ab565..e925a9a36f6 100644 --- a/curriculum/challenges/chinese/05-apis-and-microservices/mongodb-and-mongoose/chain-search-query-helpers-to-narrow-search-results.chinese.md +++ b/curriculum/challenges/chinese/05-apis-and-microservices/mongodb-and-mongoose/chain-search-query-helpers-to-narrow-search-results.chinese.md @@ -1,20 +1,17 @@ --- id: 587d7fb9367417b2b2512c12 title: Chain Search Query Helpers to Narrow Search Results +localeTitle: 链搜索查询帮助缩小搜索结果 challengeType: 2 -isHidden: false -forumTopicId: 301533 -localeTitle: 通过链搜索查询帮助器缩小搜索结果 --- ## Description -
-如果不给 Model.find() (或者别的搜索方法)传递回调函数,作为的最后一个参数, 则不执行查询。你可以将查询存储在变量中供以后使用,这类对象可以使用链接语法构建查询。 当你最终链接 .exec() 方法时,将执行实际的数据库操作。最后将回调传递给 exec() 方法。 有很多的查询助手, 这里我们使用最 '著名' 的一种。 +
0如果未将回调作为Model.find()(或其他搜索方法)的最后一个参数传递,则不执行查询。您可以将查询存储在变量中以供以后使用。这种对象使您可以使用链接语法构建查询。当您最终链接方法.exec()时,将执行实际的数据库搜索。将回调传递给最后一个方法。有很多查询助手,这里我们将使用最“着名”的助手。 0找到的人喜欢“burrito”。按名称对它们进行排序,将结果限制为两个文档,并隐藏它们的年龄。链.find(),. sort(),. limit(),。select(),然后是.exec()。将done(错误,数据)回调传递给exec()。
## Instructions -
-找到喜欢 "burrito" 的人,按照名字排序, 限制结果为两个 document, 并且隐藏他们的年龄。 使用链路 .find(), .sort(), .limit(), .select(), 然后 .exec()。将 done(err, data) 回调传给 exec() 方法。 +
+
## Tests @@ -22,7 +19,7 @@ localeTitle: 通过链搜索查询帮助器缩小搜索结果 ```yml tests: - - text: Chaining query helpers should succeed + - text: 链接查询助手应该成功 testString: 'getUserInput => $.ajax({url: getUserInput(''url'') + ''/_api/query-tools'', type: ''POST'', contentType:''application/json'', data: JSON.stringify([{name: ''Pablo'', age: 26, favoriteFoods: [''burrito'', ''hot-dog'']}, {name: ''Bob'', age: 23, favoriteFoods: [''pizza'', ''nachos'']}, {name: ''Ashley'', age: 32, favoriteFoods: [''steak'', ''burrito'']}, {name: ''Mario'', age: 51, favoriteFoods: [''burrito'', ''prosciutto'']} ]) }).then(data => { assert.isArray(data, ''the response should be an Array''); assert.equal(data.length, 2, ''the data array length is not what expected''); assert.notProperty(data[0], ''age'', ''The returned first item has too many properties''); assert.equal(data[0].name, ''Ashley'', ''The returned first item name is not what expected''); assert.notProperty(data[1], ''age'', ''The returned second item has too many properties''); assert.equal(data[1].name, ''Mario'', ''The returned second item name is not what expected'');}, xhr => { throw new Error(xhr.responseText); })' ``` @@ -38,11 +35,6 @@ tests:
```js -/** - Backend challenges don't need solutions, - because they would need to be tested against a full working project. - Please check our contributing guidelines to learn more. -*/ +// solution required ``` -
diff --git a/curriculum/challenges/chinese/05-apis-and-microservices/mongodb-and-mongoose/create-a-model.chinese.md b/curriculum/challenges/chinese/05-apis-and-microservices/mongodb-and-mongoose/create-a-model.chinese.md index 208b9d98104..bff0e979a5c 100644 --- a/curriculum/challenges/chinese/05-apis-and-microservices/mongodb-and-mongoose/create-a-model.chinese.md +++ b/curriculum/challenges/chinese/05-apis-and-microservices/mongodb-and-mongoose/create-a-model.chinese.md @@ -1,61 +1,29 @@ --- id: 587d7fb6367417b2b2512c07 title: Create a Model -challengeType: 2 -isHidden: false localeTitle: 创建一个模型 +challengeType: 2 --- ## Description -
-CRUD 之 - CREATE 创建 - -首先,我们需要一个 Schema,每一个 Schema 对应一个 MongoDB collection,并且在那个 collection 里面定义 documents 的模型。 -Schemas 是 Models 的构建块。它们可以嵌套来创建复杂的模型,但是这里,我们只学习简单的用法。 -Model 可以被实例化,实例化后的对象称为 documents。 - -注意: Glitch 是一个真实的服务,并且通过 handler 函数和 db 进行交互。 这些函数通过一些事件去触发(例如:有人从终端调用了你的 API),我们在这些练习中遵循同样的方法。 比如,我们在完成 nserting、searching、updating 或者 deleting 这样的异步操作后接着回调done()函数。它遵循 Node 的惯例,需要在 success 时回调done(null, data),在 error 时回调done(err)。 -Warning - 当与远程服务器交互时可能发生错误! - -```js -/* Example */ - -var someFunc = function(done) { - //... do something (risky) ... - if(error) return done(error); - done(null, result); -}; -``` -- Person Prototype - --------------------- -name : string [required] -age : number -favoriteFoods : array of strings (*) -你可以使用基础的 SchemaTypes 去添加更多的字段,比如使用 required 或者 unique 这样的简单验证去设置默认值。参考 Mongoose 文档。 -[C]RUD Part I - CREATE - -/* 示例 */ -var someFunc = function(done) { - // 执行一些可能产生错误的代码 - if(error) return done(error); - done(null, result); -}; +
0首先,我们需要一个Schema。每个模式都映射到MongoDB集合。它定义了该集合中文档的形状。 0模式是模型的构建块。它们可以嵌套来创建复杂的模型,但在这种情况下,我们会保持简单。 0模型允许您创建对象的实例,称为文档。 0创建一个拥有此原型的人: +- Person Prototype - +-------------------- +name : string [required] +age : number +favoriteFoods : array of strings (*) 0使用mongoose基本模式类型。如果需要,还可以添加0个字段,使用简单的验证器,如required或unique, 0并设置默认值。请参阅mongoose文档 。 +[C] RUD第一部分 - 创建0注意:Glitch是一个真实的服务器,在真实服务器中,与db的交互发生在处理函数中。当某些事件发生时执行这些功能(例如某人在您的API上命中端点)。我们将在这些练习中遵循相同的方法。 done()函数是一个回调,告诉我们在完成插入,搜索,更新或删除等异步操作后我们可以继续。它遵循Node约定,应该在成功时调用done(null,data),或者在出错时调用(err)。 0警告 - 与远程服务交互时,可能会发生错误! +/* Example */ +var someFunc = function(done) { +//... do something (risky) ... +if(error) return done(error); +done(null, result); +};
## Instructions -
-创建一个拥有以下 Prototype 的 Person 对象: -
-- Person Prototype -
---------------------
-name : string [required]
-age : number
-favoriteFoods : array of strings (*) -
+
-你可以使用基础的 SchemaTypes 去添加更多的字段, -比如使用 required 或者 unique 这样的简单验证去设置默认值。 -参考 Mongoose 文档
## Tests @@ -63,7 +31,7 @@ favoriteFoods : array of strings (*) ```yml tests: - - text: 成功创建一个 Schema 实例。 + - text: 从mongoose模式创建实例应该会成功 testString: 'getUserInput => $.post(getUserInput(''url'') + ''/_api/mongoose-model'', {name: ''Mike'', age: 28, favoriteFoods: [''pizza'', ''cheese'']}).then(data => { assert.equal(data.name, ''Mike'', ''"model.name" is not what expected''); assert.equal(data.age, ''28'', ''"model.age" is not what expected''); assert.isArray(data.favoriteFoods, ''"model.favoriteFoods" is not an Array''); assert.include(data.favoriteFoods, ''pizza'', ''"model.favoriteFoods" does not include the expected items''); assert.include(data.favoriteFoods, ''cheese'', ''"model.favoriteFoods" does not include the expected items''); }, xhr => { throw new Error(xhr.responseText); })' ``` @@ -79,11 +47,6 @@ tests:
```js -/** - Backend challenges don't need solutions, - because they would need to be tested against a full working project. - Please check our contributing guidelines to learn more. -*/ +// solution required ``` -
diff --git a/curriculum/challenges/chinese/05-apis-and-microservices/mongodb-and-mongoose/create-and-save-a-record-of-a-model.chinese.md b/curriculum/challenges/chinese/05-apis-and-microservices/mongodb-and-mongoose/create-and-save-a-record-of-a-model.chinese.md index 0b1b3772679..ab8d3c1b4ae 100644 --- a/curriculum/challenges/chinese/05-apis-and-microservices/mongodb-and-mongoose/create-and-save-a-record-of-a-model.chinese.md +++ b/curriculum/challenges/chinese/05-apis-and-microservices/mongodb-and-mongoose/create-and-save-a-record-of-a-model.chinese.md @@ -1,28 +1,21 @@ --- id: 587d7fb6367417b2b2512c09 title: Create and Save a Record of a Model +localeTitle: 创建并保存模型记录 challengeType: 2 -isHidden: false -localeTitle: 用模型来创建并保存一条记录 --- ## Description -
-在本挑战中创建保存一条记录。 +
0使用之前构建的Person构造函数创建文档实例。将具有字段名称,年龄和favoriteFoods的对象传递给构造函数。它们的类型必须符合Person Schema中的类型。然后在返回的文档实例上调用方法document.save()。使用Node约定传递回调。这是一种常见模式,以下所有CRUD方法都将这样的回调函数作为最后一个参数。 +/* Example */ +// ... +person.save(function(err, data) { +// ...do your stuff here... +});
## Instructions -
-使用 Person 的 constructor(构造器)函数可以创建一个 document 对象,该对象包含nameagefavoriteFoods字段。这些字段的类型必须符合 Person Schema 里面定义的类型。然后调用document.save()。使用 Node 惯例传递 callback。通常情况下,所有的 CRUD(增查改删)方法都会像下面一样作为最后一个参数去执行一个callback()。 - -```js -/* Example */ - -// ... -person.save(function(err, data) { - // ...do your stuff here... -}); -``` +
@@ -31,8 +24,9 @@ person.save(function(err, data) { ```yml tests: - - text: 成功创建一条 db 并保存。 + - text: 创建和保存数据库项应该会成功 testString: 'getUserInput => $.get(getUserInput(''url'') + ''/_api/create-and-save-person'').then(data => { assert.isString(data.name, ''"item.name" should be a String''); assert.isNumber(data.age, ''28'', ''"item.age" should be a Number''); assert.isArray(data.favoriteFoods, ''"item.favoriteFoods" should be an Array''); assert.equal(data.__v, 0, ''The db item should be not previously edited''); }, xhr => { throw new Error(xhr.responseText); })' + ```
@@ -46,11 +40,6 @@ tests:
```js -/** - Backend challenges don't need solutions, - because they would need to be tested against a full working project. - Please check our contributing guidelines to learn more. -*/ +// solution required ``` -
diff --git a/curriculum/challenges/chinese/05-apis-and-microservices/mongodb-and-mongoose/create-many-records-with-model.create.chinese.md b/curriculum/challenges/chinese/05-apis-and-microservices/mongodb-and-mongoose/create-many-records-with-model.create.chinese.md index 11f18b1b557..834e6be9d88 100644 --- a/curriculum/challenges/chinese/05-apis-and-microservices/mongodb-and-mongoose/create-many-records-with-model.create.chinese.md +++ b/curriculum/challenges/chinese/05-apis-and-microservices/mongodb-and-mongoose/create-many-records-with-model.create.chinese.md @@ -1,19 +1,17 @@ --- id: 587d7fb7367417b2b2512c0a title: Create Many Records with model.create() +localeTitle: 使用model.create()创建许多记录 challengeType: 2 -isHidden: false -localeTitle: 使用 model.create() 创建许多记录 --- ## Description -
-有时你需要创建很多的 model 实例。例如:在使用初始数据为数据库初始化时,Model.create()接受一组像[{name:'John', ...}, {...}, ...]的数组作为第一个参数,并将其保存到数据库。 +
0有时您需要创建模型的许多实例,例如,在使用初始数据为数据库播种时。 Model.create()接受一个对象数组,如[{name:'John',...},{...},...]作为第一个参数,并将它们全部保存在db中。使用函数参数arrayOfPeople使用Model.create()创建许多人。
## Instructions -
-使用arrayOfPeople作为Model.create()的参数创建很多个 people 实例。 +
+
## Tests @@ -21,7 +19,7 @@ localeTitle: 使用 model.create() 创建许多记录 ```yml tests: - - text: 应当可以一次性创建多个 item(项目)。 + - text: 一次创建多个数据库项应该会成功 testString: 'getUserInput => $.ajax({url: getUserInput(''url'') + ''/_api/create-many-people'', type: ''POST'', contentType:''application/json'', data: JSON.stringify([{name: ''John'', age: 24, favoriteFoods: [''pizza'', ''salad'']}, {name: ''Mary'', age: 21, favoriteFoods: [''onions'', ''chicken'']}])}).then(data => { assert.isArray(data, ''the response should be an array''); assert.equal(data.length, 2, ''the response does not contain the expected number of items''); assert.equal(data[0].name, ''John'', ''The first item is not correct''); assert.equal(data[0].__v, 0, ''The first item should be not previously edited''); assert.equal(data[1].name, ''Mary'', ''The second item is not correct''); assert.equal(data[1].__v, 0, ''The second item should be not previously edited''); }, xhr => { throw new Error(xhr.responseText); })' ``` @@ -37,11 +35,6 @@ tests:
```js -/** - Backend challenges don't need solutions, - because they would need to be tested against a full working project. - Please check our contributing guidelines to learn more. -*/ +// solution required ``` -
diff --git a/curriculum/challenges/chinese/05-apis-and-microservices/mongodb-and-mongoose/delete-many-documents-with-model.remove.chinese.md b/curriculum/challenges/chinese/05-apis-and-microservices/mongodb-and-mongoose/delete-many-documents-with-model.remove.chinese.md index 4c6acbb06ab..857aa12a6c8 100644 --- a/curriculum/challenges/chinese/05-apis-and-microservices/mongodb-and-mongoose/delete-many-documents-with-model.remove.chinese.md +++ b/curriculum/challenges/chinese/05-apis-and-microservices/mongodb-and-mongoose/delete-many-documents-with-model.remove.chinese.md @@ -1,20 +1,18 @@ --- id: 587d7fb8367417b2b2512c11 title: Delete Many Documents with model.remove() +localeTitle: 使用model.remove()删除许多文档 challengeType: 2 -isHidden: false -localeTitle: 使用 model.remove() 删除许多文档 --- ## Description -
-Model.remove() 可用于删除与给定条件匹配的所有 document。 +
+Model.remove()用于删除与给定条件匹配的所有文档。使用Model.remove()删除名称为“Mary”的所有人员。将其传递给查询文档,其中设置了“name”字段,当然还有回调。 0注意:Model.remove()不返回已删除的文档,而是返回包含操作结果和受影响项目数的JSON对象。不要忘记将它传递给done()回调,因为我们在测试中使用它。
## Instructions -
-如果想要删除所有叫 “Mary” 的人, 可以使用 Model.remove()。 传入一个设置了 “name” 字段的 document 作为查询条件,当然还需要一个回调函数。 -注意: Model.remove() 不会返回被删除的 document, 但是会返回一个包含操作结果和受影响的 item 数量的 JSON 对象。 不要忘记将它传递给 done() 回调,因为我们在测试中使用它。 +
+
## Tests @@ -22,7 +20,7 @@ localeTitle: 使用 model.remove() 删除许多文档 ```yml tests: - - text: 一次性成功的删除多个 item(项目)。 + - text: 一次删除多个项目应该会成功 testString: 'getUserInput => $.ajax({url: getUserInput(''url'') + ''/_api/remove-many-people'', type: ''POST'', contentType:''application/json'', data: JSON.stringify([{name: ''Mary'', age: 16, favoriteFoods: [''lollipop'']}, {name: ''Mary'', age: 21, favoriteFoods: [''steak'']}])}).then(data => { assert.isTrue(!!data.ok, ''The mongo stats are not what expected''); assert.equal(data.n, 2, ''The number of items affected is not what expected''); assert.equal(data.count, 0, ''the db items count is not what expected''); }, xhr => { throw new Error(xhr.responseText); })' ``` @@ -38,11 +36,6 @@ tests:
```js -/** - Backend challenges don't need solutions, - because they would need to be tested against a full working project. - Please check our contributing guidelines to learn more. -*/ +// solution required ``` -
diff --git a/curriculum/challenges/chinese/05-apis-and-microservices/mongodb-and-mongoose/delete-one-document-using-model.findbyidandremove.chinese.md b/curriculum/challenges/chinese/05-apis-and-microservices/mongodb-and-mongoose/delete-one-document-using-model.findbyidandremove.chinese.md index db7e37c6dc0..c119ce472c5 100644 --- a/curriculum/challenges/chinese/05-apis-and-microservices/mongodb-and-mongoose/delete-one-document-using-model.findbyidandremove.chinese.md +++ b/curriculum/challenges/chinese/05-apis-and-microservices/mongodb-and-mongoose/delete-one-document-using-model.findbyidandremove.chinese.md @@ -1,19 +1,16 @@ --- id: 587d7fb8367417b2b2512c10 title: Delete One Document Using model.findByIdAndRemove +localeTitle: 使用model.findByIdAndRemove删除一个文档 challengeType: 2 -isHidden: false -forumTopicId: 301539 -localeTitle: 使用 model.findByIdAndRemove() 删除一个文档 --- ## Description -
-你可以使用 findByIdAndRemove() 或者 findOneAndRemove() 方法, 通过 _id 删除一个人员。 它和上面的更新方法很像,都是先通过 personId 找到对应的 document,再删除,并返回被删除的 document。 +
0通过她的_id删除一个人。您应该使用findByIdAndRemove()或findOneAndRemove()方法之一。它们与之前的更新方法类似。他们将删除的文件传递给cb。像往常一样,使用函数参数personId作为搜索关键字。
## Instructions -
+
@@ -22,7 +19,7 @@ localeTitle: 使用 model.findByIdAndRemove() 删除一个文档 ```yml tests: - - text: 成功删除一个 item(项目)。 + - text: 删除项目应该会成功 testString: 'getUserInput => $.post(getUserInput(''url'') + ''/_api/remove-one-person'', {name:''Jason Bourne'', age: 36, favoriteFoods:[''apples'']}).then(data => { assert.equal(data.name, ''Jason Bourne'', ''item.name is not what expected''); assert.equal(data.age, 36, ''item.age is not what expected''); assert.deepEqual(data.favoriteFoods, [''apples''], ''item.favoriteFoods is not what expected''); assert.equal(data.__v, 0); assert.equal(data.count, 0, ''the db items count is not what expected''); }, xhr => { throw new Error(xhr.responseText); })' ``` @@ -38,11 +35,6 @@ tests:
```js -/** - Backend challenges don't need solutions, - because they would need to be tested against a full working project. - Please check our contributing guidelines to learn more. -*/ +// solution required ``` -
diff --git a/curriculum/challenges/chinese/05-apis-and-microservices/mongodb-and-mongoose/install-and-set-up-mongoose.chinese.md b/curriculum/challenges/chinese/05-apis-and-microservices/mongodb-and-mongoose/install-and-set-up-mongoose.chinese.md index 36d24e9aa71..bf8399fdf50 100644 --- a/curriculum/challenges/chinese/05-apis-and-microservices/mongodb-and-mongoose/install-and-set-up-mongoose.chinese.md +++ b/curriculum/challenges/chinese/05-apis-and-microservices/mongodb-and-mongoose/install-and-set-up-mongoose.chinese.md @@ -1,23 +1,16 @@ --- id: 587d7fb6367417b2b2512c06 title: Install and Set Up Mongoose +localeTitle: 安装和设置Mongoose challengeType: 2 -isHidden: false -localeTitle: 安装和设置 Mongoose --- ## Description -
-在 package.json 文件中添加 MongoDB 和 Mongoose 依赖,将 mLab 数据库的 URI 作为 MONGO_URI 变量存储在私有 .env 文件中。然后require('mongoose'),使用mongoose.connect()命令来连接数据库。 - -```js -mongoose.connect(, { useNewUrlParser: true, useUnifiedTopology: true }); -``` - +
0将mongodb和mongoose添加到项目的package.json中。然后需要猫鼬。将mLab数据库URI作为MONGO_URI存储在私有.env文件中。使用mongoose.connect连接到数据库(
## Instructions -
+
@@ -26,11 +19,11 @@ mongoose.connect(, { useNewUrlParser: true, useUnifiedTopology: true } ```yml tests: - - text: "在 package.json 文件中应该有 'mongodb' 依赖。" + - text: '"mongodb"依赖应该在package.json' testString: 'getUserInput => $.get(getUserInput(''url'') + ''/_api/file/package.json'').then(data => { var packJson = JSON.parse(data); assert.property(packJson.dependencies, ''mongodb''); }, xhr => { throw new Error(xhr.responseText); })' - - text: "在 package.json 文件中应该有 'mongoose' 依赖。" + - text: '"mongoose"依赖应该在package.json' testString: 'getUserInput => $.get(getUserInput(''url'') + ''/_api/file/package.json'').then(data => { var packJson = JSON.parse(data); assert.property(packJson.dependencies, ''mongoose''); }, xhr => { throw new Error(xhr.responseText); })' - - text: "'mongoose' 应该已经连接数据库。" + - text: '"mongoose"应该连接到数据库' testString: 'getUserInput => $.get(getUserInput(''url'') + ''/_api/is-mongoose-ok'').then(data => {assert.isTrue(data.isMongooseOk, ''mongoose is not connected'')}, xhr => { throw new Error(xhr.responseText); })' ``` @@ -46,11 +39,6 @@ tests:
```js -/** - Backend challenges don't need solutions, - because they would need to be tested against a full working project. - Please check our contributing guidelines to learn more. -*/ +// solution required ``` -
diff --git a/curriculum/challenges/chinese/05-apis-and-microservices/mongodb-and-mongoose/perform-classic-updates-by-running-find-edit-then-save.chinese.md b/curriculum/challenges/chinese/05-apis-and-microservices/mongodb-and-mongoose/perform-classic-updates-by-running-find-edit-then-save.chinese.md index 0627be0ba60..285c7a6aa23 100644 --- a/curriculum/challenges/chinese/05-apis-and-microservices/mongodb-and-mongoose/perform-classic-updates-by-running-find-edit-then-save.chinese.md +++ b/curriculum/challenges/chinese/05-apis-and-microservices/mongodb-and-mongoose/perform-classic-updates-by-running-find-edit-then-save.chinese.md @@ -1,23 +1,17 @@ --- id: 587d7fb8367417b2b2512c0e title: 'Perform Classic Updates by Running Find, Edit, then Save' +localeTitle: '通过运行查找,编辑然后保存来执行经典更新' challengeType: 2 -isHidden: false -localeTitle: 通过运行 find、edit、save 来执行经典更新 --- ## Description -
- -传统应用里,如果你想要编辑 document,然后在某处使用它。你就必须在服务器响应中将其返回。Mongoose 有一个专用的更新方法:Model.update() , 它与低级的 mongo 驱动绑定,可以批量编辑符合特定条件的多个 document,而不用返回更新后的 document,取而代之返回'状态'消息。此外,它使模型校验变得更棘手,因为它是直接调用了 mongo 的驱动程序。 +
0在过去的好时光中,如果您想编辑文档并能够以某种方式使用它,例如在服务器响应中将其发回,则需要执行此操作。 Mongoose有一个专用的更新方法:Model.update()。它与低级mongo驱动程序绑定。它可以批量编辑符合特定条件的许多文档,但它不会发回更新的文档,只会发送“状态”消息。此外,它使模型验证变得困难,因为它只是直接调用mongo驱动程序。 0使用参数personId作为搜索关键字,通过_id(使用上述任何方法)查找人物。将“hamburger”添加到她最喜欢的食物列表中(您可以使用Array.push())。然后 - 在find回调中 - save()更新的Person。 +[*]提示:如果你的Schema中你将favoriteFoods声明为一个数组而没有指定类型(即[String]),这可能会很棘手。在那种情况下,favorsFoods默认为Mixed type,你必须使用document.markModified('edited-field')手动将其标记为已编辑。 (http://mongoosejs.com/docs/schematypes.html - #Mixed)
## Instructions -
- -使用参数 personId 作为搜索关键字,然后通过 _id 找到一个 person(使用上述任何一种方法). 将 “hamburger” 添加到她的 favoriteFoods 列中去 (可以使用 Array.push())。然后在 .find() 的回调里通过 .save() 方法更新。 - -[*] 提示: 如果你在 Schema 中将 favoriteFoods 声明为一个 Array(数组), 而没有指定数组的类型(如:[String]),结果会让人很意外。 在这种情况下,favoriteFoods 默认为 Mixed 类型。如果想要编辑它,就必须执行 document.markModified('edited-field')。(http://mongoosejs.com/docs/schematypes.html - #Mixed) +
@@ -26,8 +20,9 @@ localeTitle: 通过运行 find、edit、save 来执行经典更新 ```yml tests: - - text: 对一个 item(项目)的 Find-edit-update 操作成功 + - text: 查找 - 编辑 - 更新项目应该成功 testString: "getUserInput => $.post(getUserInput('url') + '/_api/find-edit-save', {name:'Poldo', age: 40, favoriteFoods:['spaghetti']}).then(data => { assert.equal(data.name, 'Poldo', 'item.name is not what is expected'); assert.equal(data.age, 40, 'item.age is not what expected'); assert.deepEqual(data.favoriteFoods, ['spaghetti', 'hamburger'], 'item.favoriteFoods is not what expected'); assert.equal(data.__v, 1, 'The item should be previously edited'); }, xhr => { throw new Error(xhr.responseText); })" + ```
@@ -41,11 +36,6 @@ tests:
```js -/** - Backend challenges don't need solutions, - because they would need to be tested against a full working project. - Please check our contributing guidelines to learn more. -*/ +// solution required ``` -
diff --git a/curriculum/challenges/chinese/05-apis-and-microservices/mongodb-and-mongoose/perform-new-updates-on-a-document-using-model.findoneandupdate.chinese.md b/curriculum/challenges/chinese/05-apis-and-microservices/mongodb-and-mongoose/perform-new-updates-on-a-document-using-model.findoneandupdate.chinese.md index 88ee2431f11..f3dff1feb4e 100644 --- a/curriculum/challenges/chinese/05-apis-and-microservices/mongodb-and-mongoose/perform-new-updates-on-a-document-using-model.findoneandupdate.chinese.md +++ b/curriculum/challenges/chinese/05-apis-and-microservices/mongodb-and-mongoose/perform-new-updates-on-a-document-using-model.findoneandupdate.chinese.md @@ -1,21 +1,17 @@ --- id: 587d7fb8367417b2b2512c0f title: Perform New Updates on a Document Using model.findOneAndUpdate() +localeTitle: 使用model.findOneAndUpdate()对文档执行新更新 challengeType: 2 -isHidden: false -forumTopicId: 301542 -localeTitle: 使用 model.findOneAndUpdate() 对文档执行新的更新 --- ## Description -
-mongoose 的最新版本简化了 documents 的更新。 但是一些高级的用法 (比如 pre/post 钩子, 验证) 更复杂, 所以老方法更常用。当通过 Id 进行搜索时还可以使用 findByIdAndUpdate()。 +
0最新版本的mongoose具有简化文档更新的方法。一些更高级的功能(即前/后挂钩,验证)与此方法的行为不同,因此Classic方法在许多情况下仍然有用。在按Id搜索时可以使用findByIdAndUpdate()。 0按名称查找人员并将其年龄设置为20.使用函数参数personName作为搜索关键字。 0提示:我们希望您返回更新的文档。为此,您需要将选项文档{new:true}作为findOneAndUpdate()的第三个参数传递。默认情况下,这些方法返回未修改的对象。
## Instructions -
-使用 personName 作为搜索的关键词查找 person,并将查到的 person 的年龄设为 20 岁。 -提示: 我们想要你返更新后的 document,你可以把 findOneAndUpdate() 的第三个参数设置为 {new: true}。 默认情况下,这些方法返回未被修改的数据。 +
+
## Tests @@ -23,7 +19,7 @@ mongoose 的最新版本简化了 documents 的更新。 但是一些高级的 ```yml tests: - - text: 对一个 item(项目)的 findOneAndUpdate 操作成功 + - text: findOneAndUpdate项应该成功 testString: 'getUserInput => $.post(getUserInput(''url'') + ''/_api/find-one-update'', {name:''Dorian Gray'', age: 35, favoriteFoods:[''unknown'']}).then(data => { assert.equal(data.name, ''Dorian Gray'', ''item.name is not what expected''); assert.equal(data.age, 20, ''item.age is not what expected''); assert.deepEqual(data.favoriteFoods, [''unknown''], ''item.favoriteFoods is not what expected''); assert.equal(data.__v, 0, ''findOneAndUpdate does not increment version by design !!!''); }, xhr => { throw new Error(xhr.responseText); })' ``` @@ -39,11 +35,6 @@ tests:
```js -/** - Backend challenges don't need solutions, - because they would need to be tested against a full working project. - Please check our contributing guidelines to learn more. -*/ +// solution required ``` -
diff --git a/curriculum/challenges/chinese/05-apis-and-microservices/mongodb-and-mongoose/use-model.find-to-search-your-database.chinese.md b/curriculum/challenges/chinese/05-apis-and-microservices/mongodb-and-mongoose/use-model.find-to-search-your-database.chinese.md index 1e5ddb48329..87ebd519edc 100644 --- a/curriculum/challenges/chinese/05-apis-and-microservices/mongodb-and-mongoose/use-model.find-to-search-your-database.chinese.md +++ b/curriculum/challenges/chinese/05-apis-and-microservices/mongodb-and-mongoose/use-model.find-to-search-your-database.chinese.md @@ -1,20 +1,16 @@ --- id: 587d7fb7367417b2b2512c0b title: Use model.find() to Search Your Database +localeTitle: 使用model.find()搜索数据库 challengeType: 2 -isHidden: false -forumTopicId: 301543 -localeTitle: 使用 model.find() 查找数据库 --- ## Description -
-使用Model.find() -> [Person]来查询给定名称的所有的人。 -最简单的用法:Model.find()接受一个查询的 document(一个 JSON 对象)作为第一参数,然后是回调。它将返回匹配到的项目组成的数组。这个支持极其广泛的搜索选项。使用人名作为搜索的关键词,来校验它。 +
0使用Model.find() - > [Person]查找具有给定名称的所有人0在最简单的用法中,Model.find()接受查询文档(JSON对象)作为第一个参数,然后接受回调。它返回一个匹配数组。它支持极其广泛的搜索选项。在文档中查看它。使用函数参数personName作为搜索关键字。
## Instructions -
+
@@ -23,7 +19,7 @@ localeTitle: 使用 model.find() 查找数据库 ```yml tests: - - text: 成功找到所有符合条件的 item(项目)。 + - text: 找到与标准对应的所有项目都应该成功 testString: 'getUserInput => $.post(getUserInput(''url'') + ''/_api/find-all-by-name'', {name: ''r@nd0mN4m3'', age: 24, favoriteFoods: [''pizza'']}).then(data => { assert.isArray(data, ''the response should be an Array''); assert.equal(data[0].name, ''r@nd0mN4m3'', ''item.name is not what expected''); assert.equal(data[0].__v, 0, ''The item should be not previously edited''); }, xhr => { throw new Error(xhr.responseText); })' ``` @@ -39,11 +35,6 @@ tests:
```js -/** - Backend challenges don't need solutions, - because they would need to be tested against a full working project. - Please check our contributing guidelines to learn more. -*/ +// solution required ``` -
diff --git a/curriculum/challenges/chinese/05-apis-and-microservices/mongodb-and-mongoose/use-model.findbyid-to-search-your-database-by-id.chinese.md b/curriculum/challenges/chinese/05-apis-and-microservices/mongodb-and-mongoose/use-model.findbyid-to-search-your-database-by-id.chinese.md index 3d0792362ec..6f5f0cc22ac 100644 --- a/curriculum/challenges/chinese/05-apis-and-microservices/mongodb-and-mongoose/use-model.findbyid-to-search-your-database-by-id.chinese.md +++ b/curriculum/challenges/chinese/05-apis-and-microservices/mongodb-and-mongoose/use-model.findbyid-to-search-your-database-by-id.chinese.md @@ -1,19 +1,17 @@ --- id: 587d7fb7367417b2b2512c0d title: Use model.findById() to Search Your Database By _id +localeTitle: 使用model.findById()按_id搜索数据库 challengeType: 2 -isHidden: false -localeTitle: 使用 model.findById() 按 _id 搜索数据库 --- ## Description -
-当我们保存一个 document, MongoDB 自动添加 _id 字段,并给该字段设置 unique(唯一)属性。通过 _id 搜索是一个非常频繁的操作,所以 Mongose 为它提供了一个专门的方法。 +
0保存文档时,mongodb会自动添加字段_id,并将其设置为唯一的字母数字键。按_id搜索是一种非常频繁的操作,因此mongoose为它提供了一种专用方法。使用Model.findById() - > Person找到具有给定_id的(仅!!)人物。使用函数参数personId作为搜索关键字。
## Instructions -
-使用人物 Id 作为参数,执行Model.findById() -> Person,找到这个 _id 对应的唯一的一个人。 +
+
## Tests @@ -21,8 +19,9 @@ localeTitle: 使用 model.findById() 按 _id 搜索数据库 ```yml tests: - - text: 通过 Id 成功找到对应的 item(项目)。 + - text: 找到Id应该成功的项目 testString: "getUserInput => $.get(getUserInput('url') + '/_api/find-by-id').then(data => { assert.equal(data.name, 'test', 'item.name is not what expected'); assert.equal(data.age, 0, 'item.age is not what expected'); assert.deepEqual(data.favoriteFoods, ['none'], 'item.favoriteFoods is not what expected'); assert.equal(data.__v, 0, 'The item should be not previously edited'); }, xhr => { throw new Error(xhr.responseText); })" + ```
@@ -36,11 +35,6 @@ tests:
```js -/** - Backend challenges don't need solutions, - because they would need to be tested against a full working project. - Please check our contributing guidelines to learn more. -*/ +// solution required ``` -
diff --git a/curriculum/challenges/chinese/05-apis-and-microservices/mongodb-and-mongoose/use-model.findone-to-return-a-single-matching-document-from-your-database.chinese.md b/curriculum/challenges/chinese/05-apis-and-microservices/mongodb-and-mongoose/use-model.findone-to-return-a-single-matching-document-from-your-database.chinese.md index 34635f9b48e..f85e862e856 100644 --- a/curriculum/challenges/chinese/05-apis-and-microservices/mongodb-and-mongoose/use-model.findone-to-return-a-single-matching-document-from-your-database.chinese.md +++ b/curriculum/challenges/chinese/05-apis-and-microservices/mongodb-and-mongoose/use-model.findone-to-return-a-single-matching-document-from-your-database.chinese.md @@ -1,20 +1,18 @@ --- id: 587d7fb7367417b2b2512c0c title: Use model.findOne() to Return a Single Matching Document from Your Database +localeTitle: 使用model.findOne()从数据库中返回单个匹配文档 challengeType: 2 -isHidden: false -forumTopicId: 301545 -localeTitle: 使用 model.findOne() 从数据库中返回一个匹配的文档 --- ## Description -
-Model.findOne()表现像Model.find(),但是它仅仅返回一个 document(而不是一个数组),即使数据库里有很多条 item(项目)。当你按声明成unique的属性进行搜索时,Model.findOne()尤其有用。 +
+Model.findOne()的行为类似于.find(),但它只返回一个文档(不是数组),即使有多个项目也是如此。在按声明为唯一的属性进行搜索时,它尤其有用。使用Model.findOne() - > Person,找到一个在她的收藏夹中有某种食物的人。使用函数参数food作为搜索键。
## Instructions -
-把 food 作为Model.findOne() -> Person的参数,来找到一个在她的爱好中有某一食物的人。 +
+
## Tests @@ -22,7 +20,7 @@ localeTitle: 使用 model.findOne() 从数据库中返回一个匹配的文档 ```yml tests: - - text: 成功找到一个 item(项目)。 + - text: 找一个项应该成功 testString: 'getUserInput => $.post(getUserInput(''url'') + ''/_api/find-one-by-food'', {name: ''Gary'', age: 46, favoriteFoods: [''chicken salad'']}).then(data => { assert.equal(data.name, ''Gary'', ''item.name is not what expected''); assert.deepEqual(data.favoriteFoods, [''chicken salad''], ''item.favoriteFoods is not what expected''); assert.equal(data.__v, 0, ''The item should be not previously edited''); }, xhr => { throw new Error(xhr.responseText); })' ``` @@ -38,11 +36,6 @@ tests:
```js -/** - Backend challenges don't need solutions, - because they would need to be tested against a full working project. - Please check our contributing guidelines to learn more. -*/ +// solution required ``` -
diff --git a/curriculum/challenges/chinese/06-information-security-and-quality-assurance/advanced-node-and-express/announce-new-users.chinese.md b/curriculum/challenges/chinese/06-information-security-and-quality-assurance/advanced-node-and-express/announce-new-users.chinese.md index e354b54cae5..30aecacab0e 100644 --- a/curriculum/challenges/chinese/06-information-security-and-quality-assurance/advanced-node-and-express/announce-new-users.chinese.md +++ b/curriculum/challenges/chinese/06-information-security-and-quality-assurance/advanced-node-and-express/announce-new-users.chinese.md @@ -2,38 +2,24 @@ id: 589fc832f9fc0f352b528e78 title: Announce New Users challengeType: 2 -isHidden: false -forumTopicId: 301546 -localeTitle: 用户公告 +videoUrl: '' +localeTitle: 宣布新用户 --- ## Description -
-注意,本项目在这个 Glitch 项目的基础上进行开发,你也可以从 GitHub 上克隆。 -许多聊天室都有这个功能:所有已连接到服务器的在线用户都会看到有人加入或退出的提醒。我们已经写好了处理连接和断开事件的代码,只要对这个方法稍作修改就可以实现这个功能。在事件中,我们需要发送这三条信息:连接或断开的用户名、当前用户数量、事件类型(即需要知道用户究竟是连接还是断开)。 -
请将事件名称更改为 'user',其中应包含如下字段:'name'、'currentUsers'、'connected'(布尔值,对于连接是 true,断开是 false)。记得要修改之前我们写好的处理 'user count' 的那部分代码,现在我们应传入布尔值:io.emit('user', {name: socket.request.user.name, currentUsers, connected: true}); -现在,我们的客户端已经有足够的信息显示现有用户数量和发送用户上下线通知。接下来我们需要在客户端监听 'user' 事件,然后使用 jQuery 把#num-users节点的文本内容更新为 '{NUMBER} users online'。同时,我们需要为<ul>添加一个 id 为 'messages' 且带有 '{NAME} has {joined/left} the chat.' 文本的<li>:An implementation of this could look like the following:
-其中一种实现如下:
- -```js -socket.on('user', function(data){ - $('#num-users').text(data.currentUsers+' users online'); +
提醒一下,这个项目是基于Glitch的以下入门项目构建的,或者是从GitHub克隆的。许多聊天室能够在用户连接或断开连接时进行通知,然后将其显示给聊天中的所有连接用户。看起来您已经在连接和断开连接上发出事件,您只需修改此事件即可支持此功能。最合乎逻辑的方法是使用事件发送3个数据:连接/断开用户的名称,当前用户计数以及连接或断开连接的名称。
将事件名称更改为“user”,并且数据传递一个对象,包含字段'name','currentUsers'和boolean'connected'(如果是连接则为true,对于断开发送的用户,则为false)。确保对我们有'用户计数'事件的两个点进行更改,并将断开连接设置为对'field'字段发送false,而不是像在connect上发出的事件那样为true。 io.emit('user', {name: socket.request.user.name, currentUsers, connected: true});现在,您的客户端将拥有所有必要信息,以便在用户连接或断开连接时正确显示当前用户数和通知!要在客户端处理此事件,我们应该监听“用户”,然后使用jQuery将#num-users的文本更改为“{NUMBER}在线用户”,并附加<li> ,以更新当前用户数<li>使用ID为'messages'的无序列表,其中'{NAME}已{加/左}聊天。'。此实现可能如下所示:
 socket.on('user',function(data){
+  $('#num-users')。text(data.currentUsers +'users online');
   var message = data.name;
-  if(data.connected) {
-    message += ' has joined the chat.';
+  if(data.connected){
+    消息+ ='已加入聊天。';
   } else {
-    message += ' has left the chat.';
+    消息+ ='离开了聊天。';
   }
-  $('#messages').append($('
  • ').html(''+ message +'<\/b>')); -}); -``` - -完成上述要求后,你就可以在左边提交你的页面链接。 -
  • + $('#messages')。append($('<li>')。html('<b>'+ message +'<\ / b>')); +}); 当您认为自己已经做对时,请提交您的页面。
    ## Instructions -
    - +
    ## Tests @@ -41,9 +27,9 @@ socket.on('user', function(data){ ```yml tests: - - text: user 事件应发送包含 name、currentUsers、connected 字段的对象。 + - text: 使用name,currentUsers和connected发出事件“user” testString: getUserInput => $.get(getUserInput('url')+ '/_api/server.js') .then(data => { assert.match(data, /io.emit.*('|")user('|").*name.*currentUsers.*connected/gi, 'You should have an event emitted named user sending name, currentUsers, and connected'); }, xhr => { throw new Error(xhr.statusText); }) - - text: '客户端应处理和显示 "user" 对象中的信息。' + - text: 客户正确处理和显示事件'用户'中的新数据 testString: "getUserInput => $.get(getUserInput('url')+ '/public/client.js') .then(data => { assert.match(data, /socket.on.*('|\")user('|\")[^]*num-users/gi, 'You should change the text of #num-users within on your client within the \"user\" even listener to show the current users connected'); assert.match(data, /socket.on.*('|\")user('|\")[^]*messages.*li/gi, 'You should append a list item to #messages on your client within the \"user\" event listener to announce a user came or went'); }, xhr => { throw new Error(xhr.statusText); })" ``` @@ -59,11 +45,6 @@ tests:
    ```js -/** - Backend challenges don't need solutions, - because they would need to be tested against a full working project. - Please check our contributing guidelines to learn more. -*/ +// solution required ``` -
    diff --git a/curriculum/challenges/chinese/06-information-security-and-quality-assurance/advanced-node-and-express/authentication-strategies.chinese.md b/curriculum/challenges/chinese/06-information-security-and-quality-assurance/advanced-node-and-express/authentication-strategies.chinese.md index fe89ccecfb0..e965fd962e6 100644 --- a/curriculum/challenges/chinese/06-information-security-and-quality-assurance/advanced-node-and-express/authentication-strategies.chinese.md +++ b/curriculum/challenges/chinese/06-information-security-and-quality-assurance/advanced-node-and-express/authentication-strategies.chinese.md @@ -2,40 +2,25 @@ id: 5895f70df9fc0f352b528e68 title: Authentication Strategies challengeType: 2 -isHidden: false -forumTopicId: 301547 -localeTitle: 身份验证策略 +videoUrl: '' +localeTitle: 认证策略 --- ## Description -
    -注意,本项目在这个 Glitch 项目的基础上进行开发,你也可以从 GitHub 上克隆。 -现在,我们需要构建验证用户的策略,策略的选择有很多。比如,如果我们已经让用户在注册时填写了用户信息,那我们就可以基于这些信息验证;或者也可以引入第三方登录,如 Google 或者 Github。为此,你可以参考 Passports 中提供的策略插件。对于这个项目的验证策略,我们会采用自己搭建的方式完成。 -首先,我们需要引入 passport-local 作为依赖,然后将它添加到服务器,就像这样:const LocalStrategy = require('passport-local'); -然后,我们需要让 passport 使用实例化的本地策略对象。请注意,接下来的所有代码都应写在连接数据库的回调中,因为它们的执行都依赖数据库。 - -```js -passport.use(new LocalStrategy( - function(username, password, done) { - db.collection('users').findOne({ username: username }, function (err, user) { - console.log('User '+ username +' attempted to log in.'); - if (err) { return done(err); } - if (!user) { return done(null, false); } - if (password !== user.password) { return done(null, false); } - return done(null, user); - }); +
    提醒一下,这个项目是基于Glitch的以下入门项目构建的,或者是从GitHub克隆的。策略是一种验证用户的方法。您可以使用策略允许用户根据本地保存的信息(如果您首先注册)或从Google或Github等各种提供商进行身份验证。对于这个项目,我们将制定一个本地战略。要查看的策略100的列表,请访问网站护照这里 。将passport-local添加为依赖项并将其添加到服务器,如下所示: const LocalStrategy = require('passport-local');现在,您必须告诉护照使用实例化的LocalStartegy对象,并定义一些设置。确保这一点以及此时的所有内容都封装在数据库连接中,因为它依赖于它!
     passport.use(新的LocalStrategy(
    +  function(用户名,密码,已完成){
    +    db.collection('users')。findOne({username:username},function(err,user){
    +      console.log('用户'+用户名+'试图登录。');
    +      if(err){return done(err); }
    +      if(!user){return done(null,false); }
    +      if(password!== user.password){return done(null,false); }
    +      return done(null,user);
    +    });
       }
    -));
    -```
    -
    -这就是我们的用户验证逻辑:首先根据用户输入的用户名在数据库中寻找用户;然后检查密码是否匹配;最后如果没有发生错误,那么就会返回用户对象并通过验证。
    -我们也可以采用上面链接中提供的验证策略,一般来说,根据该策略仓库中的 README 来进行配置就足够了。一个很好的例子是 Github 策略,在该策略中,我们不需要写用户名或密码的相关验证逻辑,因为用户将被引导到 Github 页面进行验证。只要他们登录并同意,Github 就会返回他们的个人信息供我们使用。
    -以上就是本次挑战的内容。在下一个挑战中,我们会基于表单数据调用上面写好的验证策略。完成上述要求后,你就可以在左边提交你的页面链接。
    -
    +)); 这是我们尝试在本地验证某人时要采取的过程。首先,它尝试使用输入的用户名在我们的数据库中查找用户,然后检查要匹配的密码,最后如果没有弹出我们检查过的错误,如错误的密码,则返回用户对象,它们是认证。许多策略都是使用不同的设置设置的,一般来说,根据该策略库中的README很容易设置它。一个很好的例子是Github策略,我们不需要担心用户名或密码,因为用户将被发送到Github的auth页面进行身份验证,只要他们登录并同意,然后Github返回他们的个人资料我们用。在下一步中,我们将设置如何实际调用身份验证策略以根据表单数据验证用户!如果您认为自己已经完成了这一点,请提交您的页面。
    ## Instructions -
    - +
    ## Tests @@ -43,9 +28,9 @@ passport.use(new LocalStrategy( ```yml tests: - - text: 你的项目需要使用passport-local作为依赖。 + - text: Passport-local是一种依赖 testString: getUserInput => $.get(getUserInput('url')+ '/_api/package.json') .then(data => { var packJson = JSON.parse(data); assert.property(packJson.dependencies, 'passport-local', 'Your project should list "passport-local " as a dependency'); }, xhr => { throw new Error(xhr.statusText); }) - - text: 应正确地引入和设置passport-local。 + - text: Passport-local正确需要和设置 testString: getUserInput => $.get(getUserInput('url')+ '/_api/server.js') .then(data => { assert.match(data, /require.*("|')passport-local("|')/gi, 'You should have required passport-local'); assert.match(data, /new LocalStrategy/gi, 'You should have told passport to use a new strategy'); assert.match(data, /findOne/gi, 'Your new local strategy should use the findOne query to find a username based on the inputs'); }, xhr => { throw new Error(xhr.statusText); }) ``` @@ -61,11 +46,6 @@ tests:
    ```js -/** - Backend challenges don't need solutions, - because they would need to be tested against a full working project. - Please check our contributing guidelines to learn more. -*/ +// solution required ``` -
    diff --git a/curriculum/challenges/chinese/06-information-security-and-quality-assurance/advanced-node-and-express/authentication-with-socket.io.chinese.md b/curriculum/challenges/chinese/06-information-security-and-quality-assurance/advanced-node-and-express/authentication-with-socket.io.chinese.md index 1e191c63ce8..f0125b2c931 100644 --- a/curriculum/challenges/chinese/06-information-security-and-quality-assurance/advanced-node-and-express/authentication-with-socket.io.chinese.md +++ b/curriculum/challenges/chinese/06-information-security-and-quality-assurance/advanced-node-and-express/authentication-with-socket.io.chinese.md @@ -2,35 +2,20 @@ id: 589fc831f9fc0f352b528e77 title: Authentication with Socket.IO challengeType: 2 -isHidden: false -forumTopicId: 301548 -localeTitle: 用 Socket.IO 进行身份验证 +videoUrl: '' +localeTitle: 使用Socket.IO进行身份验证 --- ## Description -
    -注意,本项目在这个 Glitch 项目的基础上进行开发,你也可以从 GitHub 上克隆。 -目前,我们还无法确定连接到服务器的用户身份。虽然 req.user 包含用户信息,但这个只在用户直接与服务器交互(即不通过 web socket 访问服务器资源)时产正。当我们的用户通过 web socket 与服务器连接时,由于不存在 req 对象,因此我们无法获取用户数据。解决这个问题的方法之一是通过读取和解析请求中包含 passport session 的 cookie,然后反序列化,进而获取用户信息对象。幸运的是,npm 上有可以让这个复杂的流程简单化的库。 -
    添加 'passport.socketio' 作为依赖,然后赋值给 'passportSocketIo'。 -现在我们只需要做一些简单的配置,然后让 Socket.IO 使用它就可以了。请注意,这部分代码应添加在目前的 socket 代码之前,不应添加在目前的连接事件监听中: - -```js -io.use(passportSocketIo.authorize({ - cookieParser: cookieParser, - key: 'express.sid', - secret: process.env.SESSION_SECRET, - store: sessionStore -})); -``` - -你也可以为验证设置回调函数,为它传入 'success' 或 'fail'。这个函数会在用户尝试连接并完成验证后调用。 -现在,我们可以通过socket.request.user访问用户数据。例如,现在你在代码中添加以下内容:console.log('user ' + socket.request.user.name + ' connected');。这样我们就可以在服务端的控制台打印出通过 socket 连接到服务器的用户信息。 -完成上述要求后,你就可以在左边提交你的页面链接。如果运行出错,你可以在 here 这里检查这个项目的完成代码。 -
    +
    提醒一下,这个项目是基于Glitch的以下入门项目构建的,或者是从GitHub克隆的。目前,您无法确定谁连接到您的Web套接字。虽然'req.user'对用户对象进行了容器处理,但只有当您的用户与Web服务器进行交互并且使用Web套接字时,您才没有req(请求),因此没有用户数据。解决知道谁连接到您的Web套接字的问题的一种方法是解析和解码包含护照会话的cookie,然后对其进行反序列化以获取用户对象。幸运的是,NPM上有一个包,只是为了将一次复杂的任务变成简单的事情!
    将“passport.socketio”添加为依赖项,并将其命名为“passportSocketIo”。现在我们只需要告诉Socket.IO使用它并设置选项。确保在现有套接字代码之前添加它,而不是在现有连接侦听器中添加。对于您的服务器,它应如下所示:
     io.use(passportSocketIo.authorize({
    +  cookieParser:cookieParser,
    +  key:'express.sid',
    +  secret:process.env.SESSION_SECRET,
    +  store:sessionStore
    +})); 
    您还可以选择将“成功”和“失败”与在客户端尝试连接时身份验证过程完成后调用的函数一起传递。现在可以在套接字对象上以socket.request.user访问用户对象。例如,现在您可以添加以下内容: console.log('user ' + socket.request.user.name + ' connected');它将登录已连接的服务器控制台!当您认为自己已经做对时,请提交您的页面。如果您遇到错误,可以在此处查看项目。
    ## Instructions -
    - +
    ## Tests @@ -38,12 +23,12 @@ io.use(passportSocketIo.authorize({ ```yml tests: - - text: 应添加 passportSocketIo 作为依赖。 + - text: passportSocketIo是一个依赖项 testString: getUserInput => $.get(getUserInput('url')+ '/_api/package.json') .then(data => { var packJson = JSON.parse(data); assert.property(packJson.dependencies, 'passport.socketio', 'Your project should list "passport.socketio" as a dependency'); }, xhr => { throw new Error(xhr.statusText); }) - - text: 应正确引入 passportSocketIo 并实例化。 + - text: passportSocketIo是正确需要的 testString: getUserInput => $.get(getUserInput('url')+ '/_api/server.js').then(data => { assert.match(data, /require\((['"])passport\.socketio\1\)/gi, 'You should correctly require and instantiate "passport.socketio"');}, xhr => { throw new Error(xhr.statusText); }) - - text: 应正确配置 passportSocketIo。 - testString: getUserInput => $.get(getUserInput('url')+ '/_api/server.js') .then(data => { assert.match(data, /io\.use\(\s*\w+\.authorize\(/, 'You should register "passport.socketio" as socket.io middleware and provide it correct options'); }, xhr => { throw new Error(xhr.statusText); }) + - text: passportSocketIo已正确设置 + testString: getUserInput => $.get(getUserInput('url')+ '/_api/server.js') .then(data => { assert.match(data, /io\.use\(.+\.authorize\(/gi, 'You should register "passport.socketio" as socket.io middleware and provide it correct options'); }, xhr => { throw new Error(xhr.statusText); }) ``` @@ -58,11 +43,6 @@ tests:
    ```js -/** - Backend challenges don't need solutions, - because they would need to be tested against a full working project. - Please check our contributing guidelines to learn more. -*/ +// solution required ``` -
    diff --git a/curriculum/challenges/chinese/06-information-security-and-quality-assurance/advanced-node-and-express/clean-up-your-project-with-modules.chinese.md b/curriculum/challenges/chinese/06-information-security-and-quality-assurance/advanced-node-and-express/clean-up-your-project-with-modules.chinese.md index 8d977ce787f..65d0dbaf7b8 100644 --- a/curriculum/challenges/chinese/06-information-security-and-quality-assurance/advanced-node-and-express/clean-up-your-project-with-modules.chinese.md +++ b/curriculum/challenges/chinese/06-information-security-and-quality-assurance/advanced-node-and-express/clean-up-your-project-with-modules.chinese.md @@ -2,35 +2,16 @@ id: 589690e6f9fc0f352b528e6e title: Clean Up Your Project with Modules challengeType: 2 -isHidden: false -forumTopicId: 301549 +videoUrl: '' localeTitle: 使用模块清理项目 --- ## Description -
    -注意,本项目在这个 Glitch 项目的基础上进行开发,你也可以从 GitHub 上克隆。 -目前,我们把所有的代码都放到了 server.js 文件里,这会导致代码难以维护,且扩展性差。 -现在让我们来创建两个新文件:routes.js 和 auth.js。 -在每个文件的开头,我们都需要写上这段代码: - -```js -module.exports = function (app, db) { - -} -``` - -然后,在 server.js 文件的开头,我们需要像这样引入文件:const routes = require('./routes.js'); -在成功连接数据库之后,我们需要像这样进行实例化:routes(app, db)。 -最后,我们需要把所有路由相关的代码从 server.js 移动到新文件 routes.js。不要忘了,ensureAuthenticated方法的定义也要移动到新文件中,这个是我们在之前的挑战中,为在路由中判断用户是否已登录创建的函数。然后,我们还需要在 routes.js 文件开头添加所需要的依赖,如:const passport = require('passport');。 -如果在这些步骤后没有报错,那么恭喜你,你已成功地从 server.js 文件中分离出了路由文件。 -现在,我们来把 server.js 中与验证相关的代码分离到 auth.js 中,例如序列化,设置验证策略等。请正确添加依赖,并在 server.js 中调用auth(app,db)。另外,由于我们的注册路由依赖 passport,所以我们需要先调用auth(app, db),再调用routes(app, db)。 -Node 和 Express 高级课程至此就告一段落了,你可以在此基础上继续优化和完善这个项目。但至少,现在你也有一些可以展示给大家看的代码了。完成上述要求后,你就可以在左边提交你的页面链接。如果运行出错,你可以在 here 这里检查你的项目完成情况。 -
    +
    提醒一下,这个项目是基于Glitch的以下入门项目构建的,或者是从GitHub克隆的。现在你拥有的一切都在你的server.js文件中。这可能导致难以管理不易扩展的代码。创建2个新文件:Routes.js和Auth.js两者都应该从以下代码开始:
     module.exports = function(app,db){
    +

    }

    现在位于服务器文件的顶部,需要这样的文件: const routes = require('./routes.js');在您与数据库建立成功连接之后,实例化它们中的每一个如下: routes(app, db)最后,获取服务器中的所有路由并将它们粘贴到新文件中并从服务器文件中删除它们。也可以使用ensureAuthenticated,因为我们专门为路由创建了中间件功能。您现在必须正确添加所使用的依赖项,例如const passport = require('passport'); ,在routes.js文件中导出行的最上方。继续添加它们直到不再存在错误,并且您的服务器文件不再有任何路由!现在在auth.js文件中执行相同的操作,其中包含与身份验证相关的所有内容,例如序列化和本地策略的设置,并从服务器文件中删除它们。确保添加依赖项并在同一位置调用服务器中的auth(app,db) 。确保routes(app, db) auth(app, db)之前有auth(app, db) routes(app, db)因为我们的注册路由取决于发起的护照!恭喜 - 您已经处于Advanced Node和Express的这一部分的末尾,并且有一些漂亮的代码可供展示!当您认为自己已经做对时,请提交您的页面。如果您遇到错误,可以在此处查看已完成项目的示例。

    ## Instructions -
    - +
    ## Tests @@ -38,7 +19,7 @@ Node 和 Express 高级课程至此就告一段落了,你可以在此基础上 ```yml tests: - - text: 应正确引入新文件。 + - text: 存在的模块 testString: getUserInput => $.get(getUserInput('url')+ '/_api/server.js') .then(data => { assert.match(data, /require\s*\(('|")\.\/routes(\.js)?\1\)/gi, 'You should have required your new files'); assert.match(data, /mongo.connect[^]*routes/gi, 'Your new modules should be called after your connection to the database'); }, xhr => { throw new Error(xhr.statusText); }) ``` @@ -54,11 +35,6 @@ tests:
    ```js -/** - Backend challenges don't need solutions, - because they would need to be tested against a full working project. - Please check our contributing guidelines to learn more. -*/ +// solution required ``` -
    diff --git a/curriculum/challenges/chinese/06-information-security-and-quality-assurance/advanced-node-and-express/communicate-by-emitting.chinese.md b/curriculum/challenges/chinese/06-information-security-and-quality-assurance/advanced-node-and-express/communicate-by-emitting.chinese.md index b3a23f91fb2..31b20d124bb 100644 --- a/curriculum/challenges/chinese/06-information-security-and-quality-assurance/advanced-node-and-express/communicate-by-emitting.chinese.md +++ b/curriculum/challenges/chinese/06-information-security-and-quality-assurance/advanced-node-and-express/communicate-by-emitting.chinese.md @@ -2,33 +2,17 @@ id: 589fc831f9fc0f352b528e75 title: Communicate by Emitting challengeType: 2 -isHidden: false -forumTopicId: 301550 -localeTitle: 通过 Emitting 通信 +videoUrl: '' +localeTitle: 通过发射进行沟通 --- ## Description -
    -注意,本项目在这个 Glitch 项目的基础上进行开发,你也可以从 GitHub 上克隆。 -Emit 是你会用到的,最常见的通信方式。如果我们从服务器发送信息给 'io',就相当于把事件的名称和数据发送给了所有处于连接状态的 socket。我们可以利用这个特性实现这样的功能:只要有新用户连接到服务器,我们就可以把目前连接的总用户数发给所有已连接的用户,这样所有用户随时都可以看到实时的在线人数。 -
    首先,我们需要在监听连接的地方之前添加一个用于追踪用户数的变量:var currentUsers = 0; -然后,只要有人连接到服务器,我们需要在发出用户数量之前先给这个变量加 1:++currentUsers; -最后,在监听连接的地方发出(emit)该事件即可。这个事件应命名为 'user count',且数据应该为 'currentUsers':io.emit('user count', currentUsers); -
    接下来,我们还需要让客户端监听从服务端发出的事件。为此,我们还是需要用到 on 这个方法: - -```js -socket.on('user count', function(data){ - console.log(data); -}); -``` - -现在你可以尝试启动你的 app 并登录,你会看到在客户端的控制台打印出了 1,这就表示目前连接到服务器的用户数为 1。你可以试着通过打开多个 app 来验证数量是否会增加。 -完成上述要求后,你就可以在左边提交你的页面链接。 -
    +
    提醒一下,这个项目是基于Glitch的以下入门项目构建的,或者是从GitHub克隆的。 Emit是您将使用的最常见的沟通方式。当您从服务器向'io'发送内容时,会将事件的名称和数据发送到所有连接的套接字。这个概念的一个很好的例子就是每次新用户连接时都会发出连接用户的当前数量!
    首先添加一个变量,以便在您当前正在侦听连接之前跟踪用户。 var currentUsers = 0;现在当有人连接时,你应该在发出计数之前递增计数,这样你就可以在连接监听器中添加增量器。 ++currentUsers;最后,在递增计数后,您应该发出事件(仍在连接侦听器中)。该事件应命名为“用户计数”,数据应该只是'currentUsers'。 io.emit('user count', currentUsers);
    现在,您可以为客户实施一种方式来监听此事件!与在服务器上侦听连接类似,您将使用on关键字。
     socket.on('user count',function(data){
    +  的console.log(数据);
    +}); 
    现在尝试加载您的应用并进行身份验证,您应该在客户端控制台中看到“1”代表当前用户数!尝试加载更多客户端并进行身份验证以查看数量是否上升。当您认为自己已经做对时,请提交您的页面。
    ## Instructions -
    - +
    ## Tests @@ -36,11 +20,11 @@ socket.on('user count', function(data){ ```yml tests: - - text: 应定义 currentUsers + - text: currentUsers已定义 testString: getUserInput => $.get(getUserInput('url')+ '/_api/server.js').then(data => {assert.match(data, /currentUsers/gi, 'You should have variable currentUsers defined');}, xhr => { throw new Error(xhr.statusText); }) - - text: 服务器应在有新的连接时 emit 当前用户数量。 + - text: 服务器在每个新连接上发出当前用户计数 testString: getUserInput => $.get(getUserInput('url')+ '/_api/server.js') .then(data => { assert.match(data, /io.emit.*('|")user count('|").*currentUsers/gi, 'You should emit "user count" with data currentUsers'); }, xhr => { throw new Error(xhr.statusText); }) - - text: '客户端应监听 "user count" 事件。' + - text: 您的客户正在侦听“用户计数”事件 testString: getUserInput => $.get(getUserInput('url')+ '/public/client.js') .then(data => { assert.match(data, /socket.on.*('|")user count('|")/gi, 'Your client should be connection to server with the connection defined as socket'); }, xhr => { throw new Error(xhr.statusText); }) ``` @@ -56,11 +40,6 @@ tests:
    ```js -/** - Backend challenges don't need solutions, - because they would need to be tested against a full working project. - Please check our contributing guidelines to learn more. -*/ +// solution required ``` -
    diff --git a/curriculum/challenges/chinese/06-information-security-and-quality-assurance/advanced-node-and-express/create-new-middleware.chinese.md b/curriculum/challenges/chinese/06-information-security-and-quality-assurance/advanced-node-and-express/create-new-middleware.chinese.md index 469a4293583..4454fe53c01 100644 --- a/curriculum/challenges/chinese/06-information-security-and-quality-assurance/advanced-node-and-express/create-new-middleware.chinese.md +++ b/curriculum/challenges/chinese/06-information-security-and-quality-assurance/advanced-node-and-express/create-new-middleware.chinese.md @@ -2,42 +2,23 @@ id: 5895f70df9fc0f352b528e6a title: Create New Middleware challengeType: 2 -isHidden: false -forumTopicId: 301551 +videoUrl: '' localeTitle: 创建新的中间件 --- ## Description -
    -注意,本项目在这个 Glitch 项目的基础上进行开发,你也可以从 GitHub 上克隆。 -无论是否登录,或者哪怕用户试图访问其他页面,目前都会跳转到/profile。为了解决这个问题,我们需要在 profile 页面渲染之前进行用户验证,创建中间件就可以实现这个功能。 -这个挑战的目标是创建ensureAuthenticated(req, res, next)中间件方法,通过在 request 上调用 passports 的isAuthenticated方法,我们可以检查 req.user 是否定义,从而确定用户是否通过认证。如果用户已通过验证,就会调用 next(),否则我们应重定向到主页并让用户登录。该中间件的实现是: - -```js -function ensureAuthenticated(req, res, next) { - if (req.isAuthenticated()) { - return next(); +
    提醒一下,这个项目是基于Glitch的以下入门项目构建的,或者是从GitHub克隆的。同样,任何用户都可以通过输入网址来查看/配置他们是否通过身份验证。我们希望通过在呈现配置文件页面之前检查用户是否首先进行身份验证来防止这种情况。这是何时创建中间件的完美示例。这里的挑战是创建中间件功能ensureAuthenticated(req, res, next) ,它将检查用户是否通过调用护照进行身份验证isAuthenticated对请求进行检查,然后检查req.user是否定义。如果是,那么应该调用next() ,否则我们只需通过重定向到我们的主页来回复请求即可登录。该中间件的实现是:
     function ensureAuthenticated(req,res,next){
    +  if(req.isAuthenticated()){
    +      return next();
       }
    -  res.redirect('/');
    -};
    -```
    -
    -然后,我们需要把 ensureAuthenticated 中间件添加到处理请求的回调之前:
    -
    -```js
    -app
    - .route('/profile')
    - .get(ensureAuthenticated, (req,res) => {
    -    res.render(process.cwd() + '/views/pug/profile');
    - });
    -```
    -
    -完成上述要求后,你就可以在左边提交你的页面链接。
    -
    + res.redirect( '/'); +}; 现在,在包含呈现页面的函数的get请求的参数之前,将ensureAuthenticated作为中间件添加到配置文件页面的请求中。
     app.route( '/简档')
    +  .get(ensureAuthenticated,(req,res)=> {
    +       res.render(process.cwd()+'/ views / pug / profile');
    +  }); 
    当您认为自己已经做对时,请提交您的页面。
    ## Instructions -
    - +
    ## Tests @@ -45,9 +26,9 @@ app ```yml tests: - - text: ensureAuthenticated中间件应添加到/profile路由中。 + - text: 中间件确保应该在我们的/配置文件路由上实现 testString: getUserInput => $.get(getUserInput('url')+ '/_api/server.js') .then(data => { assert.match(data, /ensureAuthenticated[^]*req.isAuthenticated/gi, 'Your ensureAuthenticated middleware should be defined and utilize the req.isAuthenticated function'); assert.match(data, /profile[^]*get[^]*ensureAuthenticated/gi, 'Your ensureAuthenticated middleware should be attached to the /profile route'); }, xhr => { throw new Error(xhr.statusText); }) - - text: 如果没有通过验证,对 /profile 的 GET 请求应重定向到 / + - text: 正确的Get请求/配置文件重定向到/因为我们未经过身份验证 testString: getUserInput => $.get(getUserInput('url')+ '/profile') .then(data => { assert.match(data, /Home page/gi, 'An attempt to go to the profile at this point should redirect to the homepage since we are not logged in'); }, xhr => { throw new Error(xhr.statusText); }) ``` @@ -63,11 +44,6 @@ tests:
    ```js -/** - Backend challenges don't need solutions, - because they would need to be tested against a full working project. - Please check our contributing guidelines to learn more. -*/ +// solution required ``` -
    diff --git a/curriculum/challenges/chinese/06-information-security-and-quality-assurance/advanced-node-and-express/handle-a-disconnect.chinese.md b/curriculum/challenges/chinese/06-information-security-and-quality-assurance/advanced-node-and-express/handle-a-disconnect.chinese.md index 1ad8ffed138..848e6de9282 100644 --- a/curriculum/challenges/chinese/06-information-security-and-quality-assurance/advanced-node-and-express/handle-a-disconnect.chinese.md +++ b/curriculum/challenges/chinese/06-information-security-and-quality-assurance/advanced-node-and-express/handle-a-disconnect.chinese.md @@ -2,24 +2,15 @@ id: 589fc831f9fc0f352b528e76 title: Handle a Disconnect challengeType: 2 -isHidden: false -forumTopicId: 301552 -localeTitle: 处理连接断开 +videoUrl: '' +localeTitle: 处理断开连接 --- ## Description -
    -注意,本项目在这个 Glitch 项目的基础上进行开发,你也可以从 GitHub 上克隆。 -你也许注意到,目前为止我们只处理用户数量的增加,没有处理减少。事实上,处理用户断开连接也很简单。区别在于,新连接的监听是发生在整个服务器上,但连接断开的监听是发生在每个 socket 上。 -
    为此,我们需要在目前的监听回调里面监听 socket 断开连接的事件。在断开连接的回调函数中,我们可以不传任何参数,但你可以在这里添加连接断开的测试代码:socket.on('disconnect', () => { /* 在这里添加连接断开的测试代码 */ }); -为确保客户端可以看到实时的用户数量,显然,我们应该在用户断开时让 currentUsers 减 1,然后发送 'user count' 事件,并使用修改后的用户数量。 -注意:
    和 'disconnect' 类似,所有 socket 可以发送到服务器的事件,我们都应该在有 'socket' 定义的连接监听器里处理。 -完成上述要求后,你就可以在左边提交你的页面链接。 -
    +
    提醒一下,这个项目是基于Glitch的以下入门项目构建的,或者是从GitHub克隆的。您可能会注意到,到目前为止,您只增加了用户数。处理用户断开连接就像处理初始连接一样简单,除了区别在于你必须在每个套接字上监听它而不是在整个服务器上监听它。
    为此,请在现有的连接侦听器中添加一个侦听器,该侦听器在没有数据传递的情况下侦听套接字上的“disconnect”。您只需登录用户已断开连接的控制台即可测试此功能。 socket.on('disconnect', () => { /*anything you want to do on disconnect*/ });要确保客户端持续获得当前用户的更新计数,您应该在断开连接时将currentUsers减少1,然后使用更新的计数发出'user count'事件! 注意
    就像'disconnect'一样,套接字可以向服务器发出的所有其他事件应该在我们定义了'socket'的连接监听器中处理。当您认为自己已经做对时,请提交您的页面。
    ## Instructions -
    - +
    ## Tests @@ -27,9 +18,9 @@ localeTitle: 处理连接断开 ```yml tests: - - text: 服务器应处理断开 socket 连接的事件。 + - text: 服务器处理与套接字的事件断开连接 testString: getUserInput => $.get(getUserInput('url')+ '/_api/server.js') .then(data => { assert.match(data, /socket.on.*('|")disconnect('|")/gi, ''); }, xhr => { throw new Error(xhr.statusText); }) - - text: '客户端应监听 "user count" 事件。' + - text: 您的客户正在侦听“用户计数”事件 testString: getUserInput => $.get(getUserInput('url')+ '/public/client.js') .then(data => { assert.match(data, /socket.on.*('|")user count('|")/gi, 'Your client should be connection to server with the connection defined as socket'); }, xhr => { throw new Error(xhr.statusText); }) ``` @@ -45,11 +36,6 @@ tests:
    ```js -/** - Backend challenges don't need solutions, - because they would need to be tested against a full working project. - Please check our contributing guidelines to learn more. -*/ +// solution required ``` -
    diff --git a/curriculum/challenges/chinese/06-information-security-and-quality-assurance/advanced-node-and-express/hashing-your-passwords.chinese.md b/curriculum/challenges/chinese/06-information-security-and-quality-assurance/advanced-node-and-express/hashing-your-passwords.chinese.md index cddf7287034..ffd6b09c213 100644 --- a/curriculum/challenges/chinese/06-information-security-and-quality-assurance/advanced-node-and-express/hashing-your-passwords.chinese.md +++ b/curriculum/challenges/chinese/06-information-security-and-quality-assurance/advanced-node-and-express/hashing-your-passwords.chinese.md @@ -2,24 +2,15 @@ id: 58a25c98f9fc0f352b528e7f title: Hashing Your Passwords challengeType: 2 -isHidden: false -forumTopicId: 301553 +videoUrl: '' localeTitle: 哈希密码 --- ## Description -
    -注意,本项目在这个 Glitch 项目的基础上进行开发,你也可以从 GitHub 上克隆。 -回过头来看信息安全,你也许记得在数据库中存储明文密码是绝对禁止的。现在,我们需要引入 BCrypt 来解决这个问题。 -
    添加 BCrypt 作为依赖,并通过require添加到服务器代码中。你需要在两个步骤中使用哈希运算:注册和保存新账户,以及登录时检查密码是否正确。 -目前处理注册的路由中,我们是这样把密码添加到数据库的:password: req.body.password。我们可以通过这段代码创建哈希值:var hash = bcrypt.hashSync(req.body.password, 12);,然后就可以把passsword: req.body.password替换为password: hash。 -最后,在验证逻辑中,我们已经有这样一段代码执行检查:if (password !== user.password) { return done(null, false); }。但我们现在存储的密码user.password已经是哈希值了。由于目前的检测机制是密码不匹配时就返回未认证,因此修改后,用于比对用户密码哈希值的代码应该是这样:if (!bcrypt.compareSync(password, user.password)) { return done(null, false); }。 -当你需要存储密码时,这样做可以有效地提升网站的安全性。完成上述要求后,你就可以在左边提交你的页面链接。 -
    +
    提醒一下,这个项目是基于Glitch的以下入门项目构建的,或者是从GitHub克隆的。回到信息安全部分,您​​可能还记得存储明文密码永远不会好。现在是时候实施BCrypt来解决这个问题了。
    将BCrypt添加为依赖项并在服务器中将其需要。您需要在两个关键区域处理散列:您在哪里处理注册/保存新帐户以及在登录时检查密码是否正确。目前在我们的注册路线上,您将用户的密码插入数据库,如下所示: password: req.body.password 。实现保存哈希的一种简单方法是在数据库逻辑var hash = bcrypt.hashSync(req.body.password, 12);之前添加以下内容var hash = bcrypt.hashSync(req.body.password, 12);并使用password: hash替换数据库保存中的req.body.password 。最后在我们的身份验证策略中,我们在完成流程之前在代码中检查以下内容: if (password !== user.password) { return done(null, false); } 。完成之前的更改后,现在user.password是一个哈希。在更改现有代码之前,请注意语句如何检查密码是否不相等,然后返回未经过身份验证的密码。考虑到这一点,您的代码可能如下所示,以正确检查针对哈希输入的密码: if (!bcrypt.compareSync(password, user.password)) { return done(null, false); }这是所有需要实现的最重要的安全功能之一,当你有来存储密码!当您认为自己已经做对时,请提交您的页面。
    ## Instructions -
    - +
    ## Tests @@ -27,9 +18,9 @@ localeTitle: 哈希密码 ```yml tests: - - text: 应存在 BCrypt 依赖。 + - text: BCrypt是一种依赖 testString: getUserInput => $.get(getUserInput('url')+ '/_api/package.json') .then(data => { var packJson = JSON.parse(data); assert.property(packJson.dependencies, 'bcrypt', 'Your project should list "bcrypt" as a dependency'); }, xhr => { throw new Error(xhr.statusText); }) - - text: BCrypt 应正确地引入和调用。 + - text: BCrypt正确需要并实施 testString: getUserInput => $.get(getUserInput('url')+ '/_api/server.js') .then(data => { assert.match(data, /require.*("|')bcrypt("|')/gi, 'You should have required bcrypt'); assert.match(data, /bcrypt.hashSync/gi, 'You should use hash the password in the registration'); assert.match(data, /bcrypt.compareSync/gi, 'You should compare the password to the hash in your strategy'); }, xhr => { throw new Error(xhr.statusText); }) ``` @@ -45,11 +36,6 @@ tests:
    ```js -/** - Backend challenges don't need solutions, - because they would need to be tested against a full working project. - Please check our contributing guidelines to learn more. -*/ +// solution required ``` -
    diff --git a/curriculum/challenges/chinese/06-information-security-and-quality-assurance/advanced-node-and-express/how-to-put-a-profile-together.chinese.md b/curriculum/challenges/chinese/06-information-security-and-quality-assurance/advanced-node-and-express/how-to-put-a-profile-together.chinese.md index a227ca142c6..eafe0c87c2b 100644 --- a/curriculum/challenges/chinese/06-information-security-and-quality-assurance/advanced-node-and-express/how-to-put-a-profile-together.chinese.md +++ b/curriculum/challenges/chinese/06-information-security-and-quality-assurance/advanced-node-and-express/how-to-put-a-profile-together.chinese.md @@ -2,23 +2,15 @@ id: 5895f70ef9fc0f352b528e6b title: How to Put a Profile Together challengeType: 2 -isHidden: false -forumTopicId: 301554 -localeTitle: 如何将 Profile 放在一起 +videoUrl: '' +localeTitle: 如何将配置文件放在一起 --- ## Description -
    -注意,本项目在这个 Glitch 项目的基础上进行开发,你也可以从 GitHub 上克隆。 -现在,只有通过验证的用户才能进入 /profile 页面,这样我们就可以在页面上使用 'req.user' 里的信息了。 -请在变量中包含 username 键,值为 'req.user.username',并通过 render 方法传给 profile 页面。然后在 'profile.pug' 页面,添加这行h2.center#welcome Welcome, #{username}!代码来创建类为center、id 为welcome且文本内容为 'Welcome, ' 后加用户名的 h2 元素。 -以及,请在 profile 里添加 /logout 链接,后续会用于处理用户退出登录的逻辑:a(href='/logout') Logout -完成上述要求后,你就可以在左边提交你的页面链接。 -
    +
    提醒一下,这个项目是基于Glitch的以下入门项目构建的,或者是从GitHub克隆的。现在我们可以确保访问/ profile的用户已经过身份验证,我们可以使用页面上“req.user”中包含的信息!继续将包含变量username equaling'req.user.username'的对象传递到配置文件视图的render方法中。然后转到你的'profile.pug'视图并添加第h2.center#welcome Welcome, #{username}!h2.center#welcome Welcome, #{username}!使用“center”类创建h2元素,并使用包含文本“Welcome”和用户名的id“welcome”创建!同样在配置文件中,添加指向/ logout的链接。该路由将托管用于取消身份验证用户的逻辑。 a(href='/logout') Logout当您认为自己正确时,请提交您的页面。
    ## Instructions -
    - +
    ## Tests @@ -26,7 +18,7 @@ localeTitle: 如何将 Profile 放在一起 ```yml tests: - - text: 应在 Pug render 中给 /profile 传一个变量。 + - text: 正确地将Pug渲染变量添加到/ profile testString: getUserInput => $.get(getUserInput('url')+ '/_api/server.js') .then(data => { assert.match(data, /\/views\/pug\/profile[^]*username:( |)req.user.username/gi, 'You should be passing the variable username with req.user.username into the render function of the profile page'); }, xhr => { throw new Error(xhr.statusText); }) ``` @@ -42,11 +34,6 @@ tests:
    ```js -/** - Backend challenges don't need solutions, - because they would need to be tested against a full working project. - Please check our contributing guidelines to learn more. -*/ +// solution required ``` -
    diff --git a/curriculum/challenges/chinese/06-information-security-and-quality-assurance/advanced-node-and-express/how-to-use-passport-strategies.chinese.md b/curriculum/challenges/chinese/06-information-security-and-quality-assurance/advanced-node-and-express/how-to-use-passport-strategies.chinese.md index 306046b9c47..a05faf1a169 100644 --- a/curriculum/challenges/chinese/06-information-security-and-quality-assurance/advanced-node-and-express/how-to-use-passport-strategies.chinese.md +++ b/curriculum/challenges/chinese/06-information-security-and-quality-assurance/advanced-node-and-express/how-to-use-passport-strategies.chinese.md @@ -2,25 +2,15 @@ id: 5895f70df9fc0f352b528e69 title: How to Use Passport Strategies challengeType: 2 -isHidden: false -forumTopicId: 301555 -localeTitle: 如何使用 Passport 策略 +videoUrl: '' +localeTitle: 如何使用Passport策略 --- ## Description -
    -注意,本项目在这个 Glitch 项目的基础上进行开发,你也可以从 GitHub 上克隆。 -在提供的 index.pug 文件里有一个登录表单。因为这个表单中存在行内 JavaScript 代码if showLogin,因此它是隐藏的。因为 showLogin 未定义,所以表单不会渲染。如果在该页面的res.render()里添加一个包含showLogin: true的对象,你就可以在刷新页面后看到表单。当你点击 login 时,表单会向服务器的 /login 发送 POST 请求,此时服务器端就可以接受 POST 请求信息并进行用户验证。 -在这次挑战中,你需要为 POST 请求添加路由/login。为了用这个路由进行验证,你需要添加一个中间件,中间件应作为参数添加到用于处理请求的回调函数function(req,res)之前。对于 passport 的验证中间件,应这样调用:passport.authenticate('local')。 -passport.authenticate 也接收选项作为参数,这些选项用于设置验证,例如{ failureRedirect: '/' }就很有用,请记得添加到你的代码中。如果中间件验证通过,我们就应该提供相应的后续处理。在这个挑战中,我们需要让用户重定到 /profile,这样profile.pug页面就会渲染。 -如果验证通过,用户对象将会储存到 req.user 中。 -这时,如果你在表单里输入了用户名和密码,路由将会重定向到主页 /,在服务端将会打印 'User {USERNAME} attempted to log in.',由于现在我们还没有实现注册功能,因此所有登录尝试都会失败。 -完成上述要求后,你就可以在左边提交你的页面链接。如果运行出错,你可以在这里检查你的项目完成情况。 -
    +
    提醒一下,这个项目是基于Glitch的以下入门项目构建的,或者是从GitHub克隆的。在提供的index.pug文件中,实际上有一个登录表单。它之前已被隐藏,因为内联javascript if showLogin的形式缩进后。在showLogin作为变量从未定义之前,它从未呈现包含该表单的代码块。继续在该页面的res.render上向对象showLogin: true添加一个新变量。刷新页面时,您应该看到表单!此表单设置为POST on / login,因此我们应该设置此接受POST并验证用户身份。对于此挑战,您应添加路由/登录以接受POST请求。要在此路由上进行身份验证,您需要添加中间件才能发送响应。这是通过在您的function(req,res)之前使用中间件传递另一个参数来完成的!要使用的中间件是passport.authenticate('local')passport.authenticate也可以将一些选项作为参数,例如: { failureRedirect: '/' }这非常有用,所以一定要添加它。作为使用中间件后的响应(只有在身份验证中间件通过时才会调用)应该是将用户重定向到/ profile,并且该路由应该呈现视图'profile.pug'。如果身份验证成功,则用户对象将保存在req.user中 。现在,如果您在表单中输入用户名和密码,它应该重定向到主页/并且在服务器的控制台中应该是'用户{USERNAME}尝试登录'。因为我们目前无法登录未注册的用户。当您认为自己已经做对时,请提交您的页面。如果您遇到错误,可以在这里查看到目前为止完成的项目。
    ## Instructions -
    - +
    ## Tests @@ -28,9 +18,9 @@ localeTitle: 如何使用 Passport 策略 ```yml tests: - - text: server.js 中应正确执行所有步骤。 + - text: 所有步骤都在server.js中正确实现 testString: getUserInput => $.get(getUserInput('url')+ '/_api/server.js') .then(data => { assert.match(data, /showLogin:( |)true/gi, 'You should be passing the variable "showLogin" as true to your render function for the homepage'); assert.match(data, /failureRedirect:( |)('|")\/('|")/gi, 'Your code should include a failureRedirect to the "/" route'); assert.match(data, /login[^]*post[^]*local/gi, 'You should have a route for login which accepts a POST and passport.authenticates local'); }, xhr => { throw new Error(xhr.statusText); }) - - text: 到 /login 的 POST 请求应重定向到 / + - text: 对/ login的POST请求正确重定向到/ testString: getUserInput => $.post(getUserInput('url')+ '/login') .then(data => { assert.match(data, /Looks like this page is being rendered from Pug into HTML!/gi, 'A login attempt at this point should redirect to the homepage since we do not have any registered users'); }, xhr => { throw new Error(xhr.statusText); }) ``` @@ -46,11 +36,6 @@ tests:
    ```js -/** - Backend challenges don't need solutions, - because they would need to be tested against a full working project. - Please check our contributing guidelines to learn more. -*/ +// solution required ``` -
    diff --git a/curriculum/challenges/chinese/06-information-security-and-quality-assurance/advanced-node-and-express/implement-the-serialization-of-a-passport-user.chinese.md b/curriculum/challenges/chinese/06-information-security-and-quality-assurance/advanced-node-and-express/implement-the-serialization-of-a-passport-user.chinese.md index f3ccb68c23e..d9465fef927 100644 --- a/curriculum/challenges/chinese/06-information-security-and-quality-assurance/advanced-node-and-express/implement-the-serialization-of-a-passport-user.chinese.md +++ b/curriculum/challenges/chinese/06-information-security-and-quality-assurance/advanced-node-and-express/implement-the-serialization-of-a-passport-user.chinese.md @@ -2,37 +2,21 @@ id: 5895f70cf9fc0f352b528e67 title: Implement the Serialization of a Passport User challengeType: 2 -isHidden: false -forumTopicId: 301556 -localeTitle: 实现 Passport 用户的序列化 +videoUrl: '' +localeTitle: 实现Passport用户的序列化 --- ## Description -
    -注意,本项目在这个 Glitch 项目的基础上进行开发,你也可以从 GitHub 上克隆。 -截至目前,我们还没有配置完数据库,因此还无法加载用户数据。实现这个的方式很多,但对于我们的项目,一旦服务器启动,那么只要有 app 实例在运行,数据库就应一直处于连接状态。 -为此,我们要添加 MongoDB 作为依赖,并在 server 中require它,就像这样:const mongo = require('mongodb').MongoClient;。 -在连接数据库之后,我们才能让服务器开始监听请求,这样做可以保证服务器在数据库连接前或数据库发生错误时不接受任何请求。为此,我们需要这样写: - -```js -mongo.connect(process.env.DATABASE, (err, db) => { - if(err) { - console.log('Database error: ' + err); - } else { - console.log('Successful database connection'); - - //serialization and app.listen - } -}); -``` - -现在,请把上一个挑战中我们注释掉的deserializeUser中的代码块添加回来,然后删掉done(null, null)。请确保你已经在 .env 文件里配置了DATABASE的数据库连接字段,例如:DATABASE=mongodb://admin:pass@mlab.com:12345/my-project。你可以在 mLab 上创建一个免费的数据库。至此,序列化的创建完成。 -完成上述要求后,你就可以在左边提交你的页面链接。如果运行出错,你可以在这里检查你的项目完成情况。 -
    +
    提醒一下,这个项目是基于Glitch的以下入门项目构建的,或者是从GitHub克隆的。现在我们没有加载实际的用户对象,因为我们还没有设置我们的数据库。这可以通过许多不同的方式完成,但是对于我们的项目,当我们启动服务器并在应用程序的整个生命周期中保持持久连接时,我们将连接到数据库。为此,请将MongoDB添加为依赖项,并在服务器中将其需要。 ( const mongo = require('mongodb').MongoClient; )现在我们想要连接到我们的数据库,然后开始侦听请求。这样做的目的是在连接数据库之前或者出现数据库错误时不允许请求。要实现此目的,您需要在以下内容中包含序列化和应用程序侦听器:
     mongo.connect(process.env.DATABASE,(err,db)=> {
    +    if(错误){
    +        console.log('数据库错误:'+错误);
    +    } else {
    +        console.log('成功的数据库连接');
    +
      //serialization and app.listen 
    +

    }});

    您现在可以在deserializeUser中取消注释该块并删除您的done(null, null) 。确保将.env文件中的DATABASE设置为数据库的连接字符串(例如: DATABASE=mongodb://admin:pass@mlab.com:12345/my-project )。您可以在mLab上设置免费数据库。恭喜 - 您已完成序列化设置!当您认为自己已经做对时,请提交您的页面。如果您遇到错误,可以在这里查看到目前为止完成的项目。

    ## Instructions -
    - +
    ## Tests @@ -40,9 +24,9 @@ mongo.connect(process.env.DATABASE, (err, db) => { ```yml tests: - - text: 应存在数据库连接。 + - text: 存在数据库连接 testString: getUserInput => $.get(getUserInput('url')+ '/_api/server.js') .then(data => { assert.match(data, /mongo.connect/gi, 'You should have created a connection to your database'); assert.match(data, /mongo.connect[^]*app.listen[^]*}[^]*}/gi, 'You should have your app.listen nested at within your database connection at the bottom'); }, xhr => { throw new Error(xhr.statusText); }) - - text: 反序列化应正确使用,且应移除done(null, null)。 + - text: 反序列化现在正确使用DB并且擦除了done(null, null) testString: getUserInput => $.get(getUserInput('url')+ '/_api/server.js') .then(data => { assert.notMatch(data, /null,( |)null/gi, 'The callback in deserializeUser of (null, null) should be completely removed for the db block uncommented out'); }, xhr => { throw new Error(xhr.statusText); }) ``` @@ -58,11 +42,6 @@ tests:
    ```js -/** - Backend challenges don't need solutions, - because they would need to be tested against a full working project. - Please check our contributing guidelines to learn more. -*/ +// solution required ``` -
    diff --git a/curriculum/challenges/chinese/06-information-security-and-quality-assurance/advanced-node-and-express/implementation-of-social-authentication-ii.chinese.md b/curriculum/challenges/chinese/06-information-security-and-quality-assurance/advanced-node-and-express/implementation-of-social-authentication-ii.chinese.md index d273d518de9..5801fb5df80 100644 --- a/curriculum/challenges/chinese/06-information-security-and-quality-assurance/advanced-node-and-express/implementation-of-social-authentication-ii.chinese.md +++ b/curriculum/challenges/chinese/06-information-security-and-quality-assurance/advanced-node-and-express/implementation-of-social-authentication-ii.chinese.md @@ -2,37 +2,24 @@ id: 589a69f5f9fc0f352b528e71 title: Implementation of Social Authentication II challengeType: 2 -isHidden: false -forumTopicId: 301557 +videoUrl: '' +localeTitle: 社会认证的实施II --- ## Description -
    -注意,本项目在这个 Glitch 项目的基础上进行开发,你也可以从 GitHub 上克隆。 -设置 GitHub 验证的最后一步是创建策略本身。为此,你需要在项目中require'passport-github',且实例化为 GithubStrategy:const GitHubStrategy = require('passport-github').Strategy;。 -为了设置 GitHub 策略,我们需要在 passport 中使用实例化的 GithubStrategy,它可以接收两个参数:一个对象(包括 clientID, clientSecretcallbackURL),以及一个回调函数。在这个回调函数中,我们要处理验证成功时,判断用户是否已经在数据库中存在的逻辑,还有如果数据库中不存在,把用户数据添加到数据库的代码。这种处理方式适用于绝大部分第三方验证策略,但有些策略会需要我们提供更多的信息,详情请参考相关策略的 README。例如,Google 的验证策略会要求你提供一个 scope,用于标示用户成功登录后,你需要从返回的对象中获取那些信息。以及,这也需要经过用户同意,你才可以获取到。当前我们使用的验证策略,你也可以从它 GitHub 的页面上了解它的用法,不过我们也会在这里进行详细讲解。 -你的新策略应该这样去实现: - -```js -passport.use(new GitHubStrategy({ - clientID: process.env.GITHUB_CLIENT_ID, - clientSecret: process.env.GITHUB_CLIENT_SECRET, - callbackURL: /*INSERT CALLBACK URL ENTERED INTO GITHUB HERE*/ -}, - function(accessToken, refreshToken, profile, cb) { - console.log(profile); - //Database logic here with callback containing our user object +
    提醒一下,这个项目是基于Glitch的以下入门项目构建的,或者是从GitHub克隆的。设置Github身份验证的最后一部分是创建策略本身。为此,您需要将'passport-github'的依赖项添加到项目中,并将其作为GithubStrategy,例如const GitHubStrategy = require('passport-github').Strategy; 。要设置Github策略,你必须告诉护照 使用实例化的GithubStrategy ,它接受2个参数:一个对象(包含clientIDclientSecretcallbackURL )和一个在成功验证用户时要调用的函数,我们将确定如果用户是新用户以及最初要保存在用户数据库对象中的字段。这在许多策略中很常见,但有些可能需要更多信息,如特定策略的github README所述;例如,Google也需要一个范围来确定您的请求所返回的信息类型,并要求用户批准此类访问。我们正在实施的当前策略在此处列出它的用法,但我们将在freeCodeCamp上完成所有这些工作!以下是您的新战略应该如何看待这一点:
     passport.use(new GitHubStrategy({
    +    clientID:process.env.GITHUB_CLIENT_ID,
    +    clientSecret:process.env.GITHUB_CLIENT_SECRET,
    +    callbackURL:/ * INSERT CALLBACK URL在这里输入GITHUB * /
    +  },
    +  function(accessToken,refreshToken,profile,cb){
    +      的console.log(配置文件);
    +      //这里的数据库逻辑带有包含我们用户对象的回调
       }
    -));
    -```
    -
    -目前,你的验证部分不会成功。由于没有数据库的逻辑和回调函数,你的代码目前还会报错。但如果你试一试,就可以在右边的控制台里看到输出了你的 GitHub 的个人信息。
    -完成上述要求后,你就可以在左边提交你的页面链接。
    -
    +)); 您的身份验证还不会成功,并且实际上会抛出错误,没有数据库逻辑和回调,但如果您尝试它,它应该将您的Github配置文件记录到您的控制台!当您认为自己已经做对时,请提交您的页面。
    ## Instructions -
    - +
    ## Tests @@ -40,11 +27,11 @@ passport.use(new GitHubStrategy({ ```yml tests: - - text: 应添加依赖。 + - text: 依赖性增加了 testString: getUserInput => $.get(getUserInput('url')+ '/_api/package.json') .then(data => { var packJson = JSON.parse(data); assert.property(packJson.dependencies, 'passport-github', 'Your project should list "passport-github" as a dependency'); }, xhr => { throw new Error(xhr.statusText); }) - - text: 应引入依赖 + - text: 需要依赖性 testString: getUserInput => $.get(getUserInput('url')+ '/_api/server.js') .then(data => { assert.match(data, /require.*("|')passport-github("|')/gi, 'You should have required passport-github'); }, xhr => { throw new Error(xhr.statusText); }) - - text: 到目前为止,Github 策略应正确设置。 + - text: 到目前为止,Github策略设置正确 testString: getUserInput => $.get(getUserInput('url')+ '/_api/server.js') .then(data => { assert.match(data, /passport.use.*new GitHubStrategy/gi, 'Passport should use a new GitHubStrategy'); assert.match(data, /callbackURL:( |)("|').*("|')/gi, 'You should have a callbackURL'); assert.match(data, /process.env.GITHUB_CLIENT_SECRET/g, 'You should use process.env.GITHUB_CLIENT_SECRET'); assert.match(data, /process.env.GITHUB_CLIENT_ID/g, 'You should use process.env.GITHUB_CLIENT_ID'); }, xhr => { throw new Error(xhr.statusText); }) ``` @@ -60,11 +47,6 @@ tests:
    ```js -/** - Backend challenges don't need solutions, - because they would need to be tested against a full working project. - Please check our contributing guidelines to learn more. -*/ +// solution required ``` -
    diff --git a/curriculum/challenges/chinese/06-information-security-and-quality-assurance/advanced-node-and-express/implementation-of-social-authentication-iii.chinese.md b/curriculum/challenges/chinese/06-information-security-and-quality-assurance/advanced-node-and-express/implementation-of-social-authentication-iii.chinese.md index bdbc64f241b..41c5400d8e2 100644 --- a/curriculum/challenges/chinese/06-information-security-and-quality-assurance/advanced-node-and-express/implementation-of-social-authentication-iii.chinese.md +++ b/curriculum/challenges/chinese/06-information-security-and-quality-assurance/advanced-node-and-express/implementation-of-social-authentication-iii.chinese.md @@ -2,46 +2,34 @@ id: 589a8eb3f9fc0f352b528e72 title: Implementation of Social Authentication III challengeType: 2 -isHidden: false -forumTopicId: 301558 -localeTitle: 实现第三种社交登录 +videoUrl: '' +localeTitle: 社会认证的实施III --- ## Description -
    -注意,本项目在这个 Glitch 项目的基础上进行开发,你也可以从 GitHub 上克隆。 -验证策略的最后一部分是处理从 GitHub 返回的个人信息。如果用户存在,我们就需要从数据库中读取用户数据并在 profile 页面加载;否则,我们需要把用户信息添加到数据库。GitHub 在用户信息中为我们提供了独一无二的 id,我们可以通过序列化的 id 在数据库中搜索用户(已实现)。以下是这个逻辑的实现示例,我们应该把它传到新策略的第二个参数,就是目前console.log(profile);的下方: - -```js -db.collection('socialusers').findAndModify( - {id: profile.id}, - {}, - {$setOnInsert:{ - id: profile.id, - name: profile.displayName || 'John Doe', - photo: profile.photos[0].value || '', - email: profile.emails[0].value || 'No public email', - created_on: new Date(), - provider: profile.provider || '' - },$set:{ - last_login: new Date() - },$inc:{ - login_count: 1 - }}, - {upsert:true, new: true}, - (err, doc) => { - return cb(null, doc.value); - } -); -``` - -findAndModify的作用是在数据库中查询对象并更新,如果对象不存在,我们也可以upsert(注,upsert 可以理解为 update + insert)它,然后我们可以在回调方法里获取到插入数据后的新对象。在这个例子中,我们会把 last_login 设置成为 now,而且总会为 login_count 加 1。只有在插入一个新对象(新用户)时,我们才会初始化这些字段。另外,还需要注意默认值的使用。有时返回的用户信息可能不全,可能是因为用户没有填写,也可能是因为用户选择不公开一部分信息。在这种情况下,我们需要进行相应的处理,以防我们的 app 报错。 -你现在应该可以登录你的应用了,试试吧。完成上述要求后,你就可以在左边提交你的页面链接。如果运行出错,你可以在 here 这里检查这个迷你项目的完成代码。 -
    +
    提醒一下,这个项目是基于Glitch的以下入门项目构建的,或者是从GitHub克隆的。策略的最后一部分是处理从Github返回的配置文件。我们需要加载用户数据库对象(如果存在)或创建一个(如果不存在)并填充配置文件中的字段,然后返回用户的对象。 Github在每个配置文件中为我们提供了一个唯一的ID ,我们可以使用它来搜索(已经实现)用户序列化。下面是您可以在项目中使用的示例实现 - 它位于作为新策略的第二个参数的函数内,就在console.log(profile);目前是:
     db.collection( 'socialusers')。findAndModify(
    +    {id:profile.id},
    +    {},
    +    {$ setOnInsert:{
    +        id:profile.id,
    +        name:profile.displayName || 'John Doe',
    +        照片:profile.photos [0] .value || ”
    +        电子邮件:profile.emails [0] .value || '没有公开电子邮件',
    +        created_on:new Date(),
    +        provider:profile.provider || “
    +    } $设置:{
    +        last_login:新日期()
    +    } $ INC {
    +        login_count:1
    +    }},
    +    {upsert:true,new:true},
    +    (错误,doc)=> {
    +        return cb(null,doc.value);
    +    }
    +); 
    使用findAndModify,它允许您搜索对象并对其进行更新,如果对象不存在则将其置换,并在每次回调函数中接收新对象。在这个例子中,我们总是将last_login设置为now,我们总是将login_count增加1,并且只有当我们插入一个新对象(新用户)时,我们才会填充大部分字段。需要注意的是使用默认值。有时,返回的个人资料不会填写所有信息,或者用户会选择保留私密信息;所以在这种情况下我们必须处理它以防止错误。你现在应该可以登录你的应用了 - 试试吧!当您认为自己已经做对时,请提交您的页面。如果你正在运行到错误,您可以检查出的这个小项目的完成代码的例子在这里
    ## Instructions -
    - +
    ## Tests @@ -49,7 +37,7 @@ db.collection('socialusers').findAndModify( ```yml tests: - - text: GitHub 策略应配置完成。 + - text: Github策略设置完成 testString: getUserInput => $.get(getUserInput('url')+ '/_api/server.js') .then(data => { assert.match(data, /GitHubStrategy[^]*db.collection/gi, 'Strategy should use now use the database to search for the user'); assert.match(data, /GitHubStrategy[^]*socialusers/gi, 'Strategy should use "socialusers" as db collection'); assert.match(data, /GitHubStrategy[^]*return cb/gi, 'Strategy should return the callback function "cb"'); }, xhr => { throw new Error(xhr.statusText); }) ``` @@ -65,11 +53,6 @@ tests:
    ```js -/** - Backend challenges don't need solutions, - because they would need to be tested against a full working project. - Please check our contributing guidelines to learn more. -*/ +// solution required ``` -
    diff --git a/curriculum/challenges/chinese/06-information-security-and-quality-assurance/advanced-node-and-express/implementation-of-social-authentication.chinese.md b/curriculum/challenges/chinese/06-information-security-and-quality-assurance/advanced-node-and-express/implementation-of-social-authentication.chinese.md index 52071b3d126..7b49be11e8d 100644 --- a/curriculum/challenges/chinese/06-information-security-and-quality-assurance/advanced-node-and-express/implementation-of-social-authentication.chinese.md +++ b/curriculum/challenges/chinese/06-information-security-and-quality-assurance/advanced-node-and-express/implementation-of-social-authentication.chinese.md @@ -2,33 +2,18 @@ id: 589a69f5f9fc0f352b528e70 title: Implementation of Social Authentication challengeType: 2 -isHidden: false -forumTopicId: 301559 -localeTitle: 实现第一种社交登录 +videoUrl: '' +localeTitle: 社会认证的实施 --- ## Description -
    -注意,本项目在这个 Glitch 项目的基础上进行开发,你也可以从 GitHub 上克隆。 -第三方用户验证的实现逻辑如下:
    1. 在用户点击按钮或者链接后,进入验证页面,通过第三方平台(如 GitHub)来进行用户验证。
    2. 需要在路由中调用passport.authenticate('github'),跳转至 GitHub 验证页面。
    3. 页面跳转到 GitHub 上,如果用户未登录 GitHub,就需要在这里进行登录。登录成功后,会出现向用户申请访问权限的确认页。
    4. 如果用户同意访问,则用户会回到我们提供的回调地址,带着 GitHub 那边提供的用户信息回到我们的 app 中。
    5. 验证已完成。在我们的应用中,我们需要查询这个用户是否已经存在。如果是新用户,那我们需要把他的用户信息存储到数据库。
    -在 OAuth 验证策略中,我们至少需要提供 Client IDClient Secret,这样第三方平台就会获悉验证请求的来源,以及这个来源是否有效。为此,需要去我们使用的第三方验证平台(比如 GitHub)获取这两个字段的值。注意,我们获取到的这个值是唯一的,且仅对我们的当前 app 有效——因此,千万不要分享给别人,更不要上传到公共仓库或者直接写在代码里。通常,我们会在 .env 文件里配置,并在 Node.js 里通过:process.env.GITHUB_CLIENT_ID获取。对于这次挑战,我们将会使用 GitHub 作为验证平台。 -首先,你需要进入账户设置里的 Developer settings板块,然后在 OAuth Apps 获取 Client IDClient Secret。点击 'Register a new application',设置你的应用名称,然后把你的 glitch 主页地址(注意,不是项目代码的地址)粘贴到 Homepage URL。然后,回调 url 需要设置成上面 Homepage URL 里你粘贴的地址,但后面要加上 '/auth/github/callback'。这样在用户通过 Github 验证后才能跳转到我们指定的页面。别忘了,我们还需要在 .env 文件里配置好 'GITHUB_CLIENT_ID' 和 'GITHUB_CLIENT_SECRET'。 -然后,请在你现在的项目里,为 /auth/github 和 /auth/github/callback 创建两个接收 GET 请求的路由。第一个只需要通过 passport 来调用 'github' 验证,第二个需要调用 passport 来验证 'github',但需要在失败时跳转回主页 '/',成功是跳转到用户页面 '/profile'。跳转的逻辑与上一个项目中的逻辑一样。 -例如 '/auth/github/callback' 应该像我们处理在上一个项目中一般的登录一样: - -```js -app.route('/login') - .post(passport.authenticate('local', { failureRedirect: '/' }), (req,res) => { - res.redirect('/profile'); - }); -``` - -完成上述要求后,你就可以在左边提交你的页面链接。如果运行出错,你可以在这里检查你的项目完成情况。 -
    +
    提醒一下,这个项目是基于Glitch的以下入门项目构建的,或者是从GitHub克隆的。此类身份验证在您的应用中遵循的基本路径是:
    1. 用户单击按钮或链接将它们发送到我们使用特定策略进行身份验证的路由(EG.GitHub)
    2. 您的路由呼叫passport.authenticate('github') ,将其重定向到Github。
    3. 用户登陆的页面,在Github上,允许他们登录,如果他们还没有。然后它要求他们批准从我们的应用程序访问他们的个人资料。
    4. 然后,如果用户获得批准,则会使用他们的个人资料将该用户返回到我们的应用。
    5. 它们现在已经过身份验证,您的应用应检查它是否为返回的配置文件,如果不是,则将其保存在数据库中。
    OAuth策略要求您至少拥有客户端ID客户端密钥 ,以便他们验证身份验证请求的来源以及是否有效。这些是从您尝试使用Github实现身份验证的站点获得的,并且对您的应用程序是唯一的 - 它们不会被共享 ,不应该上传到公共存储库或直接在您的代码中编写。通常的做法是将它们放在.env文件中并引用它们: process.env.GITHUB_CLIENT_ID 。对于这个挑战,我们将使用Github策略。 从Github获取您的客户ID和密码是在“开发者设置”下的帐户配置文件设置中完成的,然后是“ OAuth应用程序 ”。点击“注册一个新的应用程序”,为您的应用命名,将网址粘贴到您的故障主页( 不是项目代码的网址 ),最后为回调网址,粘贴到与主页相同的网址,但使用'/ auth / github / callback'已添加。这是用户将被重定向到我们在Github上进行身份验证后处理的地方。将返回的信息保存为.env文件中的“GITHUB_CLIENT_ID”和“GITHUB_CLIENT_SECRET”。在重新混合的项目中,创建2条接受GET请求的路由:/ auth / github和/ auth / github / callback。第一个应该只调用护照来验证'github',第二个应该调用护照来验证'github',失败重定向到'/'然后如果成功重定向到'/ profile'(类似于我们的上一个项目)。 '/ auth / github / callback'应该如何看待的示例与我们在上一个项目中处理正常登录的方式类似:
     app.route( '/登录')
    +  .post(passport.authenticate('local',{failureRedirect:'/'}),(req,res)=> {
    +    res.redirect( '/简档');
    +  }); 
    当您认为自己已经做对时,请提交您的页面。如果您遇到错误,可以在此处查看项目。
    ## Instructions -
    - +
    ## Tests @@ -36,9 +21,9 @@ app.route('/login') ```yml tests: - - text: 路由 /auth/github 应正确配置。 + - text: Route / auth / github正确 testString: getUserInput => $.get(getUserInput('url')+ '/_api/server.js') .then(data => { assert.match(data, /('|")\/auth\/github('|")[^]*get.*passport.authenticate.*github/gi, 'Route auth/github should only call passport.authenticate with github'); }, xhr => { throw new Error(xhr.statusText); }) - - text: 路由 /auth/github/callback 应正确配置。 + - text: Route / auth / github /回调正确 testString: getUserInput => $.get(getUserInput('url')+ '/_api/server.js') .then(data => { assert.match(data, /('|")\/auth\/github\/callback('|")[^]*get.*passport.authenticate.*github.*failureRedirect:( |)("|')\/("|')/gi, 'Route auth/github/callback should accept a get request and call passport.authenticate for github with a failure redirect to home'); }, xhr => { throw new Error(xhr.statusText); }) ``` @@ -54,11 +39,6 @@ tests:
    ```js -/** - Backend challenges don't need solutions, - because they would need to be tested against a full working project. - Please check our contributing guidelines to learn more. -*/ +// solution required ``` -
    diff --git a/curriculum/challenges/chinese/06-information-security-and-quality-assurance/advanced-node-and-express/logging-a-user-out.chinese.md b/curriculum/challenges/chinese/06-information-security-and-quality-assurance/advanced-node-and-express/logging-a-user-out.chinese.md index c98a859a0f9..691513e8d21 100644 --- a/curriculum/challenges/chinese/06-information-security-and-quality-assurance/advanced-node-and-express/logging-a-user-out.chinese.md +++ b/curriculum/challenges/chinese/06-information-security-and-quality-assurance/advanced-node-and-express/logging-a-user-out.chinese.md @@ -2,41 +2,23 @@ id: 58965611f9fc0f352b528e6c title: Logging a User Out challengeType: 2 -isHidden: false -forumTopicId: 301560 -localeTitle: 用户退出 +videoUrl: '' +localeTitle: 记录用户 --- ## Description -
    -注意,本项目在这个 Glitch 项目的基础上进行开发,你也可以从 GitHub 上克隆。 -创建退出登录的逻辑是比较简单的。只要用户尝试退出登录,路由就应重定向到主页,而不应该显示任何其他页面。 -在 passport 里,只需要在重定向前调用req.logout();即可完成用户登出。 - -```js -app.route('/logout') - .get((req, res) => { - req.logout(); - res.redirect('/'); -}); -``` - -你可能注意到我们还没有处理 404 错误,这个错误码代表页面无法找到。在 Node.js 中我们通常会用如下的中间件来处理,请在所有路由之后添加这段代码: - -```js -app.use((req, res, next) => { - res.status(404) - .type('text') - .send('Not Found'); -}); -``` - -完成上述要求后,你就可以在左边提交你的页面链接。 -
    +
    提醒一下,这个项目是基于Glitch的以下入门项目构建的,或者是从GitHub克隆的。创建注销逻辑很容易。路径应该只是取消认证用户并重定向到主页而不是渲染任何视图。在护照中, req.logout();认证用户就像调用req.logout();一样简单req.logout();在重定向之前。
     app.route( '/注销')
    +  .get((req,res)=> {
    +      req.logout();
    +      res.redirect( '/');
    +  }); 
    您可能已经注意到我们也没有处理丢失的页面(404),在Node中处理此问题的常用方法是使用以下中间件。继续在所有其他路线之后添加:
     app.use((req,res,next)=> {
    +  res.status(404)
    +    .TYPE( '文本')
    +    .send('未找到');
    +}); 
    当您认为自己已经做对时,请提交您的页面。
    ## Instructions -
    - +
    ## Tests @@ -44,9 +26,9 @@ app.use((req, res, next) => { ```yml tests: - - text: 应存在退出登录的路由。 + - text: 退出路线 testString: getUserInput => $.get(getUserInput('url')+ '/_api/server.js') .then(data => { assert.match(data, /req.logout/gi, 'You should be calling req.logout() in your /logout route'); }, xhr => { throw new Error(xhr.statusText); }) - - text: 退出登录后应重定向到主页 / + - text: 注销应该重定向到主页/ testString: getUserInput => $.get(getUserInput('url')+ '/logout') .then(data => { assert.match(data, /Home page/gi, 'When a user logs out they should be redirected to the homepage'); }, xhr => { throw new Error(xhr.statusText); }) ``` @@ -62,11 +44,6 @@ tests:
    ```js -/** - Backend challenges don't need solutions, - because they would need to be tested against a full working project. - Please check our contributing guidelines to learn more. -*/ +// solution required ``` -
    diff --git a/curriculum/challenges/chinese/06-information-security-and-quality-assurance/advanced-node-and-express/registration-of-new-users.chinese.md b/curriculum/challenges/chinese/06-information-security-and-quality-assurance/advanced-node-and-express/registration-of-new-users.chinese.md index 6400d833cb1..bd7aa219d7c 100644 --- a/curriculum/challenges/chinese/06-information-security-and-quality-assurance/advanced-node-and-express/registration-of-new-users.chinese.md +++ b/curriculum/challenges/chinese/06-information-security-and-quality-assurance/advanced-node-and-express/registration-of-new-users.chinese.md @@ -2,55 +2,40 @@ id: 58966a17f9fc0f352b528e6d title: Registration of New Users challengeType: 2 -isHidden: false -forumTopicId: 301561 -localeTitle: 注册新用户 +videoUrl: '' +localeTitle: 新用户注册 --- ## Description -
    -注意,本项目在这个 Glitch 项目的基础上进行开发,你也可以从 GitHub 上克隆。 -现在我们需要为新用户添加注册帐号的功能,首先我们需要在主页的 res.render 接收的变量对象中添加showRegistration: true。此时刷新页面,你会看到页面上已经显示了我们在 index.pug 文件中定义的注册表单。这个表单设置了请求路径 /register,并将请求方法设置成 POST,所以我们需要在服务器接受 POST 请求,且在数据库中创建用户对象。 -用户注册的逻辑如下:注册新用户 > 认证新用户 > 重定向到 /profile。 -对于步骤一的注册新用户,详细逻辑如下:用 findOne 命令查询数据库 > 如果返回了用户对象,则表示用户存在,然后返回主页;如果用户未定义且没有报错,则会将包含用户名和密码的用户对象通过insertOne添加到数据库,只要没有报错则会继续下一步:认证新用户——我们已经在 /login 路由的 POST 请求中写好了这部分逻辑。 - -```js -app.route('/register') - .post((req, res, next) => { - db.collection('users').findOne({ username: req.body.username }, function(err, user) { - if (err) { - next(err); - } else if (user) { - res.redirect('/'); - } else { - db.collection('users').insertOne({ - username: req.body.username, - password: req.body.password - }, - (err, doc) => { - if (err) { - res.redirect('/'); - } else { - next(null, user); - } +
    提醒一下,这个项目是基于Glitch的以下入门项目构建的,或者是从GitHub克隆的。现在我们需要允许我们网站上的新用户注册一个帐户。在主页的res.render上,向传递的对象添加一个新变量 - showRegistration: true 。刷新页面时,您应该会看到已在index.pug文件中创建的注册表单!此表单设置为POST on / register,因此我们应该设置此接受POST并在数据库中创建用户对象。注册路由的逻辑应如下所示:注册新用户>验证新用户>重定向到/配置文件步骤1的逻辑,注册新用户,应如下所示:使用findOne命令查询数据库>如果用户返回然后它存在并重定向回到主页或者如果用户未定义且没有发生错误,则使用用户名和密码将“insertOne”输入数据库,只要没有错误发生,然后调用next转到步骤2,验证新的user,我们已经在POST / login路由中编写了逻辑。
     app.route( '/寄存器')
    +  .post((req,res,next)=> {
    +      db.collection('users')。findOne({username:req.body.username},function(err,user){
    +          if(错误){
    +              下一个(ERR);
    +          } else if(user){
    +              res.redirect( '/');
    +          } else {
    +              db.collection( '用户')。insertOne(
    +                {username:req.body.username,
    +                 密码:req.body.password},
    +                (错误,doc)=> {
    +                    if(错误){
    +                        res.redirect( '/');
    +                    } else {
    +                        next(null,user);
    +                    }
    +                }
    +              )
               }
    -        )
    -      }
    -    })
    -  },
    -    passport.authenticate('local', { failureRedirect: '/' }),
    -    (req, res, next) => {
    -      res.redirect('/profile');
    +      })},
    +    passport.authenticate('local',{failureRedirect:'/'}),
    +    (req,res,next)=> {
    +        res.redirect( '/简档');
         }
    -  );
    -```
    -
    -完成上述要求后,你就可以在左边提交你的页面链接。如果运行出错,你可以在这里检查你的项目完成情况。
    -
    +); 当您认为自己已经做对时,请提交您的页面。如果您遇到错误,可以在这里查看到目前为止完成的项目。
    ## Instructions -
    - +
    ## Tests @@ -58,15 +43,15 @@ app.route('/register') ```yml tests: - - text: 注册路由和显示主页。 + - text: 注册路线并在家中显示 testString: 'getUserInput => $.get(getUserInput(''url'')+ ''/_api/server.js'') .then(data => { assert.match(data, /showRegistration:( |)true/gi, ''You should be passing the variable "showRegistration" as true to your render function for the homepage''); assert.match(data, /register[^]*post[^]*findOne[^]*username:( |)req.body.username/gi, ''You should have a route accepted a post request on register that querys the db with findone and the query being "username: req.body.username"''); }, xhr => { throw new Error(xhr.statusText); })' - - text: 注册功能应可以正常运行。 + - text: 注册应该工作 testString: 'getUserInput => $.ajax({url: getUserInput(''url'')+ ''/register'',data: {username: ''freeCodeCampTester'', password: ''freeCodeCampTester''},crossDomain: true, type: ''POST'', xhrFields: { withCredentials: true }}) .then(data => { assert.match(data, /Profile/gi, ''I should be able to register and it direct me to my profile. CLEAR YOUR DATABASE if this test fails (each time until its right!)''); }, xhr => { throw new Error(xhr.statusText); })' - - text: 登录功能应可以正常运行。 + - text: 登录应该工作 testString: 'getUserInput => $.ajax({url: getUserInput(''url'')+ ''/login'',data: {username: ''freeCodeCampTester'', password: ''freeCodeCampTester''}, type: ''POST'', xhrFields: { withCredentials: true }}) .then(data => { assert.match(data, /Profile/gi, ''Login should work if previous test was done successfully and redirect successfully to the profile. Check your work and clear your DB''); assert.match(data, /freeCodeCampTester/gi, ''The profile should properly display the welcome to the user logged in''); }, xhr => { throw new Error(xhr.statusText); })' - - text: 退出登录功能应可以正常运行。 + - text: 注销应该有效 testString: 'getUserInput => $.ajax({url: getUserInput(''url'')+ ''/logout'', type: ''GET'', xhrFields: { withCredentials: true }}) .then(data => { assert.match(data, /Home/gi, ''Logout should redirect to home''); }, xhr => { throw new Error(xhr.statusText); })' - - text: 退出登录后,profile 页面应无法访问。 + - text: 注销后配置文件不再有效 testString: 'getUserInput => $.ajax({url: getUserInput(''url'')+ ''/profile'', type: ''GET'', crossDomain: true, xhrFields: { withCredentials: true }}) .then(data => { assert.match(data, /Home/gi, ''Profile should redirect to home when we are logged out now again''); }, xhr => { throw new Error(xhr.statusText); })' ``` @@ -82,11 +67,6 @@ tests:
    ```js -/** - Backend challenges don't need solutions, - because they would need to be tested against a full working project. - Please check our contributing guidelines to learn more. -*/ +// solution required ``` -
    diff --git a/curriculum/challenges/chinese/06-information-security-and-quality-assurance/advanced-node-and-express/send-and-display-chat-messages.chinese.md b/curriculum/challenges/chinese/06-information-security-and-quality-assurance/advanced-node-and-express/send-and-display-chat-messages.chinese.md index 8a82fbacee9..b4eab49bde9 100644 --- a/curriculum/challenges/chinese/06-information-security-and-quality-assurance/advanced-node-and-express/send-and-display-chat-messages.chinese.md +++ b/curriculum/challenges/chinese/06-information-security-and-quality-assurance/advanced-node-and-express/send-and-display-chat-messages.chinese.md @@ -2,24 +2,15 @@ id: 589fc832f9fc0f352b528e79 title: Send and Display Chat Messages challengeType: 2 -isHidden: false -forumTopicId: 301562 +videoUrl: '' localeTitle: 发送和显示聊天消息 --- ## Description -
    -注意,本项目在这个 Glitch 项目的基础上进行开发,你也可以从 GitHub 上克隆。 -现在,我们可以开始实现聊天室功能了。整体逻辑很简单,只需要获取用户发给服务端的消息,再通过服务端给所有客户端发送信息就可以了。在 client.js 文件里,你应该已经注意到了这段提交表单的代码:$('form').submit(function(){ /*logic*/ }); -
    现在我们需要处理事件的 emit,它应该发生在定义 'messageToSend' 之后,以及清除#m中的文本之前。我们称这个事件叫 'chat message',需发送的数据叫 'messageToSend':socket.emit('chat message', messageToSend); -在服务端,我们需要监听包含 'message' 的 'chat message' 事件。一旦事件发生,我们就通过io.emit 把包含 'name' 和 'message' 的 'chat message' 事件发送给所有已连接的 socket。 -回到客户端,我们需要监听 'chat message' 事件。只要接收到这个事件,就把包含名字和消息的内容(注意:需要在名字后添加冒号)通过<li>添加到#messages。 -至此,我们已经完成发送信息到所有客户端的功能。完成上述要求后,你就可以在左边提交你的页面链接。如果运行出错,你可以在 这里对应服务端这里对应客户端 来检查完成代码。 -
    +
    提醒一下,这个项目是基于Glitch的以下入门项目构建的,或者是从GitHub克隆的。是时候开始允许客户端向服务器发送聊天消息以向所有客户端发送消息!已经在您的client.js文件中,您应该看到在提交messgae表单时已经存在一段代码处理! ( $('form').submit(function(){ /*logic*/ });
    在您处理表单提交的代码中,您应该在定义“messageToSend”之后但在清除文本框#m之前发出事件。该事件应命名为“聊天消息”,数据应为“messageToSend”。 socket.emit('chat message', messageToSend);现在,在您的服务器上,您应该收听事件“聊天消息”的套接字,并将数据命名为“message”。一旦接收到事件,应该然后发射所述事件“聊天消息”到所有插座io.emit与数据为含“名称”和“报文”的对象。现在再次在您的客户端上,您现在应该监听事件“聊天消息”,并在收到时,将一个列表项追加到#messages ,其名称为冒号和消息!此时聊天功能齐全,并在所有客户端发送消息!当您认为自己已经做对时,请提交您的页面。如果您遇到错误,可以在此处检查项目到此时为服务器客户端
    ## Instructions -
    - +
    ## Tests @@ -27,9 +18,9 @@ localeTitle: 发送和显示聊天消息 ```yml tests: - - text: '服务端应监听 "chat message",且应在监听到后 emit。' + - text: 服务器侦听“聊天消息”,然后正确发出 testString: getUserInput => $.get(getUserInput('url')+ '/_api/server.js') .then(data => { assert.match(data, /socket.on.*('|")chat message('|")[^]*io.emit.*('|")chat message('|").*name.*message/gi, 'Your server should listen to the socket for "chat message" then emit to all users "chat message" with name and message in the data object'); }, xhr => { throw new Error(xhr.statusText); }) - - text: '客户端应正确处理和展示从 "chat message" 事件发来的新数据。' + - text: 客户端正确处理和显示事件“聊天消息”中的新数据 testString: "getUserInput => $.get(getUserInput('url')+ '/public/client.js') .then(data => { assert.match(data, /socket.on.*('|\")chat message('|\")[^]*messages.*li/gi, 'You should append a list item to #messages on your client within the \"chat message\" event listener to display the new message'); }, xhr => { throw new Error(xhr.statusText); })" ``` @@ -45,11 +36,6 @@ tests:
    ```js -/** - Backend challenges don't need solutions, - because they would need to be tested against a full working project. - Please check our contributing guidelines to learn more. -*/ +// solution required ``` -
    diff --git a/curriculum/challenges/chinese/06-information-security-and-quality-assurance/advanced-node-and-express/serialization-of-a-user-object.chinese.md b/curriculum/challenges/chinese/06-information-security-and-quality-assurance/advanced-node-and-express/serialization-of-a-user-object.chinese.md index c38aa67e113..96fdba6edfe 100644 --- a/curriculum/challenges/chinese/06-information-security-and-quality-assurance/advanced-node-and-express/serialization-of-a-user-object.chinese.md +++ b/curriculum/challenges/chinese/06-information-security-and-quality-assurance/advanced-node-and-express/serialization-of-a-user-object.chinese.md @@ -2,39 +2,24 @@ id: 5895f70cf9fc0f352b528e66 title: Serialization of a User Object challengeType: 2 -isHidden: false -forumTopicId: 301563 +videoUrl: '' localeTitle: 用户对象的序列化 --- ## Description -
    -注意,本项目在这个 Glitch 项目的基础上进行开发,你也可以从 GitHub 上克隆。 -序列化和反序列化在身份认证中是很重要的概念。序列化一个对象就是将其内容转换成一个体积很小的 key,后续可以通过这个 key 反序列化为原始对象。这样,服务器就可以在用户未登录时识别用户,或者说给这个用户一个唯一标识,用户也不需要在每次访问不同页面时都给服务器发送用户名和密码。 -我们需要用到序列化和反序列化的方法来进行配置。passport 为我们提供了passport.serializeUser( OURFUNCTION )passport.deserializeUser( OURFUNCTION )两个方法。 -serializeUser方法接收两个参数,分别是表示用户的对象和一个回调函数。其中,回调函数的返回值应为这个用户的唯一标识符:最简单的写法就是让它返回用户的_id,这个_id属性是 MongoDB 为用户创建的唯一字段。类似地,反序列化也接收两个参数,分别是在序列化时生成的标识符以及一个回调函数。在回调函数里,我们需要根据根据传入的标识符(比如 _id)返回表示用户的对象。为了在 MongoDB 中通过 query(查询语句)获取 _id 字段,首先我们需要引入 MongoDB 的ObjectID方法:const ObjectID = require('mongodb').ObjectID;;然后调用它:new ObjectID(THE_ID)。当然,这一切的前提都是先引入 MongoDB 作为依赖。你可以在下面的例子中看到: - -```js -passport.serializeUser((user, done) => { - done(null, user._id); -}); -passport.deserializeUser((id, done) => { - db.collection('users').findOne( - {_id: new ObjectID(id)}, - (err, doc) => { - done(null, doc); - } - ); -}); -``` - -注意:在完全配置好 MongoDB 前,deserializeUser会抛出错误。因此,现在请先注释掉上面的代码,在回调函数中仅仅调用done(null, null)即可。 -完成上述要求后,你就可以在左边提交你的页面链接。 -
    +
    提醒一下,这个项目是基于Glitch的以下入门项目构建的,或者是从GitHub克隆的。序列化和反序列化是身份验证方面的重要概念。序列化对象意味着将其内容转换为一个小键,基本上可以将其反序列化为原始对象。这使我们能够知道与服务器通信的人,而无需在每次请求新页面时发送用户名和密码等身份验证数据。要正确设置它,我们需要一个序列化函数和一个反序列化函数。在护照中,我们使用passport.serializeUser( OURFUNCTION )passport.deserializeUser( OURFUNCTION )创建它们。使用2个参数调用serializeUser,完整的用户对象和护照使用的回调。在回调中返回应该是唯一的键来标识该用户 - 最容易使用的用户是对象中的用户_id,因为它应该是MongoDb生成的唯一用户。类似地,使用该密钥和护照的回调函数调用deserializeUser,但这次我们必须获取该密钥并将用户完整对象返回到回调。要进行查询搜索Mongo _id,您必须创建const ObjectID = require('mongodb').ObjectID; ,然后使用它调用new ObjectID(THE_ID) 。一定要将MongoDB添加为依赖项。您可以在以下示例中看到:
     passport.serializeUser((user,done)=> {
    +   done(null,user._id);
    + }); 

     passport.deserializeUser((id,done)=> {
    +        db.collection( '用户')。findOne(
    +            {_id:new ObjectID(id)},
    +            (错误,doc)=> {
    +                完成(null,doc);
    +            }
    +        );
    +    }); 
    注意:这个deserializeUser将抛出一个错误,直到我们在下一步中设置数据库,因此注释掉整个块并在函数deserializeUser中调用done(null, null) 。当您认为自己已经做对时,请提交您的页面。
    ## Instructions -
    - +
    ## Tests @@ -42,13 +27,13 @@ passport.deserializeUser((id, done) => { ```yml tests: - - text: 应存在正确的serializeUser方法。 + - text: 序列化用户功能正确 testString: getUserInput => $.get(getUserInput('url')+ '/_api/server.js') .then(data => { assert.match(data, /passport.serializeUser/gi, 'You should have created your passport.serializeUser function'); assert.match(data, /null, user._id/gi, 'There should be a callback in your serializeUser with (null, user._id)'); }, xhr => { throw new Error(xhr.statusText); }) - - text: 应存在正确的deserializeUser方法。 + - text: 反序列化用户功能正确 testString: getUserInput => $.get(getUserInput('url')+ '/_api/server.js') .then(data => { assert.match(data, /passport.deserializeUser/gi, 'You should have created your passport.deserializeUser function'); assert.match(data, /null,( |)null/gi, 'There should be a callback in your deserializeUser with (null, null) for now'); }, xhr => { throw new Error(xhr.statusText); }) - - text: MongoDB 应作为项目的依赖。 + - text: MongoDB是一个依赖项 testString: getUserInput => $.get(getUserInput('url')+ '/_api/package.json') .then(data => { var packJson = JSON.parse(data); assert.property(packJson.dependencies, 'mongodb', 'Your project should list "mongodb" as a dependency'); }, xhr => { throw new Error(xhr.statusText); }) - - text: 注释掉的代码中应包含ObjectId。 + - text: Mongodb正确要求包括ObjectId testString: getUserInput => $.get(getUserInput('url')+ '/_api/server.js') .then(data => { assert.match(data, /require.*("|')mongodb("|')/gi, 'You should have required mongodb'); assert.match(data, /new ObjectID.*id/gi, 'Even though the block is commented out, you should use new ObjectID(id) for when we add the database'); }, xhr => { throw new Error(xhr.statusText); }) ``` @@ -64,11 +49,6 @@ tests:
    ```js -/** - Backend challenges don't need solutions, - because they would need to be tested against a full working project. - Please check our contributing guidelines to learn more. -*/ +// solution required ``` -
    diff --git a/curriculum/challenges/chinese/06-information-security-and-quality-assurance/advanced-node-and-express/set-up-a-template-engine.chinese.md b/curriculum/challenges/chinese/06-information-security-and-quality-assurance/advanced-node-and-express/set-up-a-template-engine.chinese.md index 87beb8b0aea..efb47a85d58 100644 --- a/curriculum/challenges/chinese/06-information-security-and-quality-assurance/advanced-node-and-express/set-up-a-template-engine.chinese.md +++ b/curriculum/challenges/chinese/06-information-security-and-quality-assurance/advanced-node-and-express/set-up-a-template-engine.chinese.md @@ -2,68 +2,42 @@ id: 5895f700f9fc0f352b528e63 title: Set up a Template Engine challengeType: 2 -isHidden: false -forumTopicId: 301564 +videoUrl: '' localeTitle: 设置模板引擎 --- ## Description - -
    -注意,本项目在这个 Glitch 项目的基础上进行开发,你也可以从 GitHub 上克隆。 -你可以在应用的模版引擎中使用静态模板文件(如那些写在Pug里的)。在运行时,模版引擎会用服务端的真实数据替换掉模版文件中的变量,然后将模版转译成发送给客户端的 HTML 静态文件。这样可以轻松地构造 HTML 页面,允许在页面直接显示变量内容而不需要发送 API 请求。 -为了在项目中使用 Pug,你需要在 package.json 中添加依赖"pug": "^0.1.0" - -为了在 Node/Express 中使用 pug 作为模版引擎,你需要在 express 中将 app 的 “view-engine” 设置为 “pug”,就像这样:app.set('view engine', 'pug')。 - -如果没有正确的 render 'views/pug' 路径下的 index 文件,页面将不会被加载。 - -最后, 你需要使用res.render方法渲染 views/pug/index.pug 页面来作为路由请求的返回。 - -如果一切顺利,刷新一下应用的主页就可以看到 Pug 成功加载的提示,这时你就可以提交你的页面了。 - -
    +
    提醒一下,这个项目是基于Glitch的以下入门项目构建的,或者是从GitHub克隆的。模板引擎使您可以在应用程序中使用静态模板文件(例如用Pug编写的文件)。在运行时,模板引擎将模板文件中的变量替换为可由服务器提供的实际值,并将模板转换为静态HTML文件,然后将其发送到客户端。这种方法可以更轻松地设计HTML页面,并允许在页面上显示变量,而无需从客户端进行API调用。要设置Pug以便在项目中使用,您需要先在package.json中将其作为依赖项添加。 "pug": "^0.1.0"现在告诉Node / Express使用模板引擎,你必须告诉你的快递应用程序 'pug' 设置为'view-engine'。 app.set('view engine', 'pug')最后,你应该改变请求您响应该指数路线res.render与路径视图意见/哈巴狗/ index.pug。如果一切按计划进行,您应该刷新应用程序主页并看到一条小消息,说您已成功从我们的Pug文件中删除Pug!当您认为自己已经做对时,请提交您的页面。
    ## Instructions - -
    - +
    ## Tests -
    ```yml tests: - - text: "项目中应使用 'pug' 作为依赖。" + - text: 帕格是一个依赖 testString: getUserInput => $.get(getUserInput('url')+ '/_api/package.json') .then(data => { var packJson = JSON.parse(data); assert.property(packJson.dependencies, 'pug', 'Your project should list "pug" as a dependency'); }, xhr => { throw new Error(xhr.statusText); }) - - text: 项目中应使用 Pug 作为模版引擎。 + - text: 查看引擎是帕格 testString: getUserInput => $.get(getUserInput('url')+ '/_api/server.js') .then(data => { assert.match(data, /('|")view engine('|"),( |)('|")pug('|")/gi, 'Your project should set Pug as a view engine'); }, xhr => { throw new Error(xhr.statusText); }) - - text: 在 Response 里使用正确的 ExpressJS 方法渲染主页面。 - testString: getUserInput => $.get(getUserInput('url')+ '/_api/server.js') .then(data => { assert.match(data, /res(\s*)?\.(r\w{5})/gi, 'You successfully rendered the Pug template!'); }, xhr => { throw new Error(xhr.statusText); }) - - text: Pug 应该生效。 + - text: 帕格正在工作 testString: getUserInput => $.get(getUserInput('url')+ '/') .then(data => { assert.match(data, /pug-success-message/gi, 'Your projects home page should now be rendered by pug with the projects .pug file unaltered'); }, xhr => { throw new Error(xhr.statusText); }) + ```
    ## Challenge Seed -
    ## Solution -
    ```js -/** - Backend challenges don't need solutions, - because they would need to be tested against a full working project. - Please check our contributing guidelines to learn more. -*/ +// solution required ``` -
    diff --git a/curriculum/challenges/chinese/06-information-security-and-quality-assurance/advanced-node-and-express/set-up-passport.chinese.md b/curriculum/challenges/chinese/06-information-security-and-quality-assurance/advanced-node-and-express/set-up-passport.chinese.md index 310e723a401..12ad21e7e6f 100644 --- a/curriculum/challenges/chinese/06-information-security-and-quality-assurance/advanced-node-and-express/set-up-passport.chinese.md +++ b/curriculum/challenges/chinese/06-information-security-and-quality-assurance/advanced-node-and-express/set-up-passport.chinese.md @@ -2,35 +2,19 @@ id: 5895f70cf9fc0f352b528e65 title: Set up Passport challengeType: 2 -isHidden: false -forumTopicId: 301565 -localeTitle: 设置 Passport +videoUrl: '' +localeTitle: 设置护照 --- ## Description -
    -注意,本项目在这个 Glitch 项目的基础上进行开发,你也可以从 GitHub 上克隆。 -现在我们来创建 Passport,最终我们需要用它来实现用户注册和登录。除了 Passport,我们会用 express-session 来处理 session(会话)。在客户端,我们可以用这个中间件把会话 id 储存到 cookie,并可以通过服务器上的 id 访问会话数据。通过这种方式,我们可以无需把用户信息存到 cookie 来完成用户的验证。 -为了在你的项目中使用 Passport,首先你需要在 package.json 文件中添加依赖:"passport": "^0.3.2" -此外,还需要添加 express-session 作为依赖,就像这样:"express-session": "^1.15.0"。express-session 有许多高级特性,但我们暂时只需要了解其基础特性。 -现在,我们需要配置 session 并初始化 Passport。请先创建变量sessionpassport引入 express-session 和 passport。 -为了让 express 应用可以使用 session,我们需要添加一些基础选项。请在 .env 文件中添加字段SESSION_SECRET,并给它赋一个随机值,便于加密 cookie、计算哈希。 - -```js -app.use(session({ - secret: process.env.SESSION_SECRET, - resave: true, - saveUninitialized: true, -})); -``` - -还有,我们需要让 express 使用passport.initialize()passport.session()。为此,你需要这样写:app.use(passport.initialize());。 -完成之后就可以提交你的页面了。如果运行出错,你可以在这里检查项目的完成情况。 -
    +
    提醒一下,这个项目是基于Glitch的以下入门项目构建的,或者是从GitHub克隆的。是时候设置Passport,这样我们终于可以开始允许用户注册或登录帐户了!除了Passport,我们还将使用Express-session来处理会话。使用此中间件将会话ID保存为客户端中的cookie,并允许我们使用服务器上的该ID访问会话数据。这样,我们将个人帐户信息保留在客户端使用的cookie之外,以验证我们的服务器是否经过身份验证,并保留密钥以访问存储在服务器上的数据。要设置Passport以便在项目中使用,您需要先在package.json中将其作为依赖项添加。 "passport": "^0.3.2"此外,现在还要将Express-session添加为依赖项。 Express-session拥有大量可以使用的高级功能,但现在我们只是要使用基础知识! "express-session": "^1.15.0"您需要立即设置会话设置并初始化Passport。一定要先创建变量'session'和'passport',分别要求'express-session'和'passport'。要设置您要使用的快速应用程序使用会话,我们将仅定义几个基本选项。请务必将“SESSION_SECRET”添加到.env文件中,并为其提供随机值。这用于计算用于加密cookie的哈希值!
     app.use(会话({
    +  secret:process.env.SESSION_SECRET,
    +  resave:是的,
    +  saveUninitialized:true,
    +})); 
    您也可以继续告诉您的快递应用程序使用 'passport.initialize()'和'passport.session()'。 (例如, app.use(passport.initialize()); )当您认为自己正确时,请提交您的页面。如果您遇到错误,可以在这里查看到目前为止完成的项目。
    ## Instructions -
    - +
    ## Tests @@ -38,13 +22,13 @@ app.use(session({ ```yml tests: - - text: 应添加 Passort 和 express-session 作为依赖。 + - text: Passort和Express-session是依赖项 testString: getUserInput => $.get(getUserInput('url')+ '/_api/package.json') .then(data => { var packJson = JSON.parse(data); assert.property(packJson.dependencies, 'passport', 'Your project should list "passport" as a dependency'); assert.property(packJson.dependencies, 'express-session', 'Your project should list "express-session" as a dependency'); }, xhr => { throw new Error(xhr.statusText); }) - - text: 依赖应正确引入。 + - text: 正确要求依赖性 testString: getUserInput => $.get(getUserInput('url')+ '/_api/server.js') .then(data => { assert.match(data, /require.*("|')passport("|')/gi, 'You should have required passport'); assert.match(data, /require.*("|')express-session("|')/gi, 'You should have required express-session'); }, xhr => { throw new Error(xhr.statusText); }) - - text: express 应调用 passport 的方法。 + - text: Express应用程序使用新的依赖项 testString: getUserInput => $.get(getUserInput('url')+ '/_api/server.js') .then(data => { assert.match(data, /passport.initialize/gi, 'Your express app should use "passport.initialize()"'); assert.match(data, /passport.session/gi, 'Your express app should use "passport.session()"'); }, xhr => { throw new Error(xhr.statusText); }) - - text: 应正确设置 session 和 session secret。 + - text: 正确设置会话和会话密钥 testString: getUserInput => $.get(getUserInput('url')+ '/_api/server.js') .then(data => { assert.match(data, /secret:( |)process.env.SESSION_SECRET/gi, 'Your express app should have express-session set up with your secret as process.env.SESSION_SECRET'); }, xhr => { throw new Error(xhr.statusText); }) ``` @@ -60,11 +44,6 @@ tests:
    ```js -/** - Backend challenges don't need solutions, - because they would need to be tested against a full working project. - Please check our contributing guidelines to learn more. -*/ +// solution required ``` -
    diff --git a/curriculum/challenges/chinese/06-information-security-and-quality-assurance/advanced-node-and-express/set-up-the-environment.chinese.md b/curriculum/challenges/chinese/06-information-security-and-quality-assurance/advanced-node-and-express/set-up-the-environment.chinese.md index 6250b84ccec..6a3c05e25bf 100644 --- a/curriculum/challenges/chinese/06-information-security-and-quality-assurance/advanced-node-and-express/set-up-the-environment.chinese.md +++ b/curriculum/challenges/chinese/06-information-security-and-quality-assurance/advanced-node-and-express/set-up-the-environment.chinese.md @@ -2,40 +2,18 @@ id: 589fc830f9fc0f352b528e74 title: Set up the Environment challengeType: 2 -isHidden: false -forumTopicId: 301566 +videoUrl: '' localeTitle: 设置环境 --- ## Description -
    -注意,本项目在这个 Glitch 项目的基础上进行开发,你也可以从 GitHub 上克隆。 -现在,我们需要添加 Socket.IO 作为依赖,在你的代码中引入,给它传入参数 http 并实例化,将其命名为io,就像这样:const io = require('socket.io')(http); -我们需要处理的第一件事是监听从客户端发出的连接事件,我们可以调用 on 方法来监听具体的事件。它接收两个参数:一个是发出的事件的标题字符串,另一个是后续用来传递数据的回调函数。在这个回调函数中,我们用 socket 来代表它所包含的数据。简单来说,socket 就是指已连接到服务器的客户端。 -在我们服务器代码中,只需要在注释间添加以下内容即可: - -```js -io.on('connection', socket => { - console.log('A user has connected'); -}); -``` - -对于发出连接事件的客户端,只需要在 client.js 中添加以下内容: - -```js -/*global io*/ -var socket = io(); -``` - -注意,这个 client.js 文件是在用户通过验证后加载到客户端的。在这个文件中,我们没有定义 io 变量,但第一行的注释会阻止运行时产生的报错。然后,我们在 chat.pug 的页面上已经为你添加好了 Socket.IO 库的 CDN。 -现在你可以尝试启动你的 app 并登录,你会看到服务器的控制台中打印了 'A user has connected' -注意:
    只有在连接到处于同一个 url/server 上的 socket 时,io()才可以正常执行。如果需要连接到外部的 socket,就需要这样调用:io.connect('URL');。 -完成上述要求后,你就可以在左边提交你的页面链接。 -
    +
    提醒一下,这个项目是基于Glitch的以下入门项目构建的,或者是从GitHub克隆的。将Socket.IO添加为依赖项,并在服务器中要求/实例化它,定义为'io',并将http服务器作为参数。 const io = require('socket.io')(http);需要处理的第一件事是从客户端侦听新连接。 on关键字就是这样 - 监听特定事件。它需要2个参数:一个包含所发出事件标题的字符串,以及一个用于传递数据的函数。在我们的连接侦听器的情况下,我们使用socket来定义第二个参数中的数据。套接字是连接的个人客户端。要在我们的服务器上侦听连接,请在项目中的注释之间添加以下内容:
     io.on('connection',socket => {
    +  console.log('用户已连接');
    +}); 
    现在,对于客户端进行连接,您只需要将以下内容添加到client.js中,该客户端经过身份验证后由页面加载:
     / * global io * /
    +var socket = io(); 
    注释会抑制您通常会看到的错误,因为文件中未定义“io”。我们已经在chat.pug页面上的Socket.IO库中添加了一个可靠的CDN。现在尝试加载您的应用并进行身份验证,您应该在服务器控制台中看到“用户已连接”! 注意
    io()仅在连接到同一URL /服务器上托管的套接字时起作用。要连接到其他地方托管的外部套接字,您可以使用io.connect('URL'); 。当您认为自己已经做对时,请提交您的页面。
    ## Instructions -
    - +
    ## Tests @@ -43,13 +21,13 @@ var socket = io(); ```yml tests: - - text: 应添加 Socket.IO 作为依赖。 + - text: Socket.IO是一个依赖项 testString: getUserInput => $.get(getUserInput('url')+ '/_api/package.json') .then(data => { var packJson = JSON.parse(data); assert.property(packJson.dependencies, 'socket.io', 'Your project should list "socket.io" as a dependency'); }, xhr => { throw new Error(xhr.statusText); }) - - text: Socket.IO 应正确地引入和实例化。 + - text: Socket.IO已得到适当的要求和实例化 testString: getUserInput => $.get(getUserInput('url')+ '/_api/server.js').then(data => {assert.match(data, /io.*=.*require.*('|")socket.io('|").*http/gi, 'You should correctly require and instantiate socket.io as io.');}, xhr => { throw new Error(xhr.statusText); }) - - text: Socket.IO 应监听连接。 + - text: Socket.IO应该正在监听连接 testString: getUserInput => $.get(getUserInput('url')+ '/_api/server.js') .then(data => { assert.match(data, /io.on.*('|")connection('|").*socket/gi, 'io should listen for "connection" and socket should be the 2nd arguments variable'); }, xhr => { throw new Error(xhr.statusText); }) - - text: 客户端应连接到服务器。 + - text: 您的客户端应该连接到您的服务器 testString: getUserInput => $.get(getUserInput('url')+ '/public/client.js') .then(data => { assert.match(data, /socket.*=.*io/gi, 'Your client should be connection to server with the connection defined as socket'); }, xhr => { throw new Error(xhr.statusText); }) ``` @@ -65,11 +43,6 @@ tests:
    ```js -/** - Backend challenges don't need solutions, - because they would need to be tested against a full working project. - Please check our contributing guidelines to learn more. -*/ +// solution required ``` -
    diff --git a/curriculum/challenges/chinese/06-information-security-and-quality-assurance/advanced-node-and-express/use-a-template-engines-powers.chinese.md b/curriculum/challenges/chinese/06-information-security-and-quality-assurance/advanced-node-and-express/use-a-template-engines-powers.chinese.md index 96ab8a0b3f5..c23a8e0c34d 100644 --- a/curriculum/challenges/chinese/06-information-security-and-quality-assurance/advanced-node-and-express/use-a-template-engines-powers.chinese.md +++ b/curriculum/challenges/chinese/06-information-security-and-quality-assurance/advanced-node-and-express/use-a-template-engines-powers.chinese.md @@ -2,26 +2,15 @@ id: 5895f70bf9fc0f352b528e64 title: Use a Template Engine's Powers challengeType: 2 -isHidden: false -forumTopicId: 301567 -localeTitle: 使用模板引擎 +videoUrl: '' +localeTitle: 使用模板引擎的权力 --- ## Description -
    -注意,本项目在这个 Glitch 项目的基础上进行开发,你也可以从 GitHub 上克隆。 -模版引擎最大的特点之一就是在 HTML 页面展示之前,可以从服务端传变量到模版文件。 -在 Pug 文件中,你可以用变量名来调用变量,比如写成#{variable_name}来实现行内调用,或像p= variable_name把元素与变量直接写在一起,这表示 p 元素的内容等价于这个变量。 -建议大家在 Pug 的 README 里看看它的语法和用法,这样你写出的代码会相对简练。另外要注意,Pug 使用缩进来表示嵌套的代码块。 -在 pug 的 'index.pug' 文件中,我们使用了 titlemessage 两个变量。 -为了从服务器传递这些信息,你需要给 res.render 的第二个参数传入一个对象,其中包含变量对应的值。比如,如果你想传递对象{title: 'Hello', message: 'Please login'到你的主页,那么应该这样写: -res.render(process.cwd() + '/views/pug/index', {title: 'Hello', message: 'Please login'}); -刷新页面,如果页面中数据显示正确,你就可以提交你的页面了。 -
    +
    提醒一下,这个项目是基于Glitch的以下入门项目构建的,或者是从GitHub克隆的。使用模板引擎的最大特点之一是能够将变量从服务器传递到模板文件,然后再将其呈现为HTML。在您的Pug文件中,您将通过引用变量名称作为#{variable_name}与元素上的其他文本内联,或者在元素上使用相等的一侧而不使用空格(例如p= variable_name来设置该p= variable_name 。 p元素文本等于变量。我们强烈建议在他们的Githubs自述文件中查看 Pug的语法和结构。 Pug就是使用空格和制表符来显示嵌套元素,并减少制作漂亮网站所需的代码量。查看项目中包含的我们的pug文件'index.pug',我们使用变量titlemessage要从我们的服务器单独传递它们,您需要将一个对象作为第二个参数添加到res.render中 ,并带有变量和他们的价值。例如,传递此对象以设置索引视图的变量: {title: 'Hello', message: 'Please login'它应该看起来像: res.render(process.cwd() + '/views/pug/index', {title: 'Hello', message: 'Please login'});现在刷新页面,您应该在视图中呈现的那些值在index.pug文件中列出的正确位置!当您认为自己已经做对时,请提交您的页面。
    ## Instructions -
    - +
    ## Tests @@ -29,7 +18,7 @@ localeTitle: 使用模板引擎 ```yml tests: - - text: Pug 应正确地展示变量。 + - text: 帕格渲染变量正确 testString: getUserInput => $.get(getUserInput('url')+ '/') .then(data => { assert.match(data, /pug-variable("|')>Please login/gi, 'Your projects home page should now be rendered by pug with the projects .pug file unaltered'); }, xhr => { throw new Error(xhr.statusText); }) ``` @@ -45,11 +34,6 @@ tests:
    ```js -/** - Backend challenges don't need solutions, - because they would need to be tested against a full working project. - Please check our contributing guidelines to learn more. -*/ +// solution required ``` -
    diff --git a/curriculum/challenges/chinese/06-information-security-and-quality-assurance/information-security-with-helmetjs/ask-browsers-to-access-your-site-via-https-only-with-helmet.hsts.chinese.md b/curriculum/challenges/chinese/06-information-security-and-quality-assurance/information-security-with-helmetjs/ask-browsers-to-access-your-site-via-https-only-with-helmet.hsts.chinese.md index 8a8f6d80219..6c8d977d436 100644 --- a/curriculum/challenges/chinese/06-information-security-and-quality-assurance/information-security-with-helmetjs/ask-browsers-to-access-your-site-via-https-only-with-helmet.hsts.chinese.md +++ b/curriculum/challenges/chinese/06-information-security-and-quality-assurance/information-security-with-helmetjs/ask-browsers-to-access-your-site-via-https-only-with-helmet.hsts.chinese.md @@ -2,21 +2,15 @@ id: 587d8248367417b2b2512c3c title: Ask Browsers to Access Your Site via HTTPS Only with helmet.hsts() challengeType: 2 -isHidden: false -forumTopicId: 301573 -localeTitle: 使用 helmet.hsts() 要求浏览器只通过HTTPS访问你的网站 +videoUrl: '' +localeTitle: 要求浏览器通过HTTPS访问您的站点仅限于使用helmet.hsts() --- ## Description -
    -温馨提醒,本项目在 这个 Glitch 项目 的基础上进行开发。你也可以从 GitHub 上克隆。 -HTTP严格安全传输 (HSTS) 是一个能帮助我们防护网站被协议降低攻击和 Cookie 挟持的 WEB 安全协议。如果你的网站支持 HTTPS 的话你可以让你的用户停止使用不安全的 HTTP。通过设置头部 ``Strict-Transport-Security``, 你告诉浏览器使用在未来的某段指定时间内使用 HTTPS 来请求网站内容。首次请求之后所以的后续请求都将使用 HTTPS -
    +
    提醒一下,这个项目是基于Glitch的以下入门项目构建的,或者是从GitHub克隆的。 HTTP严格传输安全(HSTS)是一种Web安全策略,可帮助保护网站免受协议降级攻击和cookie劫持。如果您的网站可以通过HTTPS访问,您可以要求用户的浏览器避免使用不安全的HTTP。通过设置标头Strict-Transport-Security,您可以告诉浏览器在指定的时间内对将来的请求使用HTTPS。这将适用于初始请求之后的请求。配置helmet.hsts()以在接下来的90天内使用HTTPS。传递配置对象{maxAge:timeInSeconds,force:true}。 Glitch已经启用了hsts。要覆盖其设置,您需要在配置对象中将字段“force”设置为true。在检查Glitch标头进行测试后,我们将拦截并恢复Glitch标头。注意:在自定义网站上配置HTTPS需要获取域和SSL / TSL证书。
    ## Instructions -
    -配置 helmet.hsts() 在未来的90天内使用 HTTPS。传递配置对象 {maxAge: timeInMilliseconds, force: true}. Glitch 默认已经开启 ``hsts``. 但你仍然可以通过 "force" 来覆盖它的配置。为了测试,我们会审查 Glitch 请求头部,然后拦截并恢复。 -注意: 配置 HTTPS 需要域名以及 SSL/TSL 证书。 +
    ## Tests @@ -24,9 +18,9 @@ HTTP严格安全传输 (HSTS) 是一个能帮助我们防护网站被协议降 ```yml tests: - - text: helmet.hsts() 中间件应该被正确加载 + - text: helmet.hsts()中间件应正确安装 testString: getUserInput => $.get(getUserInput('url') + '/_api/app-info').then(data => { assert.include(data.appStack, 'hsts'); assert.property(data.headers, 'strict-transport-security'); }, xhr => { throw new Error(xhr.responseText); }) - - text: maxAge 应该等于 7776000 ms (90天) + - text: maxAge应该等于7776000毫秒(90天) testString: getUserInput => $.get(getUserInput('url') + '/_api/app-info').then(data => { assert.match(data.headers['strict-transport-security'], /^max-age=7776000;?/); }, xhr => { throw new Error(xhr.responseText); }) ``` @@ -42,11 +36,6 @@ tests:
    ```js -/** - Backend challenges don't need solutions, - because they would need to be tested against a full working project. - Please check our contributing guidelines to learn more. -*/ +// solution required ``` -
    diff --git a/curriculum/challenges/chinese/06-information-security-and-quality-assurance/information-security-with-helmetjs/avoid-inferring-the-response-mime-type-with-helmet.nosniff.chinese.md b/curriculum/challenges/chinese/06-information-security-and-quality-assurance/information-security-with-helmetjs/avoid-inferring-the-response-mime-type-with-helmet.nosniff.chinese.md index a5c0f8eae7f..03c858ad0fb 100644 --- a/curriculum/challenges/chinese/06-information-security-and-quality-assurance/information-security-with-helmetjs/avoid-inferring-the-response-mime-type-with-helmet.nosniff.chinese.md +++ b/curriculum/challenges/chinese/06-information-security-and-quality-assurance/information-security-with-helmetjs/avoid-inferring-the-response-mime-type-with-helmet.nosniff.chinese.md @@ -2,20 +2,15 @@ id: 587d8248367417b2b2512c3a title: Avoid Inferring the Response MIME Type with helmet.noSniff() challengeType: 2 -isHidden: false -forumTopicId: 301574 -localeTitle: 使用 helment.noSniff() 避免推断响应的 MIME 类型 +videoUrl: '' +localeTitle: 避免使用helmet.noSniff()推断响应MIME类型 --- ## Description -
    -温馨提醒,本项目在 这个 Glitch 项目 的基础上进行开发。你也可以从 GitHub 上克隆。 -浏览器可以通过探查 ``content`` 或者 ``MIME`` 头部来判断不同的响应内容。这两个的优先级比 ``Content-Type`` 还高,浏览器可以通过这两个头部来猜测并处理响应。这个在某些情况下非常实用,但也会造成一定的潜在风险。我们可以通过中间件来设置 ``X-Content-Type-Options`` 头部为 ``nosniff``。 这样,浏览器就不会绕过 ``Content-Type`` 这个头了。 -
    +
    提醒一下,这个项目是基于Glitch的以下入门项目构建的,或者是从GitHub克隆的。浏览器可以使用内容或MIME嗅探来适应来自响应的不同数据类型。它们覆盖Content-Type标头以猜测和处理数据。虽然这在某些情况下可能很方便,但它也可能导致一些危险的攻击。此中间件将X-Content-Type-Options标头设置为nosniff。这指示浏览器不绕过提供的Content-Type。
    ## Instructions -
    - +
    ## Tests @@ -23,7 +18,7 @@ localeTitle: 使用 helment.noSniff() 避免推断响应的 MIME 类型 ```yml tests: - - text: helmet.noSniff() 中间件应该被正确加载 + - text: helmet.noSniff()中间件应该正确安装 testString: getUserInput => $.get(getUserInput('url') + '/_api/app-info').then(data => { assert.include(data.appStack, 'nosniff'); assert.equal(data.headers['x-content-type-options'], 'nosniff'); }, xhr => { throw new Error(xhr.responseText); }) ``` @@ -39,11 +34,6 @@ tests:
    ```js -/** - Backend challenges don't need solutions, - because they would need to be tested against a full working project. - Please check our contributing guidelines to learn more. -*/ +// solution required ``` -
    diff --git a/curriculum/challenges/chinese/06-information-security-and-quality-assurance/information-security-with-helmetjs/configure-helmet-using-the-parent-helmet-middleware.chinese.md b/curriculum/challenges/chinese/06-information-security-and-quality-assurance/information-security-with-helmetjs/configure-helmet-using-the-parent-helmet-middleware.chinese.md index dc9a9b649e9..17fdc239d81 100644 --- a/curriculum/challenges/chinese/06-information-security-and-quality-assurance/information-security-with-helmetjs/configure-helmet-using-the-parent-helmet-middleware.chinese.md +++ b/curriculum/challenges/chinese/06-information-security-and-quality-assurance/information-security-with-helmetjs/configure-helmet-using-the-parent-helmet-middleware.chinese.md @@ -2,38 +2,15 @@ id: 587d8249367417b2b2512c40 title: Configure Helmet Using the ‘parent’ helmet() Middleware challengeType: 2 -isHidden: false -forumTopicId: 301575 -localeTitle: 使用 helmet() 中间件来配置 Helmet +videoUrl: '' +localeTitle: 配置头盔使用“父”头盔()中间件 --- ## Description -
    -温馨提醒,本项目在 这个 Glitch 项目 的基础上进行开发。你也可以从 GitHub 上克隆。 -app.use(helmet()) 会自动加载除 noCache() 和 contentSecurityPolicy() 外上面所有提到的中间件,但有需要的话这两个中间件也被启用。你也可以使用配置对象来一个个地禁用或者配置中间件。 -

    例子:

    - -```js -app.use(helmet({ - frameguard: { // configure - action: 'deny' - }, - contentSecurityPolicy: { // enable and configure - directives: { - defaultSrc: ["self"], - styleSrc: ['style.com'], - } - }, - dnsPrefetchControl: false // disable -})) -``` - -为了教学和方便测试我们是一个个地讲解中间件,但通过使用 ‘parent’ helmet() 是最清晰和简洁的,特别是在真实的项目中。 -
    +
    提醒一下,这个项目是基于Glitch的以下入门项目构建的,或者是从GitHub克隆的。 app.use(helmet())将自动包含上面介绍的所有中间件,noCache()和contentSecurityPolicy()除外,但如果需要,可以启用这些中间件。您还可以使用配置对象单独禁用或配置任何其他中间件。 //示例app.use(helmet({ frameguard: { // configure action: 'deny' }, contentSecurityPolicy: { // enable and configure directives: { defaultSrc: ["self"], styleSrc: ['style.com'], } }, dnsPrefetchControl: false // disable }))我们分别为教学目的引入了每个中间件,并且易于测试。使用“父”头盔()中间件对于真实项目来说是最简单,更清洁的。
    ## Instructions -
    - +
    ## Tests @@ -41,7 +18,7 @@ app.use(helmet({ ```yml tests: - - text: 没有测试 - 这是一个介绍关卡 + - text: 没有测试 - 这是一个描述性的挑战 testString: assert(true) ``` @@ -57,11 +34,6 @@ tests:
    ```js -/** - Backend challenges don't need solutions, - because they would need to be tested against a full working project. - Please check our contributing guidelines to learn more. -*/ +// solution required ``` -
    diff --git a/curriculum/challenges/chinese/06-information-security-and-quality-assurance/information-security-with-helmetjs/disable-client-side-caching-with-helmet.nocache.chinese.md b/curriculum/challenges/chinese/06-information-security-and-quality-assurance/information-security-with-helmetjs/disable-client-side-caching-with-helmet.nocache.chinese.md index d6bf830852b..0c2229e2a5d 100644 --- a/curriculum/challenges/chinese/06-information-security-and-quality-assurance/information-security-with-helmetjs/disable-client-side-caching-with-helmet.nocache.chinese.md +++ b/curriculum/challenges/chinese/06-information-security-and-quality-assurance/information-security-with-helmetjs/disable-client-side-caching-with-helmet.nocache.chinese.md @@ -2,20 +2,15 @@ id: 587d8249367417b2b2512c3e title: Disable Client-Side Caching with helmet.noCache() challengeType: 2 -isHidden: false -forumTopicId: 301576 -localeTitle: 使用 helment.noCache() 禁用客户端缓存 +videoUrl: '' +localeTitle: 使用helmet.noCache()禁用客户端缓存 --- ## Description -
    -温馨提醒,本项目在 这个 Glitch 项目 的基础上进行开发。你也可以从 GitHub 上克隆。 -如果你为你的网站发布了一个更新,你想要用户永远使用最新的版本。你可以通过禁用浏览器的缓存来实现。这个功能在开发环境中也非常有用。当然你会失去缓存在性能上的优势,所以你应该在真正有必要的时候才用这个功能 -
    +
    提醒一下,这个项目是基于Glitch的以下入门项目构建的,或者是从GitHub克隆的。如果您要为您的网站发布更新,并且您希望用户始终下载较新的版本,您可以(尝试)在客户端的浏览器上禁用缓存。它在开发中也很有用。缓存具有性能优势,您将失去这些优势,因此只有在真正需要时才使用此选项。
    ## Instructions -
    - +
    ## Tests @@ -23,7 +18,7 @@ localeTitle: 使用 helment.noCache() 禁用客户端缓存 ```yml tests: - - text: helmet.noCache() 中间件应该被正确加载 + - text: 应该正确安装helmet.noCache()中间件 testString: getUserInput => $.get(getUserInput('url') + '/_api/app-info').then(data => { assert.include(data.appStack, 'nocache'); assert.equal(data.headers['cache-control'], 'no-store, no-cache, must-revalidate, proxy-revalidate'); }, xhr => { throw new Error(xhr.responseText); }) ``` @@ -39,11 +34,6 @@ tests:
    ```js -/** - Backend challenges don't need solutions, - because they would need to be tested against a full working project. - Please check our contributing guidelines to learn more. -*/ +// solution required ``` -
    diff --git a/curriculum/challenges/chinese/06-information-security-and-quality-assurance/information-security-with-helmetjs/disable-dns-prefetching-with-helmet.dnsprefetchcontrol.chinese.md b/curriculum/challenges/chinese/06-information-security-and-quality-assurance/information-security-with-helmetjs/disable-dns-prefetching-with-helmet.dnsprefetchcontrol.chinese.md index 489f7d7df60..e9879b8aa40 100644 --- a/curriculum/challenges/chinese/06-information-security-and-quality-assurance/information-security-with-helmetjs/disable-dns-prefetching-with-helmet.dnsprefetchcontrol.chinese.md +++ b/curriculum/challenges/chinese/06-information-security-and-quality-assurance/information-security-with-helmetjs/disable-dns-prefetching-with-helmet.dnsprefetchcontrol.chinese.md @@ -2,20 +2,15 @@ id: 587d8248367417b2b2512c3d title: Disable DNS Prefetching with helmet.dnsPrefetchControl() challengeType: 2 -isHidden: false -forumTopicId: 301577 -localeTitle: 使用 helmet.dnsPrefetchControl() 禁用 DNS 预取 +videoUrl: '' +localeTitle: 使用helmet.dnsPrefetchControl()禁用DNS预取 --- ## Description -
    -温馨提醒,本项目在 这个 Glitch 项目 的基础上进行开发。你也可以从 GitHub 上克隆。 -为了提高性能,大部分浏览器都会为页面上的链接预先加载 DNS 记录。这样当用户点击一个链接的时候浏览器已经提前知道 IP 地址了。但这也会造成 DNS 服务的过度使用(如果你是一个大型网站,有这千万级的用户的情况下),隐私问题 (窃听者可以推测出你在哪个页面上),和页面数据准确性(有些没访问过的链接会被标记成已访问)。如果你对安全性要求比较高,你应该禁用 DNZ 预加载。当然,这样做性能上会有一点点损失. -
    +
    提醒一下,这个项目是基于Glitch的以下入门项目构建的,或者是从GitHub克隆的。为了提高性能,大多数浏览器都会为页面中的链接预取DNS记录。以这种方式,当用户点击链接时,目标IP已知。这可能导致过度使用DNS服务(如果您拥有一个大网站,数百万人访问......),隐私问题(一个窃听者可能会推断您在某个页面上),或者页面统计信息更改(某些链接可能会即使他们不是,也会出现。)如果您有高安全性需求,则可以以性能损失为代价禁用DNS预取。
    ## Instructions -
    - +
    ## Tests @@ -23,7 +18,7 @@ localeTitle: 使用 helmet.dnsPrefetchControl() 禁用 DNS 预取 ```yml tests: - - text: helmet.dnsPrefetchControl() 中间件应该被正确加载 + - text: 应该正确安装helmet.dnsPrefetchControl()中间件 testString: getUserInput => $.get(getUserInput('url') + '/_api/app-info').then(data => { assert.include(data.appStack, 'dnsPrefetchControl'); assert.equal(data.headers['x-dns-prefetch-control'], 'off'); }, xhr => { throw new Error(xhr.responseText); }) ``` @@ -39,11 +34,6 @@ tests:
    ```js -/** - Backend challenges don't need solutions, - because they would need to be tested against a full working project. - Please check our contributing guidelines to learn more. -*/ +// solution required ``` -
    diff --git a/curriculum/challenges/chinese/06-information-security-and-quality-assurance/information-security-with-helmetjs/hash-and-compare-passwords-asynchronously.chinese.md b/curriculum/challenges/chinese/06-information-security-and-quality-assurance/information-security-with-helmetjs/hash-and-compare-passwords-asynchronously.chinese.md index 2c74d6b65c6..02a4873368c 100644 --- a/curriculum/challenges/chinese/06-information-security-and-quality-assurance/information-security-with-helmetjs/hash-and-compare-passwords-asynchronously.chinese.md +++ b/curriculum/challenges/chinese/06-information-security-and-quality-assurance/information-security-with-helmetjs/hash-and-compare-passwords-asynchronously.chinese.md @@ -2,48 +2,20 @@ id: 58a25bcff9fc0f352b528e7d title: Hash and Compare Passwords Asynchronously challengeType: 2 -isHidden: false -localeTitle: 异步哈希和比较密码 +videoUrl: '' +localeTitle: 哈希和异步比较密码 --- ## Description -
    -温馨提醒,本项目在 这个 Glitch 项目 的基础上进行开发。你也可以从 GitHub 上克隆。 -哈希会占用很大计算机资源并且会耗费比较多时间,比较推荐的做法是用异步的方法用调用哈希算法这样就不会阻挡其他的访问了。异步调用哈希方法非常简单,只需要 bcrypt.hash(myPlaintextPassword, saltRounds, (err, hash) => { /*Store hash in your db*/ }); - -```js -bcrypt.hash(myPlaintextPassword, saltRounds, (err, hash) => { - /*Store hash in your db*/ -}); -``` - -
    +
    提醒一下,这个项目是基于Glitch的以下入门项目构建的,或者是从GitHub克隆的。由于散列设计为计算密集型,因此建议在服务器上异步执行此操作,以避免在散列时阻止传入连接。所有你需要做的就是异步散列密码是调用bcrypt.hash(myPlaintextPassword, saltRounds, (err, hash) => { /*Store hash in your db*/ });
    将此散列函数添加到服务器(我们已经定义了函数中使用的变量供您使用)并将其记录到控制台以供您查看!此时,您通常会将哈希值保存到数据库中。现在,当您需要确定新输入是否与散列相同时,您只需使用比较函数bcrypt.compare(myPlaintextPassword, hash, (err, res) => { /*res == true or false*/ }); 。在记录完成的哈希并将“res”记录到比较中的控制台之后,将其添加到现有哈希函数中(因为您需要在调用比较函数之前等待哈希完成)。您应该在控制台中看到一个哈希值,然后打印出“true”!如果您将compare函数中的'myPlaintextPassword'更改为'someOtherPlaintextPassword',那么它应该为false。
     bcrypt.hash('passw0rd!',13,(错误,哈希)=> {
    +  的console.log(散列); //$2a$12$Y.PHPE15wR25qrrtgGkiYe2sXo98cjuMCG1YwSI5rJW1DSJp0gEYS
    +  bcrypt.compare('passw0rd!',hash,(err,res)=> {
    +      的console.log(RES); //真正
    +  });
    +}); 
    当您认为自己已经做对时,请提交您的页面。
    ## Instructions -
    -把这段哈希方法添加到你的服务器(我们已经定义好这个方法的变量给你直接使用了) 然后输入到控制台! 完成之后你通常需要把哈希过的值保存到数据库。 -当你需要对比用户输入的值是否和之前哈希过的值一样的时候,你只需要调用对比函数 bcrypt.compare(myPlaintextPassword, hash, (err, res) => { /*res == true or false*/ });. 把这个添加到你已有的哈希方法(你需要等哈希完成之后才能调用对比方法) 在你输入哈希过的值之后在对比方法里面输入 'res' 到控制台. 你会看到一个哈希值和 ``true`` 被打印出来。如果你在对比方法里面把 'myPlaintextPassword' 改变成 'someOtherPlaintextPassword' 那么应该会输出 ``false`` - -```js -bcrypt.compare(myPlaintextPassword, hash, (err, res) => { - /*res == true or false*/ -}); -``` - -当控制台打印哈希完成并且在对比的 console 里打印 ‘res’ 后,将其添加到现有的哈希函数中(因为要等待哈希完成才能调用 compare 函数)。 控制台中应该打印一个哈希,然后打印 “true”! 如果将比较函数中的 “myPlaintextPassword” 更改为 “someOtherPlaintextPassword”,则它应该显示为false。 - -```js -bcrypt.hash('passw0rd!', 13, (err, hash) => { - console.log(hash); - //$2a$12$Y.PHPE15wR25qrrtgGkiYe2sXo98cjuMCG1YwSI5rJW1DSJp0gEYS - bcrypt.compare('passw0rd!', hash, (err, res) => { - console.log(res); //true - }); -}); - -``` - -提交页面当你觉得已经完成的时候。 +
    ## Tests @@ -51,7 +23,7 @@ bcrypt.hash('passw0rd!', 13, (err, hash) => { ```yml tests: - - text: 异步生成哈希并正确地对比 + - text: 异步哈希生成并正确比较 testString: getUserInput => $.get(getUserInput('url')+ '/_api/server.js') .then(data => { assert.match(data, /START_ASYNC[^]*bcrypt.hash.*myPlaintextPassword( |),( |)saltRounds( |),( |).*err( |),( |)hash[^]*END_ASYNC/gi, 'You should call bcrypt.hash on myPlaintextPassword and saltRounds and handle err and hash as a result in the callback'); assert.match(data, /START_ASYNC[^]*bcrypt.hash[^]*bcrypt.compare.*myPlaintextPassword( |),( |)hash( |),( |).*err( |),( |)res[^]*}[^]*}[^]*END_ASYNC/gi, 'Nested within the hash function should be the compare function comparing myPlaintextPassword to hash'); }, xhr => { throw new Error(xhr.statusText); }) ``` @@ -67,11 +39,6 @@ tests:
    ```js -/** - Backend challenges don't need solutions, - because they would need to be tested against a full working project. - Please check our contributing guidelines to learn more. -*/ +// solution required ``` -
    diff --git a/curriculum/challenges/chinese/06-information-security-and-quality-assurance/information-security-with-helmetjs/hash-and-compare-passwords-synchronously.chinese.md b/curriculum/challenges/chinese/06-information-security-and-quality-assurance/information-security-with-helmetjs/hash-and-compare-passwords-synchronously.chinese.md index 2eb9eb6a31c..825fdda6c6b 100644 --- a/curriculum/challenges/chinese/06-information-security-and-quality-assurance/information-security-with-helmetjs/hash-and-compare-passwords-synchronously.chinese.md +++ b/curriculum/challenges/chinese/06-information-security-and-quality-assurance/information-security-with-helmetjs/hash-and-compare-passwords-synchronously.chinese.md @@ -2,34 +2,15 @@ id: 58a25bcff9fc0f352b528e7e title: Hash and Compare Passwords Synchronously challengeType: 2 -isHidden: false -forumTopicId: 301579 -localeTitle: 同步哈希和比较密码 +videoUrl: '' +localeTitle: 哈希并同步比较密码 --- ## Description -
    -温馨提醒,本项目在 这个 Glitch 项目 的基础上进行开发。你也可以从 GitHub 上克隆。 -同步哈希也是非常简单的,但是会造成延迟特别是在哈希计算量大并且次数多的情况下。同步进行哈希是通过调用 - -```js -var hash = bcrypt.hashSync(myPlaintextPassword, saltRounds); -``` - -
    把同步哈希添加到你的代码并输入到控制台,和之前一样,需要用到的变量已经提前定义好,你不需要做任何改动。你可能已经注意到,即使你是用异步的方式哈希同一个密码,结果也是不一样的。这是因为每次哈希的盐都是随机生成的,你可以通过第三个哈希字符串的头22的字符来验证。 -当你需要对比用户输入的值, 你只需要使用 compareSync 方法: - -```js -var result = bcrypt.compareSync(myPlaintextPassword, hash); -``` - -返回的结果为 ``true`` 或者 ``false``。 -
    +
    提醒一下,这个项目是基于Glitch的以下入门项目构建的,或者是从GitHub克隆的。同步散列也很容易,但如果使用服务器端成本高或经常进行散列会导致延迟。使用此方法进行散列与调用var hash = bcrypt.hashSync(myPlaintextPassword, saltRounds);
    将此散列方法添加到代码中,然后将结果记录到控制台。同样,使用的变量已在服务器中定义,因此您无需调整它们。您可能会注意到即使您使用与异步函数相同的密码进行哈希处理,控制台中的结果也不同 - 这是由于每次哈希值随机生成,如第三个哈希字符串中的前22个字符所示。现在将密码输入与新的同步散列进行比较,您将使用compareSync方法: var result = bcrypt.compareSync(myPlaintextPassword, hash);结果是布尔值true或false。添加此功能并登录控制台结果以查看其是否正常工作。当您认为自己已经做对时,请提交您的页面。如果您在这些挑战期间遇到错误,可以在此处查看示例完成的代码。
    ## Instructions -
    -添加这个方法并输出把控制台来验证同步哈希已经成功了。 -提交页面当你觉得已经完成的时候。如果你遇到任何错误,你可以参考这个链接中已经完成的代码。 +
    ## Tests @@ -37,7 +18,7 @@ var result = bcrypt.compareSync(myPlaintextPassword, hash); ```yml tests: - - text: 同步生成哈希并正确地对比 + - text: 同步哈希生成并正确比较 testString: getUserInput => $.get(getUserInput('url')+ '/_api/server.js') .then(data => { assert.match(data, /START_SYNC[^]*hash.*=.*bcrypt.hashSync.*myPlaintextPassword( |),( |)saltRounds[^]*END_SYNC/gi, 'You should call bcrypt.hashSync on myPlaintextPassword with saltRounds'); assert.match(data, /START_SYNC[^]*result.*=.*bcrypt.compareSync.*myPlaintextPassword( |),( |)hash[^]*END_SYNC/gi, 'You should call bcrypt.compareSync on myPlaintextPassword with the hash generated in the last line'); }, xhr => { throw new Error(xhr.statusText); }) ``` @@ -53,11 +34,6 @@ tests:
    ```js -/** - Backend challenges don't need solutions, - because they would need to be tested against a full working project. - Please check our contributing guidelines to learn more. -*/ +// solution required ``` -
    diff --git a/curriculum/challenges/chinese/06-information-security-and-quality-assurance/information-security-with-helmetjs/hide-potentially-dangerous-information-using-helmet.hidepoweredby.chinese.md b/curriculum/challenges/chinese/06-information-security-and-quality-assurance/information-security-with-helmetjs/hide-potentially-dangerous-information-using-helmet.hidepoweredby.chinese.md index 0f37ccc7979..c9b02d4992a 100644 --- a/curriculum/challenges/chinese/06-information-security-and-quality-assurance/information-security-with-helmetjs/hide-potentially-dangerous-information-using-helmet.hidepoweredby.chinese.md +++ b/curriculum/challenges/chinese/06-information-security-and-quality-assurance/information-security-with-helmetjs/hide-potentially-dangerous-information-using-helmet.hidepoweredby.chinese.md @@ -2,20 +2,15 @@ id: 587d8247367417b2b2512c37 title: Hide Potentially Dangerous Information Using helmet.hidePoweredBy() challengeType: 2 -isHidden: false -forumTopicId: 301580 -localeTitle: 使用 helmet.hidePoweredBy() 隐藏潜在的危险信息 +videoUrl: '' +localeTitle: 使用helmet.hidePoweredBy()隐藏潜在的危险信息 --- ## Description -
    -温馨提醒,本项目在 这个 Glitch 项目 的基础上进行开发。你也可以从 GitHub 上克隆。 -如果黑客发现你的网站是用 Express 搭建的,那么他们就可以利用 Express 或 Node 现存的漏洞来攻击你的网站。X-Powered-By: Express 默认情况下会被添加到所有响应的头部。不过 helmet.hidePoweredBy() 中间件可以帮你移除 X-Powered-By 头。你甚至可以把头设置成其它的值。 如 app.use(helmet.hidePoweredBy({ setTo: 'PHP 4.2.0' })) -
    +
    提醒一下,这个项目是基于Glitch的以下入门项目构建的,或者是从GitHub克隆的。如果黑客看到您的网站由Express提供支持,他们可以利用Express / Node中的已知漏洞。 X-Powered-By:Express默认发送来自Express的每个请求。 helmet.hidePoweredBy()中间件将删除X-Powered-By标头。您还可以将标头显式设置为其他内容,以便让人们离开。例如app.use(helmet.hidePoweredBy({setTo:'PHP 4.2.0'}))
    ## Instructions -
    - +
    ## Tests @@ -23,7 +18,7 @@ localeTitle: 使用 helmet.hidePoweredBy() 隐藏潜在的危险信息 ```yml tests: - - text: helmet.hidePoweredBy() 中间件应该被正确加载 + - text: helmet.hidePoweredBy()中间件应正确安装 testString: getUserInput => $.get(getUserInput('url') + '/_api/app-info').then(data => { assert.include(data.appStack, 'hidePoweredBy'); assert.notEqual(data.headers['x-powered-by'], 'Express')}, xhr => { throw new Error(xhr.responseText); }) ``` @@ -39,11 +34,6 @@ tests:
    ```js -/** - Backend challenges don't need solutions, - because they would need to be tested against a full working project. - Please check our contributing guidelines to learn more. -*/ +// solution required ``` -
    diff --git a/curriculum/challenges/chinese/06-information-security-and-quality-assurance/information-security-with-helmetjs/install-and-require-helmet.chinese.md b/curriculum/challenges/chinese/06-information-security-and-quality-assurance/information-security-with-helmetjs/install-and-require-helmet.chinese.md index 68ae944234f..ed6e1a38f7d 100644 --- a/curriculum/challenges/chinese/06-information-security-and-quality-assurance/information-security-with-helmetjs/install-and-require-helmet.chinese.md +++ b/curriculum/challenges/chinese/06-information-security-and-quality-assurance/information-security-with-helmetjs/install-and-require-helmet.chinese.md @@ -2,20 +2,15 @@ id: 587d8247367417b2b2512c36 title: Install and Require Helmet challengeType: 2 -isHidden: false -forumTopicId: 301581 -localeTitle: 安装和引入 Helmet +videoUrl: '' +localeTitle: 安装并需要头盔 --- ## Description -
    -注意,本项目在 这个 Glitch 项目 的基础上进行开发。你也可以从 GitHub 上克隆。 -Helmet 通过配置不同的 HTTP 头部信息来使你的 Express 应用更加安全。 -
    +
    提醒一下,这个项目是基于Glitch的以下入门项目构建的,或者是从GitHub克隆的。 Helmet通过设置各种HTTP标头来帮助您保护Express应用程序。安装包,然后需要它。
    ## Instructions -
    -安装,并引入 Helmet 这个包。 +
    ## Tests @@ -23,7 +18,7 @@ Helmet 通过配置不同的 HTTP 头部信息来使你的 Express 应用更加 ```yml tests: - - text: "package.json 文件应该有 'helmet' 这个依赖包" + - text: “helmet”依赖应该在package.json中 testString: getUserInput => $.get(getUserInput('url') + '/_api/package.json').then(data => { var packJson = JSON.parse(data); assert.property(packJson.dependencies, 'helmet'); }, xhr => { throw new Error(xhr.responseText); }) ``` @@ -39,11 +34,6 @@ tests:
    ```js -/** - Backend challenges don't need solutions, - because they would need to be tested against a full working project. - Please check our contributing guidelines to learn more. -*/ +// solution required ``` -
    diff --git a/curriculum/challenges/chinese/06-information-security-and-quality-assurance/information-security-with-helmetjs/mitigate-the-risk-of-clickjacking-with-helmet.frameguard.chinese.md b/curriculum/challenges/chinese/06-information-security-and-quality-assurance/information-security-with-helmetjs/mitigate-the-risk-of-clickjacking-with-helmet.frameguard.chinese.md index 591b582b64a..41c3cc79250 100644 --- a/curriculum/challenges/chinese/06-information-security-and-quality-assurance/information-security-with-helmetjs/mitigate-the-risk-of-clickjacking-with-helmet.frameguard.chinese.md +++ b/curriculum/challenges/chinese/06-information-security-and-quality-assurance/information-security-with-helmetjs/mitigate-the-risk-of-clickjacking-with-helmet.frameguard.chinese.md @@ -2,21 +2,15 @@ id: 587d8247367417b2b2512c38 title: Mitigate the Risk of Clickjacking with helmet.frameguard() challengeType: 2 -isHidden: false -forumTopicId: 301582 -localeTitle: 使用 helmet.frameguard() 降低点击劫持的风险 +videoUrl: '' +localeTitle: 使用helmet.frameguard()降低点击劫持的风险 --- ## Description -
    -温馨提醒,本项目在 这个 Glitch 项目 的基础上进行开发。你也可以从 GitHub 上克隆。 -黑客可能会不经过你的允许,把你的页面嵌套在 或者