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.svelte
的新文件并在其中添加一个表单。您应该使用 Meteor.loginWithPassword(username, password);
来使用提供的输入对用户进行身份验证。
imports/ui/LoginForm.svelte
<script>
import { Meteor } from 'meteor/meteor';
let username = "";
let password = "";
const handleSubmit = () => {
Meteor.loginWithPassword(username, password);
}
</script>
<form class="login-form" on:submit|preventDefault={handleSubmit}>
<div>
<label htmlFor="username">Username</label>
<input
type="text"
placeholder="Username"
name="username"
required
bind:value={username}
/>
</div>
<div>
<label htmlFor="password">Password</label>
<input
type="password"
placeholder="Password"
name="password"
required
bind:value={password}
/>
</div>
<div>
<button type="submit">Log In</button>
</div>
</form>
好的,现在您有了表单,让我们使用它。
7.4:要求进行身份验证
我们的应用应该只允许经过身份验证的用户访问其任务管理功能。
当我们没有经过身份验证的用户时,我们可以通过渲染 LoginForm
组件来实现这一点,否则我们将返回表单、筛选器和列表组件。
您可以从 Meteor.user()
获取经过身份验证的用户或 null。然后,您可以验证您是否有一个已登录的用户,如果有,则渲染应用,否则,您渲染 LoginForm
imports/ui/App.svelte
<script>
import { TasksCollection } from '../api/TasksCollection';
import { Meteor } from 'meteor/meteor';
..
let user = null;
$m: {
user = Meteor.user();
..
}
</script>
<div class="app">
..
<div class="main">
{#if user}
<TaskForm user={user}/>
<div class="filter">
<button on:click={() => setHideCompleted(!hideCompleted)}>
{hideCompleted ? 'Show All' : 'Hide Completed'}
</button>
</div>
<ul class="tasks">
{#each tasks as task (task._id)}
<Task task={task} />
{/each}
</ul>
{:else}
<LoginForm />
{/if}
</div>
</div>
7.5:登录表单样式
好的,现在让我们为登录表单设置样式。
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
以使用您的 meteorite
用户作为所有者添加种子任务。
确保在此更改后重新启动服务器,以便 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.svelte
<script>
..
$m: {
user = Meteor.user();
const userFilter = user ? { userId: user._id } : {};
const pendingOnlyFilter = { ...hideCompletedFilter, ...userFilter };
tasks = user
? TasksCollection.find(
hideCompleted ? pendingOnlyFilter : userFilter,
{ sort: { createdAt: -1 } }
).fetch()
: [];
incompleteCount = user
? TasksCollection.find(pendingOnlyFilter).count()
: 0;
..
}
</script>
<div class="app">
..
<div class="main">
..
<ul class="tasks">
{#each tasks as task (task._id)}
<Task task={task} />
{/each}
</ul>
..
</div>
</div>
还要更新 insert
调用,以在 TaskForm
中包含字段 userId
。您应该将用户从 App
组件传递到 TaskForm
。
imports/ui/TaskForm.svelte
<script>
..
export let user = null;
..
const handleSubmit = () => {
// Insert a task into the collection
TasksCollection.insert({
text: newTask,
createdAt: new Date(), // current time
userId: user._id,
});
..
}
</script>
7.8:注销
我们还可以通过在应用栏下方显示所有者的用户名来更好地组织我们的任务。让我们添加一个新的 div
,用户可以在其中点击并退出应用。
imports/ui/App.svelte
<script>
..
const logout = () => Meteor.logout();
</script>
..
<div class="app">
..
<div class="main">
{#if user}
<div class="user" on:click={logout}>
{user.username} 🚪
</div>
..
请记住也要设置用户名的样式。
client/main.css
.user {
display: flex;
align-self: flex-end;
margin: 8px 16px 0;
font-weight: bold;
}
呼!您在此步骤中做了很多事情。对用户进行身份验证,在任务中设置用户并为用户提供退出应用的方法。
您的应用现在应该如下所示
![](/simple-todos/assets/step07-login.png)
![](/simple-todos/assets/step07-logout.png)
回顾:您可以查看此步骤结束时代码应如何编写 此处
在下一步中,我们将开始使用方法,以便仅在检查某些条件后更改数据。