-
Notifications
You must be signed in to change notification settings - Fork 0
/
06-adding-users.md.erb
169 lines (127 loc) · 7.5 KB
/
06-adding-users.md.erb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
---
title: Adding Users
slug: adding-users
date: 0006/01/01
number: 6
level: starter
photoUrl: http://www.flickr.com/photos/kroqert/9687074783/
photoAuthor: Bård Harald Krogen
contents: Learn about user accounts in Meteor.|Add all the authentication we'll need for Microscope.|Use the built-in accounts-ui package to get an instant user interface.
paragraphs: 27
---
So far, we've managed to create and display some static fixture data in a sensible fashion and wire it together into a simple prototype.
We've even seen how our UI is responsive to changes in the data, and inserted or changed data appears immediately. Still, our site is hamstrung by the fact that we can't enter data. In fact, we don't even have users yet!
Let's see how we can fix that.
### Accounts: users made simple
In most web frameworks, adding user accounts is a familiar drag. Sure, you have to do it on almost every project, but it's never as easy as it could be. What's more, as soon as you have to deal with OAuth or other 3rd party authentication schemes, things tend to get ugly fast.
Luckily, Meteor has you covered. Thanks to the way Meteor packages can contribute code on both the server (JavaScript) and client (JavaScript, HTML, and CSS) side, we can get an accounts system almost for free.
We could just use Meteor's built-in UI for accounts (with `meteor add accounts-ui`) but since we've built our whole app with Bootstrap, we'll use the `ian:accounts-ui-bootstrap-3` package instead (don't worry, the only difference is the styling). On the command line, we type:
~~~bash
meteor add ian:accounts-ui-bootstrap-3
meteor add accounts-password
~~~
<%= caption "Terminal" %>
Those two commands make the special accounts templates available to us, and we can include them in our site using the `{{> loginButtons}}` helper. A handy tip: you can control on which side your log-in dropdown shows up using the `align` attribute (for example: `{{> loginButtons align="right"}}`).
We'll add the buttons to our header. And since that header is starting to grow larger, let's give it more room in its own template (we'll put it in `client/templates/includes/`). We're also using some extra markup and classes [as specified by Bootstrap](http://getbootstrap.com/components/#navbar) to make sure everything looks nice:
~~~html
<template name="layout">
<div class="container">
{{> header}}
<div id="main">
{{> yield}}
</div>
</div>
</template>
~~~
<%= caption "client/templates/application/layout.html" %>
<%= highlight "3~6" %>
~~~html
<template name="header">
<nav class="navbar navbar-default" role="navigation">
<div class="navbar-header">
<button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#navigation">
<span class="sr-only">Toggle navigation</span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
<a class="navbar-brand" href="{{pathFor 'postsList'}}">Microscope</a>
</div>
<div class="collapse navbar-collapse" id="navigation">
<ul class="nav navbar-nav navbar-right">
{{> loginButtons}}
</ul>
</div>
</nav>
</template>
~~~
<%= caption "client/templates/includes/header.html" %>
Now, when we browse to our app, we see the accounts login buttons in the top right hand corner of our site.
<%= screenshot "6-1", "Meteor's built-in accounts UI" %>
We can use these to sign up, log in, request a change of password, and everything else that a simple site needs for password-based accounts.
To tell our accounts system that we want users to log-in via a username, we simply add an `Accounts.ui` config block in a new `config.js` file inside `client/helpers/`:
~~~js
Accounts.ui.config({
passwordSignupFields: 'USERNAME_ONLY'
});
~~~
<%= caption "client/helpers/config.js" %>
<%= commit "6-1", "Added accounts and added template to the header" %>
### Creating Our First User
Go ahead and sign up for an account: the "Sign in" button will change to show your username. This confirms that a user account has been created for you. But where is that user account data coming from?
By adding the `accounts` package, Meteor has created a special new collection, which can be accessed at `Meteor.users`. To see it, open your browser console and type:
~~~js
❯ Meteor.users.findOne();
~~~
<%= caption "Browser console" %>
The console should return an object representing your user object; if you take a look, you can see that your username is in there, as well as an `_id` that uniquely identifies you. Note that you can also get the currently logged-in user with `Meteor.user()`.
Now log out and sign up again with a different username. `Meteor.user()` should now return a second user. But wait, let's run:
~~~js
❯ Meteor.users.find().count();
1
~~~
<%= caption "Browser console" %>
The console returns 1. Hold on, shouldn't that be 2? Has the first user been deleted? If you try logging in as that first user again, you'll see that's not the case.
Let's make sure and check in the canonical data-store, the Mongo database. We'll log into Mongo (`meteor mongo` in your terminal) and check:
~~~bash
> db.users.count()
2
~~~
<%= caption "Mongo console" %>
There are definitely two users. So why can we only see a single one at a time in the browser?
### A Mystery Publication!
If you think back to Chapter 4, you might remember that by turning off `autopublish`, we stopped collections from automatically sending all the data from the server into each connected client's local version of the collection. We needed to create a publication and subscription pair to channel the data across.
Yet we never set up any kind of user publication. So how come we can even see any user data at all?
The answer is that the accounts package actually does "auto-publish" the currently logged in user's basic account details no matter what. If it didn't, then that user could never log in to the site!
The accounts package only publishes the *current* user though. This explains why one user can't see another's account details.
So the publication is only publishing one user object per logged-in user (and none when you are not logged in).
What's more, documents in our user collection don't seem to contain the same fields on the server and on the client. In Mongo, a user has a lot of data in it. To see it, just go back to your Mongo terminal and type:
~~~bash
> db.users.find()
{
"_id": "H5kKyxtbkLhmPgtqs",
"createdAt": ISODate("2015-02-10T08:26:48.196Z"),
"profile": {},
"services": {
"password": {
"bcrypt": "$2a$10$yGPywo3/53IHsdffdwe766roZviT03YBGltJ0UG"
},
"resume": {
"loginTokens": [{
"when": ISODate("2015-02-10T08:26:48.203Z"),
"hashedToken": "npxGH7Rmkuxcv098wzz+qR0/jHl0EAGWr0D9ZpOw="
}]
}
},
"username": "sacha"
}
~~~
<%= caption "Mongo console" %>
On the other hand, in the browser the user object is much more pared down, as you can see by typing the equivalent command:
~~~js
❯ Meteor.users.findOne();
Object {_id: "kYdBd9hr3fWPGPcii", username: "tmeasday"}
~~~
<%= caption "Browser console" %>
This example shows us how a local collection can be a *secure subset* of the real database. The logged-in user only sees enough of the real dataset to get the job done (in this case, signing in). This is a useful pattern to learn from, as you'll see later on.
That doesn't mean you can't make more user data public if you want to. You can refer to the [Meteor docs](http://docs.meteor.com/#meteor_users) to see how to optionally publish more fields in the `Meteor.users` collection.