fix(i18n): update Chinese translation of advanced node and express (#38946)
This commit is contained in:
@ -2,24 +2,38 @@
|
||||
id: 589fc832f9fc0f352b528e78
|
||||
title: Announce New Users
|
||||
challengeType: 2
|
||||
videoUrl: ''
|
||||
localeTitle: 宣布新用户
|
||||
isHidden: false
|
||||
forumTopicId: 301546
|
||||
localeTitle: 用户公告
|
||||
---
|
||||
|
||||
## Description
|
||||
<section id="description">提醒一下,这个项目是基于<a href="https://glitch.com/#!/import/github/freeCodeCamp/boilerplate-socketio/">Glitch</a>的以下入门项目构建的,或者是从<a href="https://github.com/freeCodeCamp/boilerplate-socketio/">GitHub</a>克隆的。许多聊天室能够在用户连接或断开连接时进行通知,然后将其显示给聊天中的所有连接用户。看起来您已经在连接和断开连接上发出事件,您只需修改此事件即可支持此功能。最合乎逻辑的方法是使用事件发送3个数据:连接/断开用户的名称,当前用户计数以及连接或断开连接的名称。 <hr>将事件名称更改为“user”,并且数据传递一个对象,包含字段'name','currentUsers'和boolean'connected'(如果是连接则为true,对于断开发送的用户,则为false)。确保对我们有'用户计数'事件的两个点进行更改,并将断开连接设置为对'field'字段发送false,而不是像在connect上发出的事件那样为true。 <code>io.emit('user', {name: socket.request.user.name, currentUsers, connected: true});</code>现在,您的客户端将拥有所有必要信息,以便在用户连接或断开连接时正确显示当前用户数和通知!要在客户端处理此事件,我们应该监听“用户”,然后使用jQuery将<code>#num-users</code>的文本更改为“{NUMBER}在线用户”,并附加<code><li></code> ,以更新当前用户数<code><li></code>使用ID为'messages'的无序列表,其中'{NAME}已{加/左}聊天。'。此实现可能如下所示: <pre> socket.on('user',function(data){
|
||||
$('#num-users')。text(data.currentUsers +'users online');
|
||||
<section id='description'>
|
||||
注意,本项目在<a href='https://glitch.com/#!/import/github/freeCodeCamp/boilerplate-socketio/'>这个 Glitch 项目</a>的基础上进行开发,你也可以从 <a href='https://github.com/freeCodeCamp/boilerplate-socialauth/'>GitHub</a> 上克隆。
|
||||
许多聊天室都有这个功能:所有已连接到服务器的在线用户都会看到有人加入或退出的提醒。我们已经写好了处理连接和断开事件的代码,只要对这个方法稍作修改就可以实现这个功能。在事件中,我们需要发送这三条信息:连接或断开的用户名、当前用户数量、事件类型(即需要知道用户究竟是连接还是断开)。
|
||||
<hr>请将事件名称更改为 'user',其中应包含如下字段:'name'、'currentUsers'、'connected'(布尔值,对于连接是 true,断开是 false)。记得要修改之前我们写好的处理 'user count' 的那部分代码,现在我们应传入布尔值:<code>io.emit('user', {name: socket.request.user.name, currentUsers, connected: true});</code>
|
||||
现在,我们的客户端已经有足够的信息显示现有用户数量和发送用户上下线通知。接下来我们需要在客户端监听 'user' 事件,然后使用 jQuery 把<code>#num-users</code>节点的文本内容更新为 '{NUMBER} users online'。同时,我们需要为<code><ul></code>添加一个 id 为 'messages' 且带有 '{NAME} has {joined/left} the chat.' 文本的<code><li></code>:An implementation of this could look like the following:<br>
|
||||
其中一种实现如下:<br>
|
||||
|
||||
```js
|
||||
socket.on('user', function(data){
|
||||
$('#num-users').text(data.currentUsers+' users online');
|
||||
var message = data.name;
|
||||
if(data.connected){
|
||||
消息+ ='已加入聊天。';
|
||||
if(data.connected) {
|
||||
message += ' has joined the chat.';
|
||||
} else {
|
||||
消息+ ='离开了聊天。';
|
||||
message += ' has left the chat.';
|
||||
}
|
||||
$('#messages')。append($('<li>')。html('<b>'+ message +'<\ / b>'));
|
||||
}); </pre>当您认为自己已经做对时,请提交您的页面。 </section>
|
||||
$('#messages').append($('<li>').html('<b>'+ message +'<\/b>'));
|
||||
});
|
||||
```
|
||||
|
||||
完成上述要求后,你就可以在左边提交你的页面链接。
|
||||
</section>
|
||||
|
||||
## Instructions
|
||||
<section id="instructions">
|
||||
<section id='instructions'>
|
||||
|
||||
</section>
|
||||
|
||||
## Tests
|
||||
@ -27,9 +41,9 @@ localeTitle: 宣布新用户
|
||||
|
||||
```yml
|
||||
tests:
|
||||
- text: 使用name,currentUsers和connected发出事件“user”
|
||||
- text: user 事件应发送包含 name、currentUsers、connected 字段的对象。
|
||||
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: 客户正确处理和显示事件'用户'中的新数据
|
||||
- text: '客户端应处理和显示 "user" 对象中的信息。'
|
||||
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); })"
|
||||
|
||||
```
|
||||
@ -45,6 +59,11 @@ tests:
|
||||
<section id='solution'>
|
||||
|
||||
```js
|
||||
// solution required
|
||||
/**
|
||||
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.
|
||||
*/
|
||||
```
|
||||
|
||||
</section>
|
||||
|
@ -2,25 +2,40 @@
|
||||
id: 5895f70df9fc0f352b528e68
|
||||
title: Authentication Strategies
|
||||
challengeType: 2
|
||||
videoUrl: ''
|
||||
localeTitle: 认证策略
|
||||
isHidden: false
|
||||
forumTopicId: 301547
|
||||
localeTitle: 身份验证策略
|
||||
---
|
||||
|
||||
## Description
|
||||
<section id="description">提醒一下,这个项目是基于<a href="https://glitch.com/#!/import/github/freeCodeCamp/boilerplate-advancednode/">Glitch</a>的以下入门项目构建的,或者是从<a href="https://github.com/freeCodeCamp/boilerplate-advancednode/">GitHub</a>克隆的。策略是一种验证用户的方法。您可以使用策略允许用户根据本地保存的信息(如果您首先注册)或从Google或Github等各种提供商进行身份验证。对于这个项目,我们将制定一个本地战略。要查看的策略100的列表,请访问网站护照<a href="http://passportjs.org/">这里</a> 。将<em>passport-local</em>添加为依赖项并将其添加到服务器,如下所示: <code>const LocalStrategy = require('passport-local');</code>现在,您必须告诉护照<b>使用</b>实例化的LocalStartegy对象,并定义一些设置。确保这一点以及此时的所有内容都封装在数据库连接中,因为它依赖于它! <pre> 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);
|
||||
});
|
||||
<section id='description'>
|
||||
注意,本项目在<a href='https://glitch.com/#!/import/github/freeCodeCamp/boilerplate-advancednode/'>这个 Glitch 项目</a>的基础上进行开发,你也可以从 <a href='https://github.com/freeCodeCamp/boilerplate-advancednode/'>GitHub</a> 上克隆。
|
||||
现在,我们需要构建验证用户的策略,策略的选择有很多。比如,如果我们已经让用户在注册时填写了用户信息,那我们就可以基于这些信息验证;或者也可以引入第三方登录,如 Google 或者 Github。为此,你可以参考 <a href='http://passportjs.org/'>Passports 中提供的策略插件</a>。对于这个项目的验证策略,我们会采用自己搭建的方式完成。
|
||||
首先,我们需要引入 <em>passport-local</em> 作为依赖,然后将它添加到服务器,就像这样:<code>const LocalStrategy = require('passport-local');</code>
|
||||
然后,我们需要让 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);
|
||||
});
|
||||
}
|
||||
)); </pre>这是我们尝试在本地验证某人时要采取的过程。首先,它尝试使用输入的用户名在我们的数据库中查找用户,然后检查要匹配的密码,最后如果没有弹出我们检查过的错误,如错误的密码,则返回用户对象,它们是认证。许多策略都是使用不同的设置设置的,一般来说,根据该策略库中的README很容易设置它。一个很好的例子是Github策略,我们不需要担心用户名或密码,因为用户将被发送到Github的auth页面进行身份验证,只要他们登录并同意,然后Github返回他们的个人资料我们用。在下一步中,我们将设置如何实际调用身份验证策略以根据表单数据验证用户!如果您认为自己已经完成了这一点,请提交您的页面。 </section>
|
||||
));
|
||||
```
|
||||
|
||||
这就是我们的用户验证逻辑:首先根据用户输入的用户名在数据库中寻找用户;然后检查密码是否匹配;最后如果没有发生错误,那么就会返回用户对象并通过验证。
|
||||
我们也可以采用上面链接中提供的验证策略,一般来说,根据该策略仓库中的 README 来进行配置就足够了。一个很好的例子是 Github 策略,在该策略中,我们不需要写用户名或密码的相关验证逻辑,因为用户将被引导到 Github 页面进行验证。只要他们登录并同意,Github 就会返回他们的个人信息供我们使用。
|
||||
以上就是本次挑战的内容。在下一个挑战中,我们会基于表单数据调用上面写好的验证策略。完成上述要求后,你就可以在左边提交你的页面链接。
|
||||
</section>
|
||||
|
||||
## Instructions
|
||||
<section id="instructions">
|
||||
<section id='instructions'>
|
||||
|
||||
</section>
|
||||
|
||||
## Tests
|
||||
@ -28,9 +43,9 @@ localeTitle: 认证策略
|
||||
|
||||
```yml
|
||||
tests:
|
||||
- text: Passport-local是一种依赖
|
||||
- text: 你的项目需要使用<code>passport-local</code>作为依赖。
|
||||
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: 应正确地引入和设置<code>passport-local</code>。
|
||||
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); })
|
||||
|
||||
```
|
||||
@ -46,6 +61,11 @@ tests:
|
||||
<section id='solution'>
|
||||
|
||||
```js
|
||||
// solution required
|
||||
/**
|
||||
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.
|
||||
*/
|
||||
```
|
||||
|
||||
</section>
|
||||
|
@ -2,20 +2,35 @@
|
||||
id: 589fc831f9fc0f352b528e77
|
||||
title: Authentication with Socket.IO
|
||||
challengeType: 2
|
||||
videoUrl: ''
|
||||
localeTitle: 使用Socket.IO进行身份验证
|
||||
isHidden: false
|
||||
forumTopicId: 301548
|
||||
localeTitle: 用 Socket.IO 进行身份验证
|
||||
---
|
||||
|
||||
## Description
|
||||
<section id="description">提醒一下,这个项目是基于<a href="https://glitch.com/#!/import/github/freeCodeCamp/boilerplate-socketio/">Glitch</a>的以下入门项目构建的,或者是从<a href="https://github.com/freeCodeCamp/boilerplate-socketio/">GitHub</a>克隆的。目前,您无法确定谁连接到您的Web套接字。虽然'req.user'对用户对象进行了容器处理,但只有当您的用户与Web服务器进行交互并且使用Web套接字时,您才没有req(请求),因此没有用户数据。解决知道谁连接到您的Web套接字的问题的一种方法是解析和解码包含护照会话的cookie,然后对其进行反序列化以获取用户对象。幸运的是,NPM上有一个包,只是为了将一次复杂的任务变成简单的事情! <hr>将“passport.socketio”添加为依赖项,并将其命名为“passportSocketIo”。现在我们只需要告诉Socket.IO使用它并设置选项。确保在现有套接字代码之前添加它,而不是在现有连接侦听器中添加。对于您的服务器,它应如下所示: <pre> io.use(passportSocketIo.authorize({
|
||||
cookieParser:cookieParser,
|
||||
key:'express.sid',
|
||||
secret:process.env.SESSION_SECRET,
|
||||
store:sessionStore
|
||||
})); </pre>您还可以选择将“成功”和“失败”与在客户端尝试连接时身份验证过程完成后调用的函数一起传递。现在可以在套接字对象上以<code>socket.request.user</code>访问用户对象。例如,现在您可以添加以下内容: <code>console.log('user ' + socket.request.user.name + ' connected');</code>它将登录已连接的服务器控制台!当您认为自己已经做对时,请提交您的页面。如果您遇到错误,可以<a href="https://gist.github.com/JosephLivengood/a9e69ff91337500d5171e29324e1ff35">在此处</a>查看项目。 </section>
|
||||
<section id='description'>
|
||||
注意,本项目在<a href='https://glitch.com/#!/import/github/freeCodeCamp/boilerplate-socketio/'>这个 Glitch 项目</a>的基础上进行开发,你也可以从 <a href='https://github.com/freeCodeCamp/boilerplate-socialauth/'>GitHub</a> 上克隆。
|
||||
目前,我们还无法确定连接到服务器的用户身份。虽然 req.user 包含用户信息,但这个只在用户直接与服务器交互(即不通过 web socket 访问服务器资源)时产正。当我们的用户通过 web socket 与服务器连接时,由于不存在 req 对象,因此我们无法获取用户数据。解决这个问题的方法之一是通过读取和解析请求中包含 passport session 的 cookie,然后反序列化,进而获取用户信息对象。幸运的是,npm 上有可以让这个复杂的流程简单化的库。
|
||||
<hr>添加 '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'。这个函数会在用户尝试连接并完成验证后调用。
|
||||
现在,我们可以通过<code>socket.request.user</code>访问用户数据。例如,现在你在代码中添加以下内容:<code>console.log('user ' + socket.request.user.name + ' connected');</code>。这样我们就可以在服务端的控制台打印出通过 socket 连接到服务器的用户信息。
|
||||
完成上述要求后,你就可以在左边提交你的页面链接。如果运行出错,你可以在 <a href='https://gist.github.com/JosephLivengood/a9e69ff91337500d5171e29324e1ff35'>here</a> 这里检查这个项目的完成代码。
|
||||
</section>
|
||||
|
||||
## Instructions
|
||||
<section id="instructions">
|
||||
<section id='instructions'>
|
||||
|
||||
</section>
|
||||
|
||||
## Tests
|
||||
@ -23,12 +38,12 @@ localeTitle: 使用Socket.IO进行身份验证
|
||||
|
||||
```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\(.+\.authorize\(/gi, '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\(\s*\w+\.authorize\(/, 'You should register "passport.socketio" as socket.io middleware and provide it correct options'); }, xhr => { throw new Error(xhr.statusText); })
|
||||
|
||||
```
|
||||
|
||||
@ -43,6 +58,11 @@ tests:
|
||||
<section id='solution'>
|
||||
|
||||
```js
|
||||
// solution required
|
||||
/**
|
||||
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.
|
||||
*/
|
||||
```
|
||||
|
||||
</section>
|
||||
|
@ -2,16 +2,35 @@
|
||||
id: 589690e6f9fc0f352b528e6e
|
||||
title: Clean Up Your Project with Modules
|
||||
challengeType: 2
|
||||
videoUrl: ''
|
||||
isHidden: false
|
||||
forumTopicId: 301549
|
||||
localeTitle: 使用模块清理项目
|
||||
---
|
||||
|
||||
## Description
|
||||
<section id="description">提醒一下,这个项目是基于<a href="https://glitch.com/#!/import/github/freeCodeCamp/boilerplate-advancednode/">Glitch</a>的以下入门项目构建的,或者是从<a href="https://github.com/freeCodeCamp/boilerplate-advancednode/">GitHub</a>克隆的。现在你拥有的一切都在你的server.js文件中。这可能导致难以管理不易扩展的代码。创建2个新文件:Routes.js和Auth.js两者都应该从以下代码开始: <pre> module.exports = function(app,db){
|
||||
<p> } </p></pre>现在位于服务器文件的顶部,需要这样的文件: <code>const routes = require('./routes.js');</code>在您与数据库建立成功连接之后,实例化它们中的每一个如下: <code>routes(app, db)</code>最后,获取服务器中的所有路由并将它们粘贴到新文件中并从服务器文件中删除它们。也可以使用ensureAuthenticated,因为我们专门为路由创建了中间件功能。您现在必须正确添加所使用的依赖项,例如<code>const passport = require('passport');</code> ,在routes.js文件中导出行的最上方。继续添加它们直到不再存在错误,并且您的服务器文件不再有任何路由!现在在auth.js文件中执行相同的操作,其中包含与身份验证相关的所有内容,例如序列化和本地策略的设置,并从服务器文件中删除它们。确保添加依赖项并在同一位置调用服务器中的<code>auth(app,db)</code> 。确保<code>routes(app, db)</code> <code>auth(app, db)</code>之前有<code>auth(app, db)</code> <code>routes(app, db)</code>因为我们的注册路由取决于发起的护照!恭喜 - 您已经处于Advanced Node和Express的这一部分的末尾,并且有一些漂亮的代码可供展示!当您认为自己已经做对时,请提交您的页面。如果您遇到错误,可以<a href="https://glitch.com/#!/project/delicious-herring">在此处查看</a>已完成项目的示例。 <p></p></section>
|
||||
<section id='description'>
|
||||
注意,本项目在<a href='https://glitch.com/#!/import/github/freeCodeCamp/boilerplate-advancednode/'>这个 Glitch 项目</a>的基础上进行开发,你也可以从 <a href='https://github.com/freeCodeCamp/boilerplate-advancednode/'>GitHub</a> 上克隆。
|
||||
目前,我们把所有的代码都放到了 server.js 文件里,这会导致代码难以维护,且扩展性差。
|
||||
现在让我们来创建两个新文件:routes.js 和 auth.js。
|
||||
在每个文件的开头,我们都需要写上这段代码:
|
||||
|
||||
```js
|
||||
module.exports = function (app, db) {
|
||||
|
||||
}
|
||||
```
|
||||
|
||||
然后,在 server.js 文件的开头,我们需要像这样引入文件:<code>const routes = require('./routes.js');</code>
|
||||
在成功连接数据库之后,我们需要像这样进行实例化:<code>routes(app, db)</code>。
|
||||
最后,我们需要把所有路由相关的代码从 server.js 移动到新文件 routes.js。不要忘了,<code>ensureAuthenticated</code>方法的定义也要移动到新文件中,这个是我们在之前的挑战中,为在路由中判断用户是否已登录创建的函数。然后,我们还需要在 routes.js 文件开头添加所需要的依赖,如:<code>const passport = require('passport');</code>。
|
||||
如果在这些步骤后没有报错,那么恭喜你,你已成功地从 server.js 文件中分离出了路由文件。
|
||||
现在,我们来把 server.js 中与验证相关的代码分离到 auth.js 中,例如序列化,设置验证策略等。请正确添加依赖,并在 server.js 中调用<code>auth(app,db)</code>。另外,由于我们的注册路由依赖 passport,所以我们需要先调用<code>auth(app, db)</code>,再调用<code>routes(app, db)</code>。
|
||||
Node 和 Express 高级课程至此就告一段落了,你可以在此基础上继续优化和完善这个项目。但至少,现在你也有一些可以展示给大家看的代码了。完成上述要求后,你就可以在左边提交你的页面链接。如果运行出错,你可以在 <a href='https://glitch.com/#!/project/delicious-herring'>here</a> 这里检查你的项目完成情况。
|
||||
</section>
|
||||
|
||||
## Instructions
|
||||
<section id="instructions">
|
||||
<section id='instructions'>
|
||||
|
||||
</section>
|
||||
|
||||
## Tests
|
||||
@ -19,7 +38,7 @@ localeTitle: 使用模块清理项目
|
||||
|
||||
```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); })
|
||||
|
||||
```
|
||||
@ -35,6 +54,11 @@ tests:
|
||||
<section id='solution'>
|
||||
|
||||
```js
|
||||
// solution required
|
||||
/**
|
||||
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.
|
||||
*/
|
||||
```
|
||||
|
||||
</section>
|
||||
|
@ -2,17 +2,33 @@
|
||||
id: 589fc831f9fc0f352b528e75
|
||||
title: Communicate by Emitting
|
||||
challengeType: 2
|
||||
videoUrl: ''
|
||||
localeTitle: 通过发射进行沟通
|
||||
isHidden: false
|
||||
forumTopicId: 301550
|
||||
localeTitle: 通过 Emitting 通信
|
||||
---
|
||||
|
||||
## Description
|
||||
<section id="description">提醒一下,这个项目是基于<a href="https://glitch.com/#!/import/github/freeCodeCamp/boilerplate-socketio/">Glitch</a>的以下入门项目构建的,或者是从<a href="https://github.com/freeCodeCamp/boilerplate-socketio/">GitHub</a>克隆的。 <dfn>Emit</dfn>是您将使用的最常见的沟通方式。当您从服务器向'io'发送内容时,会将事件的名称和数据发送到所有连接的套接字。这个概念的一个很好的例子就是每次新用户连接时都会发出连接用户的当前数量! <hr>首先添加一个变量,以便在您当前正在侦听连接之前跟踪用户。 <code>var currentUsers = 0;</code>现在当有人连接时,你应该在发出计数之前递增计数,这样你就可以在连接监听器中添加增量器。 <code>++currentUsers;</code>最后,在递增计数后,您应该发出事件(仍在连接侦听器中)。该事件应命名为“用户计数”,数据应该只是'currentUsers'。 <code>io.emit('user count', currentUsers);</code> <hr>现在,您可以为客户实施一种方式来监听此事件!与在服务器上侦听连接类似,您将使用<em>on</em>关键字。 <pre> socket.on('user count',function(data){
|
||||
的console.log(数据);
|
||||
}); </pre>现在尝试加载您的应用并进行身份验证,您应该在客户端控制台中看到“1”代表当前用户数!尝试加载更多客户端并进行身份验证以查看数量是否上升。当您认为自己已经做对时,请提交您的页面。 </section>
|
||||
<section id='description'>
|
||||
注意,本项目在<a href='https://glitch.com/#!/import/github/freeCodeCamp/boilerplate-socketio/'>这个 Glitch 项目</a>的基础上进行开发,你也可以从 <a href='https://github.com/freeCodeCamp/boilerplate-socialauth/'>GitHub</a> 上克隆。
|
||||
<dfn>Emit</dfn> 是你会用到的,最常见的通信方式。如果我们从服务器发送信息给 'io',就相当于把事件的名称和数据发送给了所有处于连接状态的 socket。我们可以利用这个特性实现这样的功能:只要有新用户连接到服务器,我们就可以把目前连接的总用户数发给所有已连接的用户,这样所有用户随时都可以看到实时的在线人数。
|
||||
<hr>首先,我们需要在监听连接的地方之前添加一个用于追踪用户数的变量:<code>var currentUsers = 0;</code>
|
||||
然后,只要有人连接到服务器,我们需要在发出用户数量之前先给这个变量加 1:<code>++currentUsers;</code>
|
||||
最后,在监听连接的地方发出(emit)该事件即可。这个事件应命名为 'user count',且数据应该为 'currentUsers':<code>io.emit('user count', currentUsers);</code>
|
||||
<hr>接下来,我们还需要让客户端监听从服务端发出的事件。为此,我们还是需要用到 <em>on</em> 这个方法:
|
||||
|
||||
```js
|
||||
socket.on('user count', function(data){
|
||||
console.log(data);
|
||||
});
|
||||
```
|
||||
|
||||
现在你可以尝试启动你的 app 并登录,你会看到在客户端的控制台打印出了 1,这就表示目前连接到服务器的用户数为 1。你可以试着通过打开多个 app 来验证数量是否会增加。
|
||||
完成上述要求后,你就可以在左边提交你的页面链接。
|
||||
</section>
|
||||
|
||||
## Instructions
|
||||
<section id="instructions">
|
||||
<section id='instructions'>
|
||||
|
||||
</section>
|
||||
|
||||
## Tests
|
||||
@ -20,11 +36,11 @@ localeTitle: 通过发射进行沟通
|
||||
|
||||
```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: 服务器在每个新连接上发出当前用户计数
|
||||
- text: 服务器应在有新的连接时 emit 当前用户数量。
|
||||
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: 您的客户正在侦听“用户计数”事件
|
||||
- text: '客户端应监听 "user count" 事件。'
|
||||
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); })
|
||||
|
||||
```
|
||||
@ -40,6 +56,11 @@ tests:
|
||||
<section id='solution'>
|
||||
|
||||
```js
|
||||
// solution required
|
||||
/**
|
||||
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.
|
||||
*/
|
||||
```
|
||||
|
||||
</section>
|
||||
|
@ -2,23 +2,42 @@
|
||||
id: 5895f70df9fc0f352b528e6a
|
||||
title: Create New Middleware
|
||||
challengeType: 2
|
||||
videoUrl: ''
|
||||
isHidden: false
|
||||
forumTopicId: 301551
|
||||
localeTitle: 创建新的中间件
|
||||
---
|
||||
|
||||
## Description
|
||||
<section id="description">提醒一下,这个项目是基于<a href="https://glitch.com/#!/import/github/freeCodeCamp/boilerplate-advancednode/">Glitch</a>的以下入门项目构建的,或者是从<a href="https://github.com/freeCodeCamp/boilerplate-advancednode/">GitHub</a>克隆的。同样,任何用户都可以通过输入网址来查看/配置他们是否通过身份验证。我们希望通过在呈现配置文件页面之前检查用户是否首先进行身份验证来防止这种情况。这是何时创建中间件的完美示例。这里的挑战是创建中间件功能<code>ensureAuthenticated(req, res, next)</code> ,它将检查用户是否通过调用护照进行身份验证isAuthenticated对<em>请求</em>进行检查,然后检查<em>req.user</em>是否定义。如果是,那么应该调用<em>next()</em> ,否则我们只需通过重定向到我们的主页来回复请求即可登录。该中间件的实现是: <pre> function ensureAuthenticated(req,res,next){
|
||||
if(req.isAuthenticated()){
|
||||
return next();
|
||||
<section id='description'>
|
||||
注意,本项目在<a href='https://glitch.com/#!/import/github/freeCodeCamp/boilerplate-advancednode/'>这个 Glitch 项目</a>的基础上进行开发,你也可以从 <a href='https://github.com/freeCodeCamp/boilerplate-advancednode/'>GitHub</a> 上克隆。
|
||||
无论是否登录,或者哪怕用户试图访问其他页面,目前都会跳转到<code>/profile</code>。为了解决这个问题,我们需要在 profile 页面渲染之前进行用户验证,创建中间件就可以实现这个功能。
|
||||
这个挑战的目标是创建<code>ensureAuthenticated(req, res, next)</code>中间件方法,通过在 <em>request</em> 上调用 passports 的<code>isAuthenticated</code>方法,我们可以检查 <em>req.user</em> 是否定义,从而确定用户是否通过认证。如果用户已通过验证,就会调用 <em>next()</em>,否则我们应重定向到主页并让用户登录。该中间件的实现是:
|
||||
|
||||
```js
|
||||
function ensureAuthenticated(req, res, next) {
|
||||
if (req.isAuthenticated()) {
|
||||
return next();
|
||||
}
|
||||
res.redirect( '/');
|
||||
}; </pre>现在,在包含呈现页面的函数的get请求的参数之前,将<em>ensureAuthenticated</em>作为中间件添加到配置文件页面的请求中。 <pre> app.route( '/简档')
|
||||
.get(ensureAuthenticated,(req,res)=> {
|
||||
res.render(process.cwd()+'/ views / pug / profile');
|
||||
}); </pre>当您认为自己已经做对时,请提交您的页面。 </section>
|
||||
res.redirect('/');
|
||||
};
|
||||
```
|
||||
|
||||
然后,我们需要把 <em>ensureAuthenticated</em> 中间件添加到处理请求的回调之前:
|
||||
|
||||
```js
|
||||
app
|
||||
.route('/profile')
|
||||
.get(ensureAuthenticated, (req,res) => {
|
||||
res.render(process.cwd() + '/views/pug/profile');
|
||||
});
|
||||
```
|
||||
|
||||
完成上述要求后,你就可以在左边提交你的页面链接。
|
||||
</section>
|
||||
|
||||
## Instructions
|
||||
<section id="instructions">
|
||||
<section id='instructions'>
|
||||
|
||||
</section>
|
||||
|
||||
## Tests
|
||||
@ -26,9 +45,9 @@ localeTitle: 创建新的中间件
|
||||
|
||||
```yml
|
||||
tests:
|
||||
- text: 中间件确保应该在我们的/配置文件路由上实现
|
||||
- text: <code>ensureAuthenticated</code>中间件应添加到<code>/profile</code>路由中。
|
||||
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: 正确的Get请求/配置文件重定向到/因为我们未经过身份验证
|
||||
- text: 如果没有通过验证,对 /profile 的 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); })
|
||||
|
||||
```
|
||||
@ -44,6 +63,11 @@ tests:
|
||||
<section id='solution'>
|
||||
|
||||
```js
|
||||
// solution required
|
||||
/**
|
||||
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.
|
||||
*/
|
||||
```
|
||||
|
||||
</section>
|
||||
|
@ -2,15 +2,24 @@
|
||||
id: 589fc831f9fc0f352b528e76
|
||||
title: Handle a Disconnect
|
||||
challengeType: 2
|
||||
videoUrl: ''
|
||||
localeTitle: 处理断开连接
|
||||
isHidden: false
|
||||
forumTopicId: 301552
|
||||
localeTitle: 处理连接断开
|
||||
---
|
||||
|
||||
## Description
|
||||
<section id="description">提醒一下,这个项目是基于<a href="https://glitch.com/#!/import/github/freeCodeCamp/boilerplate-socketio/">Glitch</a>的以下入门项目构建的,或者是从<a href="https://github.com/freeCodeCamp/boilerplate-socketio/">GitHub</a>克隆的。您可能会注意到,到目前为止,您只增加了用户数。处理用户断开连接就像处理初始连接一样简单,除了区别在于你必须在每个套接字上监听它而不是在整个服务器上监听它。 <hr>为此,请在现有的连接侦听器中添加一个侦听器,该侦听器在没有数据传递的情况下侦听套接字上的“disconnect”。您只需登录用户已断开连接的控制台即可测试此功能。 <code>socket.on('disconnect', () => { /*anything you want to do on disconnect*/ });</code>要确保客户端持续获得当前用户的更新计数,您应该在断开连接时将currentUsers减少1,然后使用更新的计数发出'user count'事件! <strong>注意</strong> <br>就像'disconnect'一样,套接字可以向服务器发出的所有其他事件应该在我们定义了'socket'的连接监听器中处理。当您认为自己已经做对时,请提交您的页面。 </section>
|
||||
<section id='description'>
|
||||
注意,本项目在<a href='https://glitch.com/#!/import/github/freeCodeCamp/boilerplate-socketio/'>这个 Glitch 项目</a>的基础上进行开发,你也可以从 <a href='https://github.com/freeCodeCamp/boilerplate-socialauth/'>GitHub</a> 上克隆。
|
||||
你也许注意到,目前为止我们只处理用户数量的增加,没有处理减少。事实上,处理用户断开连接也很简单。区别在于,新连接的监听是发生在整个服务器上,但连接断开的监听是发生在每个 socket 上。
|
||||
<hr>为此,我们需要在目前的监听回调里面监听 socket 断开连接的事件。在断开连接的回调函数中,我们可以不传任何参数,但你可以在这里添加连接断开的测试代码:<code>socket.on('disconnect', () => { /* 在这里添加连接断开的测试代码 */ });</code>
|
||||
为确保客户端可以看到实时的用户数量,显然,我们应该在用户断开时让 currentUsers 减 1,然后发送 'user count' 事件,并使用修改后的用户数量。
|
||||
<strong>注意:</strong><br>和 'disconnect' 类似,所有 socket 可以发送到服务器的事件,我们都应该在有 'socket' 定义的连接监听器里处理。
|
||||
完成上述要求后,你就可以在左边提交你的页面链接。
|
||||
</section>
|
||||
|
||||
## Instructions
|
||||
<section id="instructions">
|
||||
<section id='instructions'>
|
||||
|
||||
</section>
|
||||
|
||||
## Tests
|
||||
@ -18,9 +27,9 @@ localeTitle: 处理断开连接
|
||||
|
||||
```yml
|
||||
tests:
|
||||
- text: 服务器处理与套接字的事件断开连接
|
||||
- text: 服务器应处理断开 socket 连接的事件。
|
||||
testString: getUserInput => $.get(getUserInput('url')+ '/_api/server.js') .then(data => { assert.match(data, /socket.on.*('|")disconnect('|")/gi, ''); }, xhr => { throw new Error(xhr.statusText); })
|
||||
- text: 您的客户正在侦听“用户计数”事件
|
||||
- text: '客户端应监听 "user count" 事件。'
|
||||
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); })
|
||||
|
||||
```
|
||||
@ -36,6 +45,11 @@ tests:
|
||||
<section id='solution'>
|
||||
|
||||
```js
|
||||
// solution required
|
||||
/**
|
||||
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.
|
||||
*/
|
||||
```
|
||||
|
||||
</section>
|
||||
|
@ -2,15 +2,24 @@
|
||||
id: 58a25c98f9fc0f352b528e7f
|
||||
title: Hashing Your Passwords
|
||||
challengeType: 2
|
||||
videoUrl: ''
|
||||
isHidden: false
|
||||
forumTopicId: 301553
|
||||
localeTitle: 哈希密码
|
||||
---
|
||||
|
||||
## Description
|
||||
<section id="description">提醒一下,这个项目是基于<a href="https://glitch.com/#!/import/github/freeCodeCamp/boilerplate-advancednode/">Glitch</a>的以下入门项目构建的,或者是从<a href="https://github.com/freeCodeCamp/boilerplate-advancednode/">GitHub</a>克隆的。回到信息安全部分,您可能还记得存储明文密码<em>永远不会</em>好。现在是时候实施BCrypt来解决这个问题了。 <hr>将BCrypt添加为依赖项并在服务器中将其需要。您需要在两个关键区域处理散列:您在哪里处理注册/保存新帐户以及在登录时检查密码是否正确。目前在我们的注册路线上,您将用户的密码插入数据库,如下所示: <code>password: req.body.password</code> 。实现保存哈希的一种简单方法是在数据库逻辑<code>var hash = bcrypt.hashSync(req.body.password, 12);</code>之前添加以下内容<code>var hash = bcrypt.hashSync(req.body.password, 12);</code>并使用<code>password: hash</code>替换数据库保存中的<code>req.body.password</code> 。最后在我们的身份验证策略中,我们在完成流程之前在代码中检查以下内容: <code>if (password !== user.password) { return done(null, false); }</code> 。完成之前的更改后,现在<code>user.password</code>是一个哈希。在更改现有代码之前,请注意语句如何检查密码是否不相等,然后返回未经过身份验证的密码。考虑到这一点,您的代码可能如下所示,以正确检查针对哈希输入的密码: <code>if (!bcrypt.compareSync(password, user.password)) { return done(null, false); }</code>这是所有需要实现的最重要的安全功能之一,当你有来存储密码!当您认为自己已经做对时,请提交您的页面。 </section>
|
||||
<section id='description'>
|
||||
注意,本项目在<a href='https://glitch.com/#!/import/github/freeCodeCamp/boilerplate-advancednode/'>这个 Glitch 项目</a>的基础上进行开发,你也可以从 <a href='https://github.com/freeCodeCamp/boilerplate-advancednode/'>GitHub</a> 上克隆。
|
||||
回过头来看信息安全,你也许记得在数据库中存储明文密码是<em>绝对</em>禁止的。现在,我们需要引入 BCrypt 来解决这个问题。
|
||||
<hr>添加 BCrypt 作为依赖,并通过<code>require</code>添加到服务器代码中。你需要在两个步骤中使用哈希运算:注册和保存新账户,以及登录时检查密码是否正确。
|
||||
目前处理注册的路由中,我们是这样把密码添加到数据库的:<code>password: req.body.password</code>。我们可以通过这段代码创建哈希值:<code>var hash = bcrypt.hashSync(req.body.password, 12);</code>,然后就可以把<code>passsword: req.body.password</code>替换为<code>password: hash</code>。
|
||||
最后,在验证逻辑中,我们已经有这样一段代码执行检查:<code>if (password !== user.password) { return done(null, false); }</code>。但我们现在存储的密码<code>user.password</code>已经是哈希值了。由于目前的检测机制是密码不匹配时就返回未认证,因此修改后,用于比对用户密码哈希值的代码应该是这样:<code>if (!bcrypt.compareSync(password, user.password)) { return done(null, false); }</code>。
|
||||
当你需要存储密码时,这样做可以有效地提升网站的安全性。完成上述要求后,你就可以在左边提交你的页面链接。
|
||||
</section>
|
||||
|
||||
## Instructions
|
||||
<section id="instructions">
|
||||
<section id='instructions'>
|
||||
|
||||
</section>
|
||||
|
||||
## Tests
|
||||
@ -18,9 +27,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); })
|
||||
|
||||
```
|
||||
@ -36,6 +45,11 @@ tests:
|
||||
<section id='solution'>
|
||||
|
||||
```js
|
||||
// solution required
|
||||
/**
|
||||
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.
|
||||
*/
|
||||
```
|
||||
|
||||
</section>
|
||||
|
@ -2,15 +2,23 @@
|
||||
id: 5895f70ef9fc0f352b528e6b
|
||||
title: How to Put a Profile Together
|
||||
challengeType: 2
|
||||
videoUrl: ''
|
||||
localeTitle: 如何将配置文件放在一起
|
||||
isHidden: false
|
||||
forumTopicId: 301554
|
||||
localeTitle: 如何将 Profile 放在一起
|
||||
---
|
||||
|
||||
## Description
|
||||
<section id="description">提醒一下,这个项目是基于<a href="https://glitch.com/#!/import/github/freeCodeCamp/boilerplate-advancednode/">Glitch</a>的以下入门项目构建的,或者是从<a href="https://github.com/freeCodeCamp/boilerplate-advancednode/">GitHub</a>克隆的。现在我们可以确保访问<em>/ profile</em>的用户已经过身份验证,我们可以使用页面上“req.user”中包含的信息!继续将包含变量<em>username</em> equaling'req.user.username'的对象传递到配置文件视图的render方法中。然后转到你的'profile.pug'视图并添加第<code>h2.center#welcome Welcome, #{username}!</code>行<code>h2.center#welcome Welcome, #{username}!</code>使用“center”类创建h2元素,并使用包含文本“Welcome”和用户名的id“welcome”创建!同样在配置文件中,添加指向<em>/ logout</em>的链接。该路由将托管用于取消身份验证用户的逻辑。 <code>a(href='/logout') Logout</code>当您认为自己正确时,请提交您的页面。 </section>
|
||||
<section id='description'>
|
||||
注意,本项目在<a href='https://glitch.com/#!/import/github/freeCodeCamp/boilerplate-advancednode/'>这个 Glitch 项目</a>的基础上进行开发,你也可以从 <a href='https://github.com/freeCodeCamp/boilerplate-advancednode/'>GitHub</a> 上克隆。
|
||||
现在,只有通过验证的用户才能进入 <em>/profile</em> 页面,这样我们就可以在页面上使用 'req.user' 里的信息了。
|
||||
请在变量中包含 <em>username</em> 键,值为 'req.user.username',并通过 render 方法传给 profile 页面。然后在 'profile.pug' 页面,添加这行<code>h2.center#welcome Welcome, #{username}!</code>代码来创建类为<code>center</code>、id 为<code>welcome</code>且文本内容为 'Welcome, ' 后加用户名的 h2 元素。
|
||||
以及,请在 profile 里添加 <em>/logout</em> 链接,后续会用于处理用户退出登录的逻辑:<code>a(href='/logout') Logout</code>
|
||||
完成上述要求后,你就可以在左边提交你的页面链接。
|
||||
</section>
|
||||
|
||||
## Instructions
|
||||
<section id="instructions">
|
||||
<section id='instructions'>
|
||||
|
||||
</section>
|
||||
|
||||
## Tests
|
||||
@ -18,7 +26,7 @@ localeTitle: 如何将配置文件放在一起
|
||||
|
||||
```yml
|
||||
tests:
|
||||
- text: 正确地将Pug渲染变量添加到/ profile
|
||||
- text: 应在 Pug render 中给 /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); })
|
||||
|
||||
```
|
||||
@ -34,6 +42,11 @@ tests:
|
||||
<section id='solution'>
|
||||
|
||||
```js
|
||||
// solution required
|
||||
/**
|
||||
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.
|
||||
*/
|
||||
```
|
||||
|
||||
</section>
|
||||
|
@ -2,15 +2,25 @@
|
||||
id: 5895f70df9fc0f352b528e69
|
||||
title: How to Use Passport Strategies
|
||||
challengeType: 2
|
||||
videoUrl: ''
|
||||
localeTitle: 如何使用Passport策略
|
||||
isHidden: false
|
||||
forumTopicId: 301555
|
||||
localeTitle: 如何使用 Passport 策略
|
||||
---
|
||||
|
||||
## Description
|
||||
<section id="description">提醒一下,这个项目是基于<a href="https://glitch.com/#!/import/github/freeCodeCamp/boilerplate-advancednode/">Glitch</a>的以下入门项目构建的,或者是从<a href="https://github.com/freeCodeCamp/boilerplate-advancednode/">GitHub</a>克隆的。在提供的index.pug文件中,实际上有一个登录表单。它之前已被隐藏,因为内联javascript <code>if showLogin</code>的形式缩进后。在showLogin作为变量从未定义之前,它从未呈现包含该表单的代码块。继续在该页面的res.render上向对象<code>showLogin: true</code>添加一个新变量。刷新页面时,您应该看到表单!此表单设置为<b>POST</b> on <em>/ login,</em>因此我们应该设置此接受POST并验证用户身份。对于此挑战,您应添加路由/登录以接受POST请求。要在此路由上进行身份验证,您需要添加中间件才能发送响应。这是通过在您的<code>function(req,res)</code>之前使用中间件传递另一个参数来完成的!要使用的中间件是<code>passport.authenticate('local')</code> 。 <em>passport.authenticate</em>也可以将一些选项作为参数,例如: <code>{ failureRedirect: '/' }</code>这非常有用,所以一定要添加它。作为使用中间件后的响应(只有在身份验证中间件通过时才会调用)应该是将用户重定向到<em>/ profile,</em>并且该路由应该呈现视图'profile.pug'。如果身份验证成功,则用户对象将保存在<em>req.user中</em> 。现在,如果您在表单中输入用户名和密码,它应该重定向到主页<em>/</em>并且在服务器的控制台中应该是'用户{USERNAME}尝试登录'。因为我们目前无法登录未注册的用户。当您认为自己已经做对时,请提交您的页面。如果您遇到错误,可以<a href="https://gist.github.com/JosephLivengood/8a335d1a68ed9170da02bb9d8f5b71d5">在这里查看</a>到目前为止完成的项目。 </section>
|
||||
<section id='description'>
|
||||
注意,本项目在<a href='https://glitch.com/#!/import/github/freeCodeCamp/boilerplate-advancednode/'>这个 Glitch 项目</a>的基础上进行开发,你也可以从 <a href='https://github.com/freeCodeCamp/boilerplate-advancednode/'>GitHub</a> 上克隆。
|
||||
在提供的 index.pug 文件里有一个登录表单。因为这个表单中存在行内 JavaScript 代码<code>if showLogin</code>,因此它是隐藏的。因为 showLogin 未定义,所以表单不会渲染。如果在该页面的<code>res.render()</code>里添加一个包含<code>showLogin: true</code>的对象,你就可以在刷新页面后看到表单。当你点击 login 时,表单会向服务器的 <em>/login</code> 发送 POST 请求,此时服务器端就可以接受 POST 请求信息并进行用户验证。
|
||||
在这次挑战中,你需要为 POST 请求添加路由<code>/login</code>。为了用这个路由进行验证,你需要添加一个中间件,中间件应作为参数添加到用于处理请求的回调函数<code>function(req,res)</code>之前。对于 passport 的验证中间件,应这样调用:<code>passport.authenticate('local')</code>。
|
||||
<em>passport.authenticate</em> 也接收选项作为参数,这些选项用于设置验证,例如<code>{ failureRedirect: '/' }</code>就很有用,请记得添加到你的代码中。如果中间件验证通过,我们就应该提供相应的后续处理。在这个挑战中,我们需要让用户重定到 <em>/profile</em>,这样<code>profile.pug</code>页面就会渲染。
|
||||
如果验证通过,用户对象将会储存到 <em>req.user</em> 中。
|
||||
这时,如果你在表单里输入了用户名和密码,路由将会重定向到主页 <em>/</em>,在服务端将会打印 'User {USERNAME} attempted to log in.',由于现在我们还没有实现注册功能,因此所有登录尝试都会失败。
|
||||
完成上述要求后,你就可以在左边提交你的页面链接。如果运行出错,你可以在<a href='https://gist.github.com/JosephLivengood/8a335d1a68ed9170da02bb9d8f5b71d5'>这里</a>检查你的项目完成情况。
|
||||
</section>
|
||||
|
||||
## Instructions
|
||||
<section id="instructions">
|
||||
<section id='instructions'>
|
||||
|
||||
</section>
|
||||
|
||||
## Tests
|
||||
@ -18,9 +28,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); })
|
||||
|
||||
```
|
||||
@ -36,6 +46,11 @@ tests:
|
||||
<section id='solution'>
|
||||
|
||||
```js
|
||||
// solution required
|
||||
/**
|
||||
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.
|
||||
*/
|
||||
```
|
||||
|
||||
</section>
|
||||
|
@ -2,21 +2,37 @@
|
||||
id: 5895f70cf9fc0f352b528e67
|
||||
title: Implement the Serialization of a Passport User
|
||||
challengeType: 2
|
||||
videoUrl: ''
|
||||
localeTitle: 实现Passport用户的序列化
|
||||
isHidden: false
|
||||
forumTopicId: 301556
|
||||
localeTitle: 实现 Passport 用户的序列化
|
||||
---
|
||||
|
||||
## Description
|
||||
<section id="description">提醒一下,这个项目是基于<a href="https://glitch.com/#!/import/github/freeCodeCamp/boilerplate-advancednode/">Glitch</a>的以下入门项目构建的,或者是从<a href="https://github.com/freeCodeCamp/boilerplate-advancednode/">GitHub</a>克隆的。现在我们没有加载实际的用户对象,因为我们还没有设置我们的数据库。这可以通过许多不同的方式完成,但是对于我们的项目,当我们启动服务器并在应用程序的整个生命周期中保持持久连接时,我们将连接到数据库。为此,请将MongoDB添加为依赖项,并在服务器中将其需要。 ( <code>const mongo = require('mongodb').MongoClient;</code> )现在我们想要连接到我们的数据库,然后开始侦听请求。这样做的目的是在连接数据库之前或者出现数据库错误时不允许请求。要实现此目的,您需要在以下内容中包含序列化和应用程序侦听器: <pre> mongo.connect(process.env.DATABASE,(err,db)=> {
|
||||
if(错误){
|
||||
console.log('数据库错误:'+错误);
|
||||
} else {
|
||||
console.log('成功的数据库连接');
|
||||
<pre> <code> //serialization and app.listen</code> </pre>
|
||||
<p> }}); </p></pre>您现在可以在deserializeUser中取消注释该块并删除您的<code>done(null, null)</code> 。确保将.env文件中的<em>DATABASE</em>设置为数据库的连接字符串(例如: <code>DATABASE=mongodb://admin:pass@mlab.com:12345/my-project</code> )。您可以在<a href="https://mlab.com/welcome/">mLab</a>上设置免费数据库。恭喜 - 您已完成序列化设置!当您认为自己已经做对时,请提交您的页面。如果您遇到错误,可以<a href="https://gist.github.com/JosephLivengood/e192e809a1d27cb80dc2c6d3467b7477">在这里查看</a>到目前为止完成的项目。 <p></p></section>
|
||||
<section id='description'>
|
||||
注意,本项目在<a href='https://glitch.com/#!/import/github/freeCodeCamp/boilerplate-advancednode/'>这个 Glitch 项目</a>的基础上进行开发,你也可以从 <a href='https://github.com/freeCodeCamp/boilerplate-advancednode/'>GitHub</a> 上克隆。
|
||||
截至目前,我们还没有配置完数据库,因此还无法加载用户数据。实现这个的方式很多,但对于我们的项目,一旦服务器启动,那么只要有 app 实例在运行,数据库就应一直处于连接状态。
|
||||
为此,我们要添加 MongoDB 作为依赖,并在 server 中<code>require</code>它,就像这样:<code>const mongo = require('mongodb').MongoClient;</code>。
|
||||
在连接数据库之后,我们才能让服务器开始监听请求,这样做可以保证服务器在数据库连接前或数据库发生错误时不接受任何请求。为此,我们需要这样写:
|
||||
|
||||
```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
|
||||
}
|
||||
});
|
||||
```
|
||||
|
||||
现在,请把上一个挑战中我们注释掉的<code>deserializeUser</code>中的代码块添加回来,然后删掉<code>done(null, null)</code>。请确保你已经在 .env 文件里配置了<code>DATABASE</code>的数据库连接字段,例如:<code>DATABASE=mongodb://admin:pass@mlab.com:12345/my-project</code>。你可以在 <a href='https://mlab.com/welcome/'>mLab</a> 上创建一个免费的数据库。至此,序列化的创建完成。
|
||||
完成上述要求后,你就可以在左边提交你的页面链接。如果运行出错,你可以在<a href="https://gist.github.com/JosephLivengood/e192e809a1d27cb80dc2c6d3467b7477">这里</a>检查你的项目完成情况。
|
||||
</section>
|
||||
|
||||
## Instructions
|
||||
<section id="instructions">
|
||||
<section id='instructions'>
|
||||
|
||||
</section>
|
||||
|
||||
## Tests
|
||||
@ -24,9 +40,9 @@ localeTitle: 实现Passport用户的序列化
|
||||
|
||||
```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: 反序列化现在正确使用DB并且擦除了<code>done(null, null)</code>
|
||||
- text: 反序列化应正确使用,且应移除<code>done(null, null)</code>。
|
||||
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); })
|
||||
|
||||
```
|
||||
@ -42,6 +58,11 @@ tests:
|
||||
<section id='solution'>
|
||||
|
||||
```js
|
||||
// solution required
|
||||
/**
|
||||
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.
|
||||
*/
|
||||
```
|
||||
|
||||
</section>
|
||||
|
@ -2,24 +2,37 @@
|
||||
id: 589a69f5f9fc0f352b528e71
|
||||
title: Implementation of Social Authentication II
|
||||
challengeType: 2
|
||||
videoUrl: ''
|
||||
localeTitle: 社会认证的实施II
|
||||
isHidden: false
|
||||
forumTopicId: 301557
|
||||
---
|
||||
|
||||
## Description
|
||||
<section id="description">提醒一下,这个项目是基于<a href="https://glitch.com/#!/import/github/freeCodeCamp/boilerplate-socialauth/">Glitch</a>的以下入门项目构建的,或者是从<a href="https://github.com/freeCodeCamp/boilerplate-socialauth/">GitHub</a>克隆的。设置Github身份验证的最后一部分是创建策略本身。为此,您需要将'passport-github'的依赖项添加到项目中,并将其作为GithubStrategy,例如<code>const GitHubStrategy = require('passport-github').Strategy;</code> 。要设置Github策略,你必须告诉<b>护照</b> <b>使用</b>实例化的<b>GithubStrategy</b> ,它接受2个参数:一个对象(包含<em>clientID</em> , <em>clientSecret</em>和<em>callbackURL</em> )和一个在成功验证用户时要调用的函数,我们将确定如果用户是新用户以及最初要保存在用户数据库对象中的字段。这在许多策略中很常见,但有些可能需要更多信息,如特定策略的github README所述;例如,Google也需要一个<em>范围</em>来确定您的请求所返回的信息类型,并要求用户批准此类访问。我们正在实施的当前策略<a>在此处</a>列出<a>了</a>它的用法,但我们将在freeCodeCamp上完成所有这些工作!以下是您的新战略应该如何看待这一点: <pre> 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(配置文件);
|
||||
//这里的数据库逻辑带有包含我们用户对象的回调
|
||||
<section id='description'>
|
||||
注意,本项目在<a href='https://glitch.com/#!/import/github/freeCodeCamp/boilerplate-socialauth/'>这个 Glitch 项目</a>的基础上进行开发,你也可以从 <a href='https://github.com/freeCodeCamp/boilerplate-socialauth/'>GitHub</a> 上克隆。
|
||||
设置 GitHub 验证的最后一步是创建策略本身。为此,你需要在项目中<code>require</code>'passport-github',且实例化为 GithubStrategy:<code>const GitHubStrategy = require('passport-github').Strategy;</code>。
|
||||
为了设置 GitHub 策略,我们需要在 <b>passport</b> 中使用实例化的 <b>GithubStrategy</b>,它可以接收两个参数:一个对象(包括 <em>clientID</em>, <em>clientSecret</em> 和 <em>callbackURL</em>),以及一个回调函数。在这个回调函数中,我们要处理验证成功时,判断用户是否已经在数据库中存在的逻辑,还有如果数据库中不存在,把用户数据添加到数据库的代码。这种处理方式适用于绝大部分第三方验证策略,但有些策略会需要我们提供更多的信息,详情请参考相关策略的 README。例如,Google 的验证策略会要求你提供一个 <em>scope</em>,用于标示用户成功登录后,你需要从返回的对象中获取那些信息。以及,这也需要经过用户同意,你才可以获取到。当前我们使用的验证策略,你也可以从它 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
|
||||
}
|
||||
)); </pre>您的身份验证还不会成功,并且实际上会抛出错误,没有数据库逻辑和回调,但如果您尝试它,它应该将您的Github配置文件记录到您的控制台!当您认为自己已经做对时,请提交您的页面。 </section>
|
||||
));
|
||||
```
|
||||
|
||||
目前,你的验证部分不会成功。由于没有数据库的逻辑和回调函数,你的代码目前还会报错。但如果你试一试,就可以在右边的控制台里看到输出了你的 GitHub 的个人信息。
|
||||
完成上述要求后,你就可以在左边提交你的页面链接。
|
||||
</section>
|
||||
|
||||
## Instructions
|
||||
<section id="instructions">
|
||||
<section id='instructions'>
|
||||
|
||||
</section>
|
||||
|
||||
## Tests
|
||||
@ -27,11 +40,11 @@ localeTitle: 社会认证的实施II
|
||||
|
||||
```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); })
|
||||
|
||||
```
|
||||
@ -47,6 +60,11 @@ tests:
|
||||
<section id='solution'>
|
||||
|
||||
```js
|
||||
// solution required
|
||||
/**
|
||||
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.
|
||||
*/
|
||||
```
|
||||
|
||||
</section>
|
||||
|
@ -2,34 +2,46 @@
|
||||
id: 589a8eb3f9fc0f352b528e72
|
||||
title: Implementation of Social Authentication III
|
||||
challengeType: 2
|
||||
videoUrl: ''
|
||||
localeTitle: 社会认证的实施III
|
||||
isHidden: false
|
||||
forumTopicId: 301558
|
||||
localeTitle: 实现第三种社交登录
|
||||
---
|
||||
|
||||
## Description
|
||||
<section id="description">提醒一下,这个项目是基于<a href="https://glitch.com/#!/import/github/freeCodeCamp/boilerplate-socialauth/">Glitch</a>的以下入门项目构建的,或者是从<a href="https://github.com/freeCodeCamp/boilerplate-socialauth/">GitHub</a>克隆的。策略的最后一部分是处理从Github返回的配置文件。我们需要加载用户数据库对象(如果存在)或创建一个(如果不存在)并填充配置文件中的字段,然后返回用户的对象。 Github在每个配置文件中为我们提供了一个唯一的<em>ID</em> ,我们可以使用它来搜索(已经实现)用户序列化。下面是您可以在项目中使用的示例实现 - 它位于作为新策略的第二个参数的函数内,就在<code>console.log(profile);</code>目前是: <pre> 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);
|
||||
}
|
||||
); </pre>使用findAndModify,它允许您搜索对象并对其进行更新,如果对象不存在则将其置换,并在每次回调函数中接收新对象。在这个例子中,我们总是将last_login设置为now,我们总是将login_count增加1,并且只有当我们插入一个新对象(新用户)时,我们才会填充大部分字段。需要注意的是使用默认值。有时,返回的个人资料不会填写所有信息,或者用户会选择保留私密信息;所以在这种情况下我们必须处理它以防止错误。你现在应该可以登录你的应用了 - 试试吧!当您认为自己已经做对时,请提交您的页面。如果你正在运行到错误,您可以检查出的这个小项目的完成代码的例子<a href="https://glitch.com/#!/project/guttural-birch">在这里</a> 。 </section>
|
||||
<section id='description'>
|
||||
注意,本项目在<a href='https://glitch.com/#!/import/github/freeCodeCamp/boilerplate-socialauth/'>这个 Glitch 项目</a>的基础上进行开发,你也可以从 <a href='https://github.com/freeCodeCamp/boilerplate-socialauth/'>GitHub</a> 上克隆。
|
||||
验证策略的最后一部分是处理从 GitHub 返回的个人信息。如果用户存在,我们就需要从数据库中读取用户数据并在 profile 页面加载;否则,我们需要把用户信息添加到数据库。GitHub 在用户信息中为我们提供了独一无二的 <em>id</em>,我们可以通过序列化的 id 在数据库中搜索用户(已实现)。以下是这个逻辑的实现示例,我们应该把它传到新策略的第二个参数,就是目前<code>console.log(profile);</code>的下方:
|
||||
|
||||
```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);
|
||||
}
|
||||
);
|
||||
```
|
||||
|
||||
<code>findAndModify</code>的作用是在数据库中查询对象并更新,如果对象不存在,我们也可以<code>upsert</code>(注,upsert 可以理解为 update + insert)它,然后我们可以在回调方法里获取到插入数据后的新对象。在这个例子中,我们会把 last_login 设置成为 now,而且总会为 login_count 加 1。只有在插入一个新对象(新用户)时,我们才会初始化这些字段。另外,还需要注意默认值的使用。有时返回的用户信息可能不全,可能是因为用户没有填写,也可能是因为用户选择不公开一部分信息。在这种情况下,我们需要进行相应的处理,以防我们的 app 报错。
|
||||
你现在应该可以登录你的应用了,试试吧。完成上述要求后,你就可以在左边提交你的页面链接。如果运行出错,你可以在 <a href='https://glitch.com/#!/project/guttural-birch'>here</a> 这里检查这个迷你项目的完成代码。
|
||||
</section>
|
||||
|
||||
## Instructions
|
||||
<section id="instructions">
|
||||
<section id='instructions'>
|
||||
|
||||
</section>
|
||||
|
||||
## Tests
|
||||
@ -37,7 +49,7 @@ localeTitle: 社会认证的实施III
|
||||
|
||||
```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); })
|
||||
|
||||
```
|
||||
@ -53,6 +65,11 @@ tests:
|
||||
<section id='solution'>
|
||||
|
||||
```js
|
||||
// solution required
|
||||
/**
|
||||
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.
|
||||
*/
|
||||
```
|
||||
|
||||
</section>
|
||||
|
@ -2,18 +2,33 @@
|
||||
id: 589a69f5f9fc0f352b528e70
|
||||
title: Implementation of Social Authentication
|
||||
challengeType: 2
|
||||
videoUrl: ''
|
||||
localeTitle: 社会认证的实施
|
||||
isHidden: false
|
||||
forumTopicId: 301559
|
||||
localeTitle: 实现第一种社交登录
|
||||
---
|
||||
|
||||
## Description
|
||||
<section id="description">提醒一下,这个项目是基于<a href="https://glitch.com/#!/import/github/freeCodeCamp/boilerplate-socialauth/">Glitch</a>的以下入门项目构建的,或者是从<a href="https://github.com/freeCodeCamp/boilerplate-socialauth/">GitHub</a>克隆的。此类身份验证在您的应用中遵循的基本路径是: <ol><li>用户单击按钮或链接将它们发送到我们使用特定策略进行身份验证的路由(EG.GitHub) </li><li>您的路由呼叫<code>passport.authenticate('github')</code> ,将其重定向到Github。 </li><li>用户登陆的页面,在Github上,允许他们登录,如果他们还没有。然后它要求他们批准从我们的应用程序访问他们的个人资料。 </li><li>然后,如果用户获得批准,则会使用他们的个人资料将该用户返回到我们的应用。 </li><li>它们现在已经过身份验证,您的应用应检查它是否为返回的配置文件,如果不是,则将其保存在数据库中。 </li></ol> OAuth策略要求您至少拥有<em>客户端ID</em>和<em>客户端密钥</em> ,以便他们验证身份验证请求的来源以及是否有效。这些是从您尝试使用Github实现身份验证的站点获得的,并且对您的应用程序是唯一的 - 它们不会被<b>共享</b> ,不应该上传到公共存储库或直接在您的代码中编写。通常的做法是将它们放在<em>.env</em>文件中并引用它们: <code>process.env.GITHUB_CLIENT_ID</code> 。对于这个挑战,我们将使用Github策略。 <em><em>从Github</em></em>获取您的<em>客户ID和密码<em>是在“开发者设置”下的帐户配置文件设置中完成的,然后是“ <a href="https://github.com/settings/developers">OAuth应用程序</a> ”。点击“注册一个新的应用程序”,为您的应用命名,将网址粘贴到您的故障主页( <b>不是项目代码的网址</b> ),最后为回调网址,粘贴到与主页相同的网址,但使用'/ auth / github / callback'已添加。这是用户将被重定向到我们在Github上进行身份验证后处理的地方。将返回的信息保存为.env文件中的“GITHUB_CLIENT_ID”和“GITHUB_CLIENT_SECRET”。在重新混合的项目中,创建2条接受GET请求的路由:/ auth / github和/ auth / github / callback。第一个应该只调用护照来验证'github',第二个应该调用护照来验证'github',失败重定向到'/'然后如果成功重定向到'/ profile'(类似于我们的上一个项目)。 '/ auth / github / callback'应该如何看待的示例与我们在上一个项目中处理正常登录的方式类似:</em></em> <pre> <em><em>app.route( '/登录')
|
||||
.post(passport.authenticate('local',{failureRedirect:'/'}),(req,res)=> {
|
||||
res.redirect( '/简档');
|
||||
});</em></em> </pre> <em><em>当您认为自己已经做对时,请提交您的页面。如果您遇到错误,可以<a href="https://gist.github.com/JosephLivengood/28ea2cae7e1dc6a53d7f0c42d987313b">在此处</a>查看项目。</em></em> </section>
|
||||
<section id='description'>
|
||||
注意,本项目在<a href='https://glitch.com/#!/import/github/freeCodeCamp/boilerplate-socialauth/'>这个 Glitch 项目</a>的基础上进行开发,你也可以从 <a href='https://github.com/freeCodeCamp/boilerplate-socialauth/'>GitHub</a> 上克隆。
|
||||
第三方用户验证的实现逻辑如下:<ol><li>在用户点击按钮或者链接后,进入验证页面,通过第三方平台(如 GitHub)来进行用户验证。</li><li>需要在路由中调用<code>passport.authenticate('github')</code>,跳转至 GitHub 验证页面。</li><li>页面跳转到 GitHub 上,如果用户未登录 GitHub,就需要在这里进行登录。登录成功后,会出现向用户申请访问权限的确认页。</li><li>如果用户同意访问,则用户会回到我们提供的回调地址,带着 GitHub 那边提供的用户信息回到我们的 app 中。</li><li>验证已完成。在我们的应用中,我们需要查询这个用户是否已经存在。如果是新用户,那我们需要把他的用户信息存储到数据库。</li></ol>
|
||||
在 OAuth 验证策略中,我们至少需要提供 <em>Client ID</em> 和 <em>Client Secret</em>,这样第三方平台就会获悉验证请求的来源,以及这个来源是否有效。为此,需要去我们使用的第三方验证平台(比如 GitHub)获取这两个字段的值。注意,我们获取到的这个值是唯一的,且仅对我们的当前 app 有效——<b>因此,千万不要分享给别人</b>,更不要上传到公共仓库或者直接写在代码里。通常,我们会在 <em>.env</em> 文件里配置,并在 Node.js 里通过:<code>process.env.GITHUB_CLIENT_ID</code>获取。对于这次挑战,我们将会使用 GitHub 作为验证平台。
|
||||
首先,你需要进入账户设置里的 <a href='https://github.com/settings/developers'>Developer settings</a>板块,然后在 OAuth Apps 获取 <em>Client ID</em> 和 <em>Client Secret</em>。点击 'Register a new application',设置你的应用名称,然后把你的 glitch 主页地址(<b>注意,不是项目代码的地址</b>)粘贴到 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');
|
||||
});
|
||||
```
|
||||
|
||||
完成上述要求后,你就可以在左边提交你的页面链接。如果运行出错,你可以在<a href='https://gist.github.com/JosephLivengood/28ea2cae7e1dc6a53d7f0c42d987313b'>这里</a>检查你的项目完成情况。
|
||||
</section>
|
||||
|
||||
## Instructions
|
||||
<section id="instructions">
|
||||
<section id='instructions'>
|
||||
|
||||
</section>
|
||||
|
||||
## Tests
|
||||
@ -21,9 +36,9 @@ localeTitle: 社会认证的实施
|
||||
|
||||
```yml
|
||||
tests:
|
||||
- text: Route / auth / github正确
|
||||
- text: 路由 /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: Route / auth / github /回调正确
|
||||
- text: 路由 /auth/github/callback 应正确配置。
|
||||
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); })
|
||||
|
||||
```
|
||||
@ -39,6 +54,11 @@ tests:
|
||||
<section id='solution'>
|
||||
|
||||
```js
|
||||
// solution required
|
||||
/**
|
||||
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.
|
||||
*/
|
||||
```
|
||||
|
||||
</section>
|
||||
|
@ -2,23 +2,41 @@
|
||||
id: 58965611f9fc0f352b528e6c
|
||||
title: Logging a User Out
|
||||
challengeType: 2
|
||||
videoUrl: ''
|
||||
localeTitle: 记录用户
|
||||
isHidden: false
|
||||
forumTopicId: 301560
|
||||
localeTitle: 用户退出
|
||||
---
|
||||
|
||||
## Description
|
||||
<section id="description">提醒一下,这个项目是基于<a href="https://glitch.com/#!/import/github/freeCodeCamp/boilerplate-advancednode/">Glitch</a>的以下入门项目构建的,或者是从<a href="https://github.com/freeCodeCamp/boilerplate-advancednode/">GitHub</a>克隆的。创建注销逻辑很容易。路径应该只是取消认证用户并重定向到主页而不是渲染任何视图。在护照中, <code>req.logout();</code>认证用户就像调用<code>req.logout();</code>一样简单<code>req.logout();</code>在重定向之前。 <pre> app.route( '/注销')
|
||||
.get((req,res)=> {
|
||||
req.logout();
|
||||
res.redirect( '/');
|
||||
}); </pre>您可能已经注意到我们也没有处理丢失的页面(404),在Node中处理此问题的常用方法是使用以下中间件。继续在所有其他路线之后添加: <pre> app.use((req,res,next)=> {
|
||||
res.status(404)
|
||||
.TYPE( '文本')
|
||||
.send('未找到');
|
||||
}); </pre>当您认为自己已经做对时,请提交您的页面。 </section>
|
||||
<section id='description'>
|
||||
注意,本项目在<a href='https://glitch.com/#!/import/github/freeCodeCamp/boilerplate-advancednode/'>这个 Glitch 项目</a>的基础上进行开发,你也可以从 <a href='https://github.com/freeCodeCamp/boilerplate-advancednode/'>GitHub</a> 上克隆。
|
||||
创建退出登录的逻辑是比较简单的。只要用户尝试退出登录,路由就应重定向到主页,而不应该显示任何其他页面。
|
||||
在 passport 里,只需要在重定向前调用<code>req.logout();</code>即可完成用户登出。
|
||||
|
||||
```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');
|
||||
});
|
||||
```
|
||||
|
||||
完成上述要求后,你就可以在左边提交你的页面链接。
|
||||
</section>
|
||||
|
||||
## Instructions
|
||||
<section id="instructions">
|
||||
<section id='instructions'>
|
||||
|
||||
</section>
|
||||
|
||||
## Tests
|
||||
@ -26,9 +44,9 @@ localeTitle: 记录用户
|
||||
|
||||
```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); })
|
||||
|
||||
```
|
||||
@ -44,6 +62,11 @@ tests:
|
||||
<section id='solution'>
|
||||
|
||||
```js
|
||||
// solution required
|
||||
/**
|
||||
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.
|
||||
*/
|
||||
```
|
||||
|
||||
</section>
|
||||
|
@ -2,40 +2,55 @@
|
||||
id: 58966a17f9fc0f352b528e6d
|
||||
title: Registration of New Users
|
||||
challengeType: 2
|
||||
videoUrl: ''
|
||||
localeTitle: 新用户注册
|
||||
isHidden: false
|
||||
forumTopicId: 301561
|
||||
localeTitle: 注册新用户
|
||||
---
|
||||
|
||||
## Description
|
||||
<section id="description">提醒一下,这个项目是基于<a href="https://glitch.com/#!/import/github/freeCodeCamp/boilerplate-advancednode/">Glitch</a>的以下入门项目构建的,或者是从<a href="https://github.com/freeCodeCamp/boilerplate-advancednode/">GitHub</a>克隆的。现在我们需要允许我们网站上的新用户注册一个帐户。在主页的res.render上,向传递的对象添加一个新变量 - <code>showRegistration: true</code> 。刷新页面时,您应该会看到已在index.pug文件中创建的注册表单!此表单设置为<b>POST</b> on <em>/ register,</em>因此我们应该设置此接受POST并在数据库中创建用户对象。注册路由的逻辑应如下所示:注册新用户>验证新用户>重定向到/配置文件步骤1的逻辑,注册新用户,应如下所示:使用findOne命令查询数据库>如果用户返回然后它存在并重定向回到主页<em>或者</em>如果用户未定义且没有发生错误,则使用用户名和密码将“insertOne”输入数据库,只要没有错误发生,然后调用<em>next</em>转到步骤2,验证新的user,我们已经在POST / login路由中编写了逻辑。 <pre> 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);
|
||||
}
|
||||
}
|
||||
)
|
||||
<section id='description'>
|
||||
注意,本项目在<a href='https://glitch.com/#!/import/github/freeCodeCamp/boilerplate-advancednode/'>这个 Glitch 项目</a>的基础上进行开发,你也可以从 <a href='https://github.com/freeCodeCamp/boilerplate-advancednode/'>GitHub</a> 上克隆。
|
||||
现在我们需要为新用户添加注册帐号的功能,首先我们需要在主页的 res.render 接收的变量对象中添加<code>showRegistration: true</code>。此时刷新页面,你会看到页面上已经显示了我们在 index.pug 文件中定义的注册表单。这个表单设置了请求路径 <em>/register</em>,并将请求方法设置成 <b>POST</b>,所以我们需要在服务器接受 <b>POST</b> 请求,且在数据库中创建用户对象。
|
||||
用户注册的逻辑如下:注册新用户 > 认证新用户 > 重定向到 /profile。
|
||||
对于步骤一的注册新用户,详细逻辑如下:用 findOne 命令查询数据库 > 如果返回了用户对象,则表示用户存在,然后返回主页;如果用户未定义且没有报错,则会将包含用户名和密码的用户对象通过<code>insertOne</code>添加到数据库,只要没有报错则会继续下一步:认证新用户——我们已经在 /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);
|
||||
}
|
||||
}
|
||||
})},
|
||||
passport.authenticate('local',{failureRedirect:'/'}),
|
||||
(req,res,next)=> {
|
||||
res.redirect( '/简档');
|
||||
)
|
||||
}
|
||||
})
|
||||
},
|
||||
passport.authenticate('local', { failureRedirect: '/' }),
|
||||
(req, res, next) => {
|
||||
res.redirect('/profile');
|
||||
}
|
||||
); </pre>当您认为自己已经做对时,请提交您的页面。如果您遇到错误,可以<a href="https://gist.github.com/JosephLivengood/6c47bee7df34df9f11820803608071ed">在这里查看</a>到目前为止完成的项目。 </section>
|
||||
);
|
||||
```
|
||||
|
||||
完成上述要求后,你就可以在左边提交你的页面链接。如果运行出错,你可以在<a href='https://gist.github.com/JosephLivengood/6c47bee7df34df9f11820803608071ed'>这里</a>检查你的项目完成情况。
|
||||
</section>
|
||||
|
||||
## Instructions
|
||||
<section id="instructions">
|
||||
<section id='instructions'>
|
||||
|
||||
</section>
|
||||
|
||||
## Tests
|
||||
@ -43,15 +58,15 @@ localeTitle: 新用户注册
|
||||
|
||||
```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: 注销后配置文件不再有效
|
||||
- text: 退出登录后,profile 页面应无法访问。
|
||||
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); })'
|
||||
|
||||
```
|
||||
@ -67,6 +82,11 @@ tests:
|
||||
<section id='solution'>
|
||||
|
||||
```js
|
||||
// solution required
|
||||
/**
|
||||
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.
|
||||
*/
|
||||
```
|
||||
|
||||
</section>
|
||||
|
@ -2,15 +2,24 @@
|
||||
id: 589fc832f9fc0f352b528e79
|
||||
title: Send and Display Chat Messages
|
||||
challengeType: 2
|
||||
videoUrl: ''
|
||||
isHidden: false
|
||||
forumTopicId: 301562
|
||||
localeTitle: 发送和显示聊天消息
|
||||
---
|
||||
|
||||
## Description
|
||||
<section id="description">提醒一下,这个项目是基于<a href="https://glitch.com/#!/import/github/freeCodeCamp/boilerplate-socketio/">Glitch</a>的以下入门项目构建的,或者是从<a href="https://github.com/freeCodeCamp/boilerplate-socketio/">GitHub</a>克隆的。是时候开始允许客户端向服务器发送聊天消息以向所有客户端发送消息!已经在您的client.js文件中,您应该看到在提交messgae表单时已经存在一段代码处理! ( <code>$('form').submit(function(){ /*logic*/ });</code> ) <hr>在您处理表单提交的代码中,您应该在定义“messageToSend”之后但在清除文本框<code>#m</code>之前发出事件。该事件应命名为“聊天消息”,数据应为“messageToSend”。 <code>socket.emit('chat message', messageToSend);</code>现在,在您的服务器上,您应该收听事件“聊天消息”的套接字,并将数据命名为“message”。一旦接收到事件,应该然后发射所述事件“聊天消息”到所有插座<code>io.emit</code>与数据为含“名称”和“报文”的对象。现在再次在您的客户端上,您现在应该监听事件“聊天消息”,并在收到时,将一个列表项追加到<code>#messages</code> ,其名称为冒号和消息!此时聊天功能齐全,并在所有客户端发送消息!当您认为自己已经做对时,请提交您的页面。如果您遇到错误,可以<a href="https://gist.github.com/JosephLivengood/3e4b7750f6cd42feaa2768458d682136">在此处</a>检查项目到此时<a href="https://gist.github.com/JosephLivengood/3e4b7750f6cd42feaa2768458d682136">为服务器</a>和<a href="https://gist.github.com/JosephLivengood/41ba76348df3013b7870dc64861de744">客户端</a> 。 </section>
|
||||
<section id='description'>
|
||||
注意,本项目在<a href='https://glitch.com/#!/import/github/freeCodeCamp/boilerplate-socketio/'>这个 Glitch 项目</a>的基础上进行开发,你也可以从 <a href='https://github.com/freeCodeCamp/boilerplate-socialauth/'>GitHub</a> 上克隆。
|
||||
现在,我们可以开始实现聊天室功能了。整体逻辑很简单,只需要获取用户发给服务端的消息,再通过服务端给所有客户端发送信息就可以了。在 client.js 文件里,你应该已经注意到了这段提交表单的代码:<code>$('form').submit(function(){ /*logic*/ });</code>
|
||||
<hr>现在我们需要处理事件的 emit,它应该发生在定义 'messageToSend' 之后,以及清除<code>#m</code>中的文本之前。我们称这个事件叫 'chat message',需发送的数据叫 'messageToSend':<code>socket.emit('chat message', messageToSend);</code>
|
||||
在服务端,我们需要监听包含 'message' 的 'chat message' 事件。一旦事件发生,我们就通过<code>io.emit</code> 把包含 'name' 和 'message' 的 'chat message' 事件发送给所有已连接的 socket。
|
||||
回到客户端,我们需要监听 'chat message' 事件。只要接收到这个事件,就把包含名字和消息的内容(注意:需要在名字后添加冒号)通过<code><li></code>添加到<code>#messages</code>。
|
||||
至此,我们已经完成发送信息到所有客户端的功能。完成上述要求后,你就可以在左边提交你的页面链接。如果运行出错,你可以在 <a href='https://gist.github.com/JosephLivengood/3e4b7750f6cd42feaa2768458d682136'>这里对应服务端</a> 和 <a href='https://gist.github.com/JosephLivengood/41ba76348df3013b7870dc64861de744'>这里对应客户端</a> 来检查完成代码。
|
||||
</section>
|
||||
|
||||
## Instructions
|
||||
<section id="instructions">
|
||||
<section id='instructions'>
|
||||
|
||||
</section>
|
||||
|
||||
## Tests
|
||||
@ -18,9 +27,9 @@ localeTitle: 发送和显示聊天消息
|
||||
|
||||
```yml
|
||||
tests:
|
||||
- text: 服务器侦听“聊天消息”,然后正确发出
|
||||
- text: '服务端应监听 "chat message",且应在监听到后 emit。'
|
||||
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: 客户端正确处理和显示事件“聊天消息”中的新数据
|
||||
- text: '客户端应正确处理和展示从 "chat message" 事件发来的新数据。'
|
||||
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); })"
|
||||
|
||||
```
|
||||
@ -36,6 +45,11 @@ tests:
|
||||
<section id='solution'>
|
||||
|
||||
```js
|
||||
// solution required
|
||||
/**
|
||||
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.
|
||||
*/
|
||||
```
|
||||
|
||||
</section>
|
||||
|
@ -2,24 +2,39 @@
|
||||
id: 5895f70cf9fc0f352b528e66
|
||||
title: Serialization of a User Object
|
||||
challengeType: 2
|
||||
videoUrl: ''
|
||||
isHidden: false
|
||||
forumTopicId: 301563
|
||||
localeTitle: 用户对象的序列化
|
||||
---
|
||||
|
||||
## Description
|
||||
<section id="description">提醒一下,这个项目是基于<a href="https://glitch.com/#!/import/github/freeCodeCamp/boilerplate-advancednode/">Glitch</a>的以下入门项目构建的,或者是从<a href="https://github.com/freeCodeCamp/boilerplate-advancednode/">GitHub</a>克隆的。序列化和反序列化是身份验证方面的重要概念。序列化对象意味着将其内容转换为一个小<em>键,</em>基本上可以将其反序列化为原始对象。这使我们能够知道与服务器通信的人,而无需在每次请求新页面时发送用户名和密码等身份验证数据。要正确设置它,我们需要一个序列化函数和一个反序列化函数。在护照中,我们使用<code>passport.serializeUser( OURFUNCTION )</code>和<code>passport.deserializeUser( OURFUNCTION )</code>创建它们。使用2个参数调用serializeUser,完整的用户对象和护照使用的回调。在回调中返回应该是唯一的键来标识该用户 - 最容易使用的用户是对象中的用户_id,因为它应该是MongoDb生成的唯一用户。类似地,使用该密钥和护照的回调函数调用deserializeUser,但这次我们必须获取该密钥并将用户完整对象返回到回调。要进行查询搜索Mongo _id,您必须创建<code>const ObjectID = require('mongodb').ObjectID;</code> ,然后使用它调用<code>new ObjectID(THE_ID)</code> 。一定要将MongoDB添加为依赖项。您可以在以下示例中看到: <pre> passport.serializeUser((user,done)=> {
|
||||
done(null,user._id);
|
||||
}); </pre><br><pre> passport.deserializeUser((id,done)=> {
|
||||
db.collection( '用户')。findOne(
|
||||
{_id:new ObjectID(id)},
|
||||
(错误,doc)=> {
|
||||
完成(null,doc);
|
||||
}
|
||||
);
|
||||
}); </pre>注意:这个deserializeUser将抛出一个错误,直到我们在下一步中设置数据库,因此注释掉整个块并在函数deserializeUser中调用<code>done(null, null)</code> 。当您认为自己已经做对时,请提交您的页面。 </section>
|
||||
<section id='description'>
|
||||
注意,本项目在<a href='https://glitch.com/#!/import/github/freeCodeCamp/boilerplate-advancednode/'>这个 Glitch 项目</a>的基础上进行开发,你也可以从 <a href='https://github.com/freeCodeCamp/boilerplate-advancednode/'>GitHub</a> 上克隆。
|
||||
序列化和反序列化在身份认证中是很重要的概念。序列化一个对象就是将其内容转换成一个体积很小的 <em>key</em>,后续可以通过这个 <em>key</em> 反序列化为原始对象。这样,服务器就可以在用户未登录时识别用户,或者说给这个用户一个唯一标识,用户也不需要在每次访问不同页面时都给服务器发送用户名和密码。
|
||||
我们需要用到序列化和反序列化的方法来进行配置。passport 为我们提供了<code>passport.serializeUser( OURFUNCTION )</code>和<code>passport.deserializeUser( OURFUNCTION )</code>两个方法。
|
||||
<code>serializeUser</code>方法接收两个参数,分别是表示用户的对象和一个回调函数。其中,回调函数的返回值应为这个用户的唯一标识符:最简单的写法就是让它返回用户的<code>_id</code>,这个<code>_id</code>属性是 MongoDB 为用户创建的唯一字段。类似地,反序列化也接收两个参数,分别是在序列化时生成的标识符以及一个回调函数。在回调函数里,我们需要根据根据传入的标识符(比如 _id)返回表示用户的对象。为了在 MongoDB 中通过 query(查询语句)获取 _id 字段,首先我们需要引入 MongoDB 的<code>ObjectID</code>方法:<code>const ObjectID = require('mongodb').ObjectID;</code>;然后调用它:<code>new ObjectID(THE_ID)</code>。当然,这一切的前提都是先引入 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 前,<code>deserializeUser</code>会抛出错误。因此,现在请先注释掉上面的代码,在回调函数中仅仅调用<code>done(null, null)</code>即可。
|
||||
完成上述要求后,你就可以在左边提交你的页面链接。
|
||||
</section>
|
||||
|
||||
## Instructions
|
||||
<section id="instructions">
|
||||
<section id='instructions'>
|
||||
|
||||
</section>
|
||||
|
||||
## Tests
|
||||
@ -27,13 +42,13 @@ localeTitle: 用户对象的序列化
|
||||
|
||||
```yml
|
||||
tests:
|
||||
- text: 序列化用户功能正确
|
||||
- text: 应存在正确的<code>serializeUser</code>方法。
|
||||
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: 反序列化用户功能正确
|
||||
- text: 应存在正确的<code>deserializeUser</code>方法。
|
||||
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: Mongodb正确要求包括ObjectId
|
||||
- text: 注释掉的代码中应包含<code>ObjectId</code>。
|
||||
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); })
|
||||
|
||||
```
|
||||
@ -49,6 +64,11 @@ tests:
|
||||
<section id='solution'>
|
||||
|
||||
```js
|
||||
// solution required
|
||||
/**
|
||||
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.
|
||||
*/
|
||||
```
|
||||
|
||||
</section>
|
||||
|
@ -2,42 +2,68 @@
|
||||
id: 5895f700f9fc0f352b528e63
|
||||
title: Set up a Template Engine
|
||||
challengeType: 2
|
||||
videoUrl: ''
|
||||
isHidden: false
|
||||
forumTopicId: 301564
|
||||
localeTitle: 设置模板引擎
|
||||
---
|
||||
|
||||
## Description
|
||||
<section id="description">提醒一下,这个项目是基于<a href="https://glitch.com/#!/import/github/freeCodeCamp/boilerplate-advancednode/">Glitch</a>的以下入门项目构建的,或者是从<a href="https://github.com/freeCodeCamp/boilerplate-advancednode/">GitHub</a>克隆的。模板引擎使您可以在应用程序中使用静态模板文件(例如用<em>Pug</em>编写的文件)。在运行时,模板引擎将模板文件中的变量替换为可由服务器提供的实际值,并将模板转换为静态HTML文件,然后将其发送到客户端。这种方法可以更轻松地设计HTML页面,并允许在页面上显示变量,而无需从客户端进行API调用。要设置<em>Pug</em>以便在项目中使用,您需要先在package.json中将其作为依赖项添加。 <code>"pug": "^0.1.0"</code>现在告诉Node / Express使用模板引擎,你必须告诉你的快递<b>应用程序</b> <b>将</b> 'pug' <b>设置</b>为'view-engine'。 <code>app.set('view engine', 'pug')</code>最后,你应该改变请求您响应该指数路线<code>res.render</code>与路径视图<em>意见/哈巴狗/ index.pug。</em>如果一切按计划进行,您应该刷新应用程序主页并看到一条小消息,说您已成功从我们的Pug文件中删除Pug!当您认为自己已经做对时,请提交您的页面。 </section>
|
||||
|
||||
<section id='description'>
|
||||
注意,本项目在<a href='https://glitch.com/#!/import/github/freeCodeCamp/boilerplate-advancednode/'>这个 Glitch 项目</a>的基础上进行开发,你也可以从 <a href='https://github.com/freeCodeCamp/boilerplate-advancednode/'>GitHub</a> 上克隆。
|
||||
你可以在应用的模版引擎中使用静态模板文件(如那些写在<em>Pug</em>里的)。在运行时,模版引擎会用服务端的真实数据替换掉模版文件中的变量,然后将模版转译成发送给客户端的 HTML 静态文件。这样可以轻松地构造 HTML 页面,允许在页面直接显示变量内容而不需要发送 API 请求。
|
||||
为了在项目中使用 <em>Pug</em>,你需要在 package.json 中添加依赖<code>"pug": "^0.1.0"</code>
|
||||
|
||||
为了在 Node/Express 中使用 pug 作为模版引擎,你需要在 express 中将 <b>app</b> 的 “view-engine” 设置为 “pug”,就像这样:<code>app.set('view engine', 'pug')</code>。
|
||||
|
||||
如果没有正确的 <em>render</em> <em>'views/pug'</em> 路径下的 index 文件,页面将不会被加载。
|
||||
|
||||
最后, 你需要使用<code>res.render</code>方法渲染 <em>views/pug/index.pug</em> 页面来作为路由请求的返回。
|
||||
|
||||
如果一切顺利,刷新一下应用的主页就可以看到 Pug 成功加载的提示,这时你就可以提交你的页面了。
|
||||
|
||||
</section>
|
||||
|
||||
## Instructions
|
||||
<section id="instructions">
|
||||
|
||||
<section id='instructions'>
|
||||
|
||||
</section>
|
||||
|
||||
## Tests
|
||||
|
||||
<section id='tests'>
|
||||
|
||||
```yml
|
||||
tests:
|
||||
- text: 帕格是一个依赖
|
||||
- text: "项目中应使用 'pug' 作为依赖。"
|
||||
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: 查看引擎是帕格
|
||||
- text: 项目中应使用 Pug 作为模版引擎。
|
||||
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: 帕格正在工作
|
||||
- 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 应该生效。
|
||||
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); })
|
||||
|
||||
```
|
||||
|
||||
</section>
|
||||
|
||||
## Challenge Seed
|
||||
|
||||
<section id='challengeSeed'>
|
||||
|
||||
</section>
|
||||
|
||||
## Solution
|
||||
|
||||
<section id='solution'>
|
||||
|
||||
```js
|
||||
// solution required
|
||||
/**
|
||||
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.
|
||||
*/
|
||||
```
|
||||
|
||||
</section>
|
||||
|
@ -2,19 +2,35 @@
|
||||
id: 5895f70cf9fc0f352b528e65
|
||||
title: Set up Passport
|
||||
challengeType: 2
|
||||
videoUrl: ''
|
||||
localeTitle: 设置护照
|
||||
isHidden: false
|
||||
forumTopicId: 301565
|
||||
localeTitle: 设置 Passport
|
||||
---
|
||||
|
||||
## Description
|
||||
<section id="description">提醒一下,这个项目是基于<a href="https://glitch.com/#!/import/github/freeCodeCamp/boilerplate-advancednode/">Glitch</a>的以下入门项目构建的,或者是从<a href="https://github.com/freeCodeCamp/boilerplate-advancednode/">GitHub</a>克隆的。是时候设置<em>Passport,</em>这样我们终于可以开始允许用户注册或登录帐户了!除了Passport,我们还将使用Express-session来处理会话。使用此中间件将会话ID保存为客户端中的cookie,并允许我们使用服务器上的该ID访问会话数据。这样,我们将个人帐户信息保留在客户端使用的cookie之外,以验证我们的服务器是否经过身份验证,并保留<em>密钥</em>以访问存储在服务器上的数据。要设置Passport以便在项目中使用,您需要先在package.json中将其作为依赖项添加。 <code>"passport": "^0.3.2"</code>此外,现在还要将Express-session添加为依赖项。 Express-session拥有大量可以使用的高级功能,但现在我们只是要使用基础知识! <code>"express-session": "^1.15.0"</code>您需要立即设置会话设置并初始化Passport。一定要先创建变量'session'和'passport',分别要求'express-session'和'passport'。要设置您要使用的快速应用程序使用会话,我们将仅定义几个基本选项。请务必将“SESSION_SECRET”添加到.env文件中,并为其提供随机值。这用于计算用于加密cookie的哈希值! <pre> app.use(会话({
|
||||
secret:process.env.SESSION_SECRET,
|
||||
resave:是的,
|
||||
saveUninitialized:true,
|
||||
})); </pre>您也可以继续告诉您的快递应用程序<b>使用</b> 'passport.initialize()'和'passport.session()'。 (例如, <code>app.use(passport.initialize());</code> )当您认为自己正确时,请提交您的页面。如果您遇到错误,可以<a href="https://gist.github.com/JosephLivengood/338a9c5a326923c3826a666d430e65c3">在这里查看</a>到目前为止完成的项目。 </section>
|
||||
<section id='description'>
|
||||
注意,本项目在<a href='https://glitch.com/#!/import/github/freeCodeCamp/boilerplate-advancednode/'>这个 Glitch 项目</a>的基础上进行开发,你也可以从 <a href='https://github.com/freeCodeCamp/boilerplate-advancednode/'>GitHub</a> 上克隆。
|
||||
现在我们来创建 <em>Passport</em>,最终我们需要用它来实现用户注册和登录。除了 Passport,我们会用 express-session 来处理 session(会话)。在客户端,我们可以用这个中间件把会话 id 储存到 cookie,并可以通过服务器上的 id 访问会话数据。通过这种方式,我们可以无需把用户信息存到 cookie 来完成用户的验证。
|
||||
为了在你的项目中使用 Passport,首先你需要在 package.json 文件中添加依赖:<code>"passport": "^0.3.2"</code>
|
||||
此外,还需要添加 express-session 作为依赖,就像这样:<code>"express-session": "^1.15.0"</code>。express-session 有许多高级特性,但我们暂时只需要了解其基础特性。
|
||||
现在,我们需要配置 session 并初始化 Passport。请先创建变量<code>session</code>和<code>passport</code>引入 express-session 和 passport。
|
||||
为了让 express 应用可以使用 session,我们需要添加一些基础选项。请在 .env 文件中添加字段<code>SESSION_SECRET</code>,并给它赋一个随机值,便于加密 cookie、计算哈希。
|
||||
|
||||
```js
|
||||
app.use(session({
|
||||
secret: process.env.SESSION_SECRET,
|
||||
resave: true,
|
||||
saveUninitialized: true,
|
||||
}));
|
||||
```
|
||||
|
||||
还有,我们需要让 express 使用<code>passport.initialize()</code>和<code>passport.session()</code>。为此,你需要这样写:<code>app.use(passport.initialize());</code>。
|
||||
完成之后就可以提交你的页面了。如果运行出错,你可以在<a href='https://gist.github.com/JosephLivengood/338a9c5a326923c3826a666d430e65c3'>这里</a>检查项目的完成情况。
|
||||
</section>
|
||||
|
||||
## Instructions
|
||||
<section id="instructions">
|
||||
<section id='instructions'>
|
||||
|
||||
</section>
|
||||
|
||||
## Tests
|
||||
@ -22,13 +38,13 @@ localeTitle: 设置护照
|
||||
|
||||
```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应用程序使用新的依赖项
|
||||
- text: express 应调用 passport 的方法。
|
||||
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: 正确设置会话和会话密钥
|
||||
- text: 应正确设置 session 和 session secret。
|
||||
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); })
|
||||
|
||||
```
|
||||
@ -44,6 +60,11 @@ tests:
|
||||
<section id='solution'>
|
||||
|
||||
```js
|
||||
// solution required
|
||||
/**
|
||||
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.
|
||||
*/
|
||||
```
|
||||
|
||||
</section>
|
||||
|
@ -2,18 +2,40 @@
|
||||
id: 589fc830f9fc0f352b528e74
|
||||
title: Set up the Environment
|
||||
challengeType: 2
|
||||
videoUrl: ''
|
||||
isHidden: false
|
||||
forumTopicId: 301566
|
||||
localeTitle: 设置环境
|
||||
---
|
||||
|
||||
## Description
|
||||
<section id="description">提醒一下,这个项目是基于<a href="https://glitch.com/#!/import/github/freeCodeCamp/boilerplate-socketio/">Glitch</a>的以下入门项目构建的,或者是从<a href="https://github.com/freeCodeCamp/boilerplate-socketio/">GitHub</a>克隆的。将Socket.IO添加为依赖项,并在服务器中要求/实例化它,定义为'io',并将http服务器作为参数。 <code>const io = require('socket.io')(http);</code>需要处理的第一件事是从客户端侦听新连接。 <dfn>on</dfn>关键字就是这样 - 监听特定事件。它需要2个参数:一个包含所发出事件标题的字符串,以及一个用于传递数据的函数。在我们的连接侦听器的情况下,我们使用<em>socket</em>来定义第二个参数中的数据。套接字是连接的个人客户端。要在我们的服务器上侦听连接,请在项目中的注释之间添加以下内容: <pre> io.on('connection',socket => {
|
||||
console.log('用户已连接');
|
||||
}); </pre>现在,对于客户端进行连接,您只需要将以下内容添加到client.js中,该客户端经过身份验证后由页面加载: <pre> / * global io * /
|
||||
var socket = io(); </pre>注释会抑制您通常会看到的错误,因为文件中未定义“io”。我们已经在chat.pug页面上的Socket.IO库中添加了一个可靠的CDN。现在尝试加载您的应用并进行身份验证,您应该在服务器控制台中看到“用户已连接”! <strong>注意</strong> <br> <code>io()</code>仅在连接到同一URL /服务器上托管的套接字时起作用。要连接到其他地方托管的外部套接字,您可以使用<code>io.connect('URL');</code> 。当您认为自己已经做对时,请提交您的页面。 </section>
|
||||
<section id='description'>
|
||||
注意,本项目在<a href='https://glitch.com/#!/import/github/freeCodeCamp/boilerplate-socketio/'>这个 Glitch 项目</a>的基础上进行开发,你也可以从 <a href='https://github.com/freeCodeCamp/boilerplate-socialauth/'>GitHub</a> 上克隆。
|
||||
现在,我们需要添加 Socket.IO 作为依赖,在你的代码中引入,给它传入参数 http 并实例化,将其命名为<code>io</code>,就像这样:<code>const io = require('socket.io')(http);</code>
|
||||
我们需要处理的第一件事是监听从客户端发出的连接事件,我们可以调用 <em>on</em> 方法来监听具体的事件。它接收两个参数:一个是发出的事件的标题字符串,另一个是后续用来传递数据的回调函数。在这个回调函数中,我们用 <em>socket</em> 来代表它所包含的数据。简单来说,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'
|
||||
<strong>注意:</strong><br>只有在连接到处于同一个 url/server 上的 socket 时,<code>io()</code>才可以正常执行。如果需要连接到外部的 socket,就需要这样调用:<code>io.connect('URL');</code>。
|
||||
完成上述要求后,你就可以在左边提交你的页面链接。
|
||||
</section>
|
||||
|
||||
## Instructions
|
||||
<section id="instructions">
|
||||
<section id='instructions'>
|
||||
|
||||
</section>
|
||||
|
||||
## Tests
|
||||
@ -21,13 +43,13 @@ var socket = io(); </pre>注释会抑制您通常会看到的错误,因为
|
||||
|
||||
```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); })
|
||||
|
||||
```
|
||||
@ -43,6 +65,11 @@ tests:
|
||||
<section id='solution'>
|
||||
|
||||
```js
|
||||
// solution required
|
||||
/**
|
||||
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.
|
||||
*/
|
||||
```
|
||||
|
||||
</section>
|
||||
|
@ -2,15 +2,26 @@
|
||||
id: 5895f70bf9fc0f352b528e64
|
||||
title: Use a Template Engine's Powers
|
||||
challengeType: 2
|
||||
videoUrl: ''
|
||||
localeTitle: 使用模板引擎的权力
|
||||
isHidden: false
|
||||
forumTopicId: 301567
|
||||
localeTitle: 使用模板引擎
|
||||
---
|
||||
|
||||
## Description
|
||||
<section id="description">提醒一下,这个项目是基于<a href="https://glitch.com/#!/import/github/freeCodeCamp/boilerplate-advancednode/">Glitch</a>的以下入门项目构建的,或者是从<a href="https://github.com/freeCodeCamp/boilerplate-advancednode/">GitHub</a>克隆的。使用模板引擎的最大特点之一是能够将变量从服务器传递到模板文件,然后再将其呈现为HTML。在您的Pug文件中,您将通过引用变量名称作为<code>#{variable_name}</code>与元素上的其他文本内联,或者在元素上使用相等的一侧而不使用空格(例如<code>p= variable_name</code>来设置该<code>p= variable_name</code> 。 p元素文本等于变量。我们强烈建议在他们的Githubs自述文件中<a href="https://github.com/pugjs/pug">查看</a> Pug的语法和结构。 Pug就是使用空格和制表符来显示嵌套元素,并减少制作漂亮网站所需的代码量。查看项目中包含的我们的pug文件'index.pug',我们使用变量<em>title</em>和<em>message</em>要从我们的服务器单独传递它们,您需要将一个对象作为第二个参数添加到<em>res.render中</em> ,并带有变量和他们的价值。例如,传递此对象以设置索引视图的变量: <code>{title: 'Hello', message: 'Please login'</code>它应该看起来像: <code>res.render(process.cwd() + '/views/pug/index', {title: 'Hello', message: 'Please login'});</code>现在刷新页面,您应该在视图中呈现的那些值在index.pug文件中列出的正确位置!当您认为自己已经做对时,请提交您的页面。 </section>
|
||||
<section id='description'>
|
||||
注意,本项目在<a href='https://glitch.com/#!/import/github/freeCodeCamp/boilerplate-advancednode/'>这个 Glitch 项目</a>的基础上进行开发,你也可以从 <a href='https://github.com/freeCodeCamp/boilerplate-advancednode/'>GitHub</a> 上克隆。
|
||||
模版引擎最大的特点之一就是在 HTML 页面展示之前,可以从服务端传变量到模版文件。
|
||||
在 Pug 文件中,你可以用变量名来调用变量,比如写成<code>#{variable_name}</code>来实现行内调用,或像<code>p= variable_name</code>把元素与变量直接写在一起,这表示 p 元素的内容等价于这个变量。
|
||||
建议大家在 <a href='https://github.com/pugjs/pug'>Pug 的 README</a> 里看看它的语法和用法,这样你写出的代码会相对简练。另外要注意,Pug 使用缩进来表示嵌套的代码块。
|
||||
在 pug 的 'index.pug' 文件中,我们使用了 <em>title</em> 和 <em>message</em> 两个变量。
|
||||
为了从服务器传递这些信息,你需要给 <em>res.render</em> 的第二个参数传入一个对象,其中包含变量对应的值。比如,如果你想传递对象<code>{title: 'Hello', message: 'Please login'</code>到你的主页,那么应该这样写:
|
||||
<code>res.render(process.cwd() + '/views/pug/index', {title: 'Hello', message: 'Please login'});</code>
|
||||
刷新页面,如果页面中数据显示正确,你就可以提交你的页面了。
|
||||
</section>
|
||||
|
||||
## Instructions
|
||||
<section id="instructions">
|
||||
<section id='instructions'>
|
||||
|
||||
</section>
|
||||
|
||||
## Tests
|
||||
@ -18,7 +29,7 @@ localeTitle: 使用模板引擎的权力
|
||||
|
||||
```yml
|
||||
tests:
|
||||
- text: 帕格渲染变量正确
|
||||
- text: Pug 应正确地展示变量。
|
||||
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); })
|
||||
|
||||
```
|
||||
@ -34,6 +45,11 @@ tests:
|
||||
<section id='solution'>
|
||||
|
||||
```js
|
||||
// solution required
|
||||
/**
|
||||
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.
|
||||
*/
|
||||
```
|
||||
|
||||
</section>
|
||||
|
Reference in New Issue
Block a user