markdown 挑战18:多用户

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了markdown 挑战18:多用户相关的知识,希望对你有一定的参考价值。

In this challenge you will update the Noteful to support multiple users. Each user will have their own set of notes, folder and tags. And you must ensure that a user cannot read, modify or delete another user's items.

## Requirements

* Update Notes, Folder and Tags models and seed data individual users
* Protect against invalid `folderId` or `tag` references

## Update Note schema and endpoints

To get started, update the Note schema to support a User reference. Reseed the database with Notes that contain a `userId`. And update all of the notes routes to reference the current user id.

### Update Note Schema and reseed the DB

The User reference in the Note schema is similar to the Folder reference. Each Note will refer to a User similar to how a Note can refer to a folder. However, the Folder reference is optional whereas the User reference is required.

Your task. In the `/models/notes.js` file, add a `userId`. And set the `type` to `ObjectId`, reference the `User` model and set `required` to be `true`. Below is an example.

```js
  userId: { type: mongoose.Schema.Types.ObjectId, ref: 'User', required: true }
```

Next you will need to update your `/db/seed/users.json` with a digest (aka hash) of a password. You can generate new digests with the following script. Create a `/utils/hash-password.js` script and add the following. Then execute the script to get a digest.

```js
const bcrypt = require('bcryptjs');
const password = 'baseball';

/* Hash a password with cost-factor 10, then run compare to verify */
bcrypt.hash(password, 10)
  .then(digest => {
    console.log('digest:', digest);
    return digest;
  })
  .then(hash => {
    return bcrypt.compare(password, hash);
  })
  .then(valid => {
    console.log('isValid: ', valid);
  })
  .catch(err => {
    console.error('error', err);
  });
```

Update `/db/seed/users.json` by replacing the plain-text password with a digest (aka hash) of a password. Below is an example. 

```json
  {
    "_id": "333333333333333333333300",
    "fullname": "Bob User",
    "username": "bobuser",
    "password": "$2a$10$QJCIX42iD5QMxLRgHHBJre2rH6c6nI24UysmSYtkmeFv6X8uS1kgi"
  },
```

> Note: The digest above is for the string 'password'.

Finally, update `/utils/seed-database.js` script. Require the User model and seed data. And add an `insertMany` and `createIndexes` similar to Folders and Tags.

Verify the seed database script worked by checking the database. You should see the users from the `/db/seed/users.json` along with the hashed password.

Using Postman, test the update by POSTing a `username` and `password` to the `/api/login` endpoint. You should be able to login and receive a JWT.

### Update `/notes` endpoints

Next, update the `/notes` endpoints to ensure that a user can only interact with their own notes.

In each endpoint, capture the current user id from `req.user` and update the query. Note, you may need to change the Mongoose method. For instance, the GET `/notes/:id` example below uses `Note.findOne({ _id: id, userId })` instead of `Note.findById(id)`.

```js
router.get('/:id', (req, res, next) => {
  const { id } = req.params;
  const userId = req.user.id;

  if (!mongoose.Types.ObjectId.isValid(id)) {
    const err = new Error('The `id` is not valid');
    err.status = 400;
    return next(err);
  }

  Note.findOne({ _id: id, userId })
    .populate('tags')
    .then(result => {
      if (result) {
        res.json(result);
      } else {
        next();
      }
    })
    .catch(err => {
      next(err);
    });
});
```

Your turn.

Update the other Note endpoints and check the changes using Postman. Verify that a user can only view notes that belong to them, and ensure that a user cannot create, modify or delete a note which does not belong to them.

> Note: At this point, a user can create or update a note and assign it a folder or tag created by another user. We'll tackle this problem at the towards the end of the challenge.

## Update Folder and Tag schemas and endpoints

The notes are updated but folders and tags are still shared among all the users. Currently, a user can view, modify and delete another user's folders and tags. To prevent this, update the Folder and Tag schemas to include a `userId` that reference the User model, similar to the Note schema with one exception. Folders and Tags must be unique per user. In other words, the database can contain multiple Folders or Tags with the same name. But each user may only not have duplicate folders or tags.

### Add User Id reference to Folder and Tag schemas

Your task, update the folder and tag schemas to include a `userId` that references the `User` model. Refer to the Note schema as an example.

### Create Folder and Tag Compound Indexes on schemas

Currently, the folder and tag names are set to `unique: true`. This restricts the database to one item with that name for **all** users. The requirement is folder or tag names should be unique for each user. The solution is to use **compound indexes**.

Your task, update the folder and tag schemas. Remove the `unique: true` option from the `name` and create a unique compound index using `userId` and the `name`.

Below is an example:

```js
folderSchema.index({ name: 1, userId: 1}, { unique: true });
```

More information is available in the Mongoose and Mongo documentation:

* [Mongoose Indexes](http://mongoosejs.com/docs/guide.html#indexes)
* [Mongo Compound Index](https://docs.mongodb.com/manual/core/index-compound)


### Update `/folders` and `/tags` endpoints

The next challenge is to update the folder and tags endpoints and queries with the current user id. But before working on the endpoints, update the seed data and repopulate the database.

Your challenge, update the `/folders` and `/tags` endpoints to ensure that a user can only interact with their own items. Like notes, capture the current user id from `req.user` and update the query in each endpoint.

Check your changes in Postman. Verify that a user can only view items that belong to them, and ensure that a user cannot create, modify or delete a folder or tag which does not belong to them.

## Validate Folders and Tags Ids

The application still has one issue - a user can create or update a note and assign it a folder or tag belonging to another user. This breaks the isolation between users.

Your challenge is to update the POST and PUT `/api/notes` endpoints to verify that the incoming note's folder `id` and `tags` belong to the current user before updating the database. 

For folders, verify the `folderId` is a valid `ObjectId` and the item belongs to the current user. If the validation fails, then return an error message 'The `folderId` is not valid' with status 400.

For tags, first verify the `tags` property is an Array, if validation fails, then return 'The `tags` property must be an array' with a status 400. Then verify that each tag id in the array is a valid `ObjectId`. And verify all the tags belong to the current user. If the validation fails, then return an error message 'The `tags` array contains an invalid `id`' with status 400.

Test the endpoint using Postman. Attempt to POST and PUT notes with both valid and invalid folder ids and tags ids.

# Create User Tests

Using [Node JWT Auth](https://github.com/Thinkful-Ed/node-jwt-auth) as a guide, create integration tests to verify Users are validated and created properly.

## Create a User tests

Create a `/test/users.test.js` file and copy in the starter from this [gist](https://gist.github.com/cklanac/2e82a1a8e151c79779293a3615877fcc)

The setup has been completed for you. Your challenge is to update your POST user endpoint and complete the rest of the tests and assertions. Again you can use the [Node JWT Auth](https://github.com/Thinkful-Ed/node-jwt-auth) as a guide.

以上是关于markdown 挑战18:多用户的主要内容,如果未能解决你的问题,请参考以下文章

markdown 值得关注的挑战指数

markdown Certbot与DNS挑战

markdown 挑战11:Mongo基础知识

markdown 挑战11 - Vue简介

markdown 挑战10 - Vue简介

markdown 挑战10:Knex JS测试