7:添加用户账户

7.1:密码认证

Meteor 自带基本的认证和账户管理系统,因此您只需要添加 accounts-password 即可启用用户名和密码认证。

meteor add accounts-password

支持更多认证方法。您可以阅读有关账户系统的更多信息 此处

我们还建议您安装 bcrypt 节点模块,否则您将看到一条警告,提示您正在使用纯 JavaScript 实现。

meteor npm install --save bcrypt

您应该始终使用 meteor npm 而不是仅使用 npm,这样您才能始终使用 Meteor 锁定的 npm 版本,这有助于避免因不同版本的 npm 安装不同模块而导致的问题。

7.2:创建用户账户

现在您可以为我们的应用创建默认用户,我们将使用 meteorite 作为用户名,如果我们在数据库中找不到它,我们只需在服务器启动时创建一个新用户。

server/main.js

import { Meteor } from 'meteor/meteor';
import { Accounts } from 'meteor/accounts-base';
import { TasksCollection } from '/imports/api/TasksCollection';

..

const SEED_USERNAME = 'meteorite';
const SEED_PASSWORD = 'password';

Meteor.startup(() => {
  if (!Accounts.findUserByUsername(SEED_USERNAME)) {
    Accounts.createUser({
      username: SEED_USERNAME,
      password: SEED_PASSWORD,
    });
  }
  ..
});

您在应用 UI 中应该还看不到任何变化。

7.3:登录表单

您需要为用户提供输入凭据和进行身份验证的方法,为此我们需要一个表单。

创建一个名为 LoginForm.vue 的新文件,并在其中添加一个表单。您应该使用 Meteor.loginWithPassword(username, password); 来使用提供的输入对用户进行身份验证。

imports/ui/components/LoginForm.vue

<template>
  <form class="login-form" @submit.prevent="handleSubmit">
    <div>
      <label for="username">Username</label>
      <input
          id="username"
          name="username"
          type="text"
          placeholder="Username"
          required
          v-model="username"
      />
    </div>

    <div>
      <label for="password">Password</label>
      <input
          id="password"
          name="password"
          type="password"
          placeholder="Password"
          required
          v-model="password"
      />
    </div>

    <div>
      <button type="submit">Log In</button>
    </div>
  </form>
</template>

<script>
import { Meteor } from 'meteor/meteor';

export default {
  name: "LoginForm",
  data() {
    return {
      username: "",
      password: ""
    };
  },
  methods: {
    handleSubmit(event) {
      Meteor.loginWithPassword(this.username, this.password);
    }
  },
}
</script>

好的,现在您有一个表单,让我们来使用它。

7.4:需要认证

我们的应用应该只允许已认证的用户访问其任务管理功能。

当我们没有已认证的用户时,我们可以通过返回 LoginForm 组件来实现这一点,否则我们返回表单、过滤器和列表组件。

修改数据容器以获取有关当前登录用户的的信息

imports/ui/App.vue

..
incompleteCount() {
  return TasksCollection.find({ checked: { $ne: true } }).count();
},
currentUser() {
  return Meteor.user();
}
..

然后,我们可以将我们的用户功能包装在一个 <template> 标签中,并在其中添加 v-if 指令,以便在有登录用户时有条件地渲染我们的用户功能

imports/ui/App.vue

..
<div class="main">
  <template v-if="currentUser">
    <TaskForm />
    <div class="filter">
      <button
          v-model="hideCompleted"
          @click="toggleHideCompleted"
      >
        <span v-if="hideCompleted">Show All</span>
        <span v-else>Hide Completed Tasks</span>
      </button>
    </div>
    <ul class="tasks">
      <Task
          class="task"
          v-for="task in tasks"
          v-bind:key="task._id"
          v-bind:task="task"
      />
    </ul>
  </template>
  <template v-else>
    <LoginForm />
  </template>
</div>
..

7.5:登录表单样式

好的,现在让我们来设置登录表单的样式。

将标签和输入的每一对都包装在 div 中,以便在 CSS 中更容易控制它。

client/main.css

.login-form {
  display: flex;
  flex-direction: column;
  height: 100%;

  justify-content: center;
  align-items: center;
}

.login-form > div {
  margin: 8px;
}

.login-form > div > label {
  font-weight: bold;
}

.login-form > div  > input {
  flex-grow: 1;
  box-sizing: border-box;
  padding: 10px 6px;
  background: transparent;
  border: 1px solid #aaa;
  width: 100%;
  font-size: 1em;
  margin-right: 16px;
  margin-top: 4px;
}

.login-form > div > input:focus {
  outline: 0;
}

.login-form > div > button {
  background-color: #62807e;
}

现在您的登录表单应该居中且美观。

7.6:服务器启动

从现在开始,每个任务都应该有一个所有者。因此,请转到您的数据库,就像您之前学到的那样,并从中删除所有任务。

db.tasks.remove({});

更改您的 server/main.js 以使用您的 meteoriote 用户作为所有者来添加种子任务。

请确保在此更改后重新启动服务器,以便 Meteor.startup 块再次运行。这很可能自动发生,因为您将在服务器端代码中进行更改。

server/main.js

import { Meteor } from 'meteor/meteor';
import { Accounts } from 'meteor/accounts-base';
import { TasksCollection } from '/imports/api/TasksCollection';

const insertTask = (taskText, user) =>
  TasksCollection.insert({
    text: taskText,
    userId: user._id,
    createdAt: new Date(),
  });

const SEED_USERNAME = 'meteorite';
const SEED_PASSWORD = 'password';

Meteor.startup(() => {
  if (!Accounts.findUserByUsername(SEED_USERNAME)) {
    Accounts.createUser({
      username: SEED_USERNAME,
      password: SEED_PASSWORD,
    });
  }

  const user = Accounts.findUserByUsername(SEED_USERNAME);

  if (TasksCollection.find().count() === 0) {
    [
      'First Task',
      'Second Task',
      'Third Task',
      'Fourth Task',
      'Fifth Task',
      'Sixth Task',
      'Seventh Task',
    ].forEach(taskText => insertTask(taskText, user));
  }
});

请注意,我们正在使用一个名为 userId 的新字段以及我们的用户 _id 字段,我们还正在设置 createdAt 字段。

7.7:任务所有者

现在,您可以在 UI 中通过已认证的用户过滤任务。在从 Mini Mongo 获取任务时,使用用户 _id 将字段 userId 添加到您的 Mongo 选择器中。

imports/ui/App.vue

..
meteor: {
    tasks() {
      if (!this.currentUser) {
        return [];
      }
    
        const hideCompletedFilter = { isChecked: { $ne: true } };
        
        const userFilter = this.currentUser ? { userId: this.currentUser._id } : {};
        
        const pendingOnlyFilter = { ...hideCompletedFilter, ...userFilter };
        
        return TasksCollection.find(
          this.hideCompleted ? pendingOnlyFilter : userFilter,
          {
            sort: { createdAt: -1 },
          }
        ).fetch();
    },
    incompleteCount() {
      return TasksCollection.find({ isChecked: { $ne: true }, userId: this.currentUser._id }).count();
    },
    currentUser() {
      return Meteor.user();
    }
}
..

还更新 insert 调用以在 TaskForm 中包含字段 userId。您应该将用户从 App 组件传递到 TaskForm

imports/ui/components/TaskForm.vue

..
methods: {
  handleSubmit(event) {

    if (this.newTask.length === 0) return;

    const user = Meteor.user()

    TasksCollection.insert({
      text: this.newTask.trim(),
      createdAt: new Date(), // current time
      userId: user._id
    });

    // Clear form
    this.newTask = "";
  }
},
..

7.8:注销

我们还可以通过在应用栏下方显示所有者的用户名来更好地组织我们的任务。您可以在我们的 template 开始标签之后添加一个新的 div

您可以在其中添加一个 onClick 处理程序以注销用户。这非常简单,只需在其上调用 Meteor.logout() 即可。

imports/ui/App.vue

..
  const logout = () => Meteor.logout();

  return (
..
    <template v-if="currentUser">
      <div class="user" v-on:click="logout">
        {{currentUser.username}} 🚪
      </div>
      <TaskForm />
..
      methods: {
          toggleHideCompleted() {
            this.hideCompleted = !this.hideCompleted;
          },
          logout() {
            Meteor.logout();
          }
      },
..

请记住也要设置用户名的样式。

client/main.css

.user {
  display: flex;
  cursor: pointer;
  align-self: flex-end;
  margin: 8px 16px 0;
  font-weight: bold;
}

呼!您在此步骤中做了很多工作。对用户进行身份验证,在任务中设置用户,并为用户提供注销的方法。

您的应用应该如下所示

复习:您可以查看此步骤结束时代码应该是什么样子 此处

在下一步中,我们将开始使用方法,仅在检查某些条件后才更改数据。

在 GitHub 上编辑
// 搜索框