1
1
# @loopback/authentication
2
2
3
- A LoopBack component for authentication support.
3
+ A LoopBack 4 component for authentication support.
4
4
5
5
** This is a reference implementation showing how to implement an authentication component, it is not production ready.**
6
6
7
7
## Overview
8
8
9
9
The component demonstrates how to leverage Passport module and extension points
10
- provided by LoopBack Next to implement an authentication layer.
10
+ provided by LoopBack 4 to implement an authentication layer.
11
11
12
12
## Installation
13
13
@@ -20,18 +20,27 @@ npm install --save @loopback/authentication
20
20
Start by decorating your controller methods with ` @authenticate ` to require
21
21
the request to be authenticated.
22
22
23
+ In this example, we make the user profile available via dependency injection
24
+ using a key available from ` @loopback/authentication ` package.
25
+
23
26
``` ts
24
- // controllers/my-controller.ts
25
- import {UserProfile , authenticate , AuthenticationBindings } from ' @loopback/authentication' ;
26
- import {inject } from ' @loopback/core' ;
27
+ // src/controllers/who-am-i.controller.ts
28
+ import {inject } from ' @loopback/context' ;
29
+ import {
30
+ AuthenticationBindings ,
31
+ UserProfile ,
32
+ authenticate ,
33
+ } from ' @loopback/authentication' ;
27
34
import {get } from ' @loopback/rest' ;
28
35
29
- export class MyController {
30
- constructor (@inject (AuthenticationBindings .CURRENT_USER ) private user : UserProfile ) {}
36
+ export class WhoAmIController {
37
+ constructor (
38
+ @inject (AuthenticationBindings .CURRENT_USER ) private user : UserProfile ,
39
+ ) {}
31
40
32
41
@authenticate (' BasicStrategy' )
33
- @get (' /whoAmI ' )
34
- whoAmI() {
42
+ @get (' /whoami ' )
43
+ whoAmI(): string {
35
44
return this .user .id ;
36
45
}
37
46
}
@@ -42,19 +51,20 @@ in `@authenticate` decorators into Passport Strategy instances.
42
51
Remember to install ` passport ` , ` passport-http ` , ` @types/passport ` , and
43
52
` @types/passport-http ` modules beforehand.
44
53
54
+ ``` shell
55
+ npm install --save passport passport-http
56
+ npm install --save-dev @types/passport @types/passport-http
57
+ ```
58
+
45
59
``` ts
46
- // providers/auth-strategy.ts
47
- import {
48
- inject ,
49
- Provider ,
50
- ValueOrPromise ,
51
- } from ' @loopback/context' ;
60
+ // src/providers/auth-strategy.provider.ts
61
+ import {Provider , inject , ValueOrPromise } from ' @loopback/context' ;
62
+ import {Strategy } from ' passport' ;
52
63
import {
53
64
AuthenticationBindings ,
54
65
AuthenticationMetadata ,
66
+ UserProfile ,
55
67
} from ' @loopback/authentication' ;
56
-
57
- import {Strategy } from ' passport' ;
58
68
import {BasicStrategy } from ' passport-http' ;
59
69
60
70
export class MyAuthStrategyProvider implements Provider <Strategy | undefined > {
@@ -63,8 +73,7 @@ export class MyAuthStrategyProvider implements Provider<Strategy | undefined> {
63
73
private metadata : AuthenticationMetadata ,
64
74
) {}
65
75
66
- value() : ValueOrPromise <Strategy | undefined > {
67
-
76
+ value(): ValueOrPromise <Strategy | undefined > {
68
77
// The function was not decorated, so we shouldn't attempt authentication
69
78
if (! this .metadata ) {
70
79
return undefined ;
@@ -78,10 +87,14 @@ export class MyAuthStrategyProvider implements Provider<Strategy | undefined> {
78
87
}
79
88
}
80
89
81
- verify(username : string , password : string , cb : Function ) {
90
+ verify(
91
+ username : string ,
92
+ password : string ,
93
+ cb : (err : Error | null , user ? : UserProfile | false ) => void ,
94
+ ) {
82
95
// find user by name & password
83
96
// call cb(null, false) when user not found
84
- // call cb(null, userProfile ) when user is authenticated
97
+ // call cb(null, user ) when user is authenticated
85
98
}
86
99
}
87
100
```
@@ -90,27 +103,20 @@ In order to perform authentication, we need to implement a custom Sequence
90
103
invoking the authentication at the right time during the request handling.
91
104
92
105
``` ts
93
- // sequence.ts
94
- import {
95
- inject ,
96
- } from ' @loopback/core' ;
97
-
106
+ // src/sequence.ts
98
107
import {
108
+ RestBindings ,
109
+ SequenceHandler ,
99
110
FindRoute ,
100
- InvokeMethod ,
101
- ParsedRequest ,
102
111
ParseParams ,
103
- Reject ,
112
+ InvokeMethod ,
104
113
Send ,
105
- ServerResponse ,
106
- SequenceHandler ,
107
- RestBindings ,
114
+ Reject ,
115
+ ParsedRequest ,
108
116
} from ' @loopback/rest' ;
109
-
110
- import {
111
- AuthenticateFn ,
112
- AuthenticationBindings ,
113
- } from ' @loopback/authentication' ;
117
+ import {inject } from ' @loopback/context' ;
118
+ import {AuthenticationBindings , AuthenticateFn } from ' @loopback/authentication' ;
119
+ import {ServerResponse } from ' http' ;
114
120
115
121
const SequenceActions = RestBindings .SequenceActions ;
116
122
@@ -145,45 +151,55 @@ export class MySequence implements SequenceHandler {
145
151
Finally, put it all together in your application class:
146
152
147
153
``` ts
154
+ // src/application.ts
155
+ import {BootMixin , Binding , Booter } from ' @loopback/boot' ;
156
+ import {RestApplication , RestServer } from ' @loopback/rest' ;
148
157
import {
149
158
AuthenticationComponent ,
150
159
AuthenticationBindings ,
151
160
} from ' @loopback/authentication' ;
152
- import {RestApplication , RestServer } from ' @loopback/rest' ;
153
- import {MyAuthStrategyProvider } from ' ./providers/auth-strategy' ;
154
- import {MyController } from ' ./controllers/my-controller' ;
161
+ import {MyAuthStrategyProvider } from ' ./providers/auth-strategy.provider' ;
155
162
import {MySequence } from ' ./sequence' ;
163
+ import {ApplicationConfig } from ' @loopback/core' ;
164
+
165
+ export class MyApp extends BootMixin (RestApplication ) {
166
+ constructor (options ? : ApplicationConfig ) {
167
+ super (options );
156
168
157
- class MyApp extends RestApplication {
158
- constructor () {
159
- super ();
169
+ this .projectRoot = __dirname ;
160
170
161
171
this .component (AuthenticationComponent );
162
- this
163
- . bind ( AuthenticationBindings . STRATEGY )
164
- . toProvider ( MyAuthStrategyProvider );
172
+ this . bind ( AuthenticationBindings . STRATEGY ). toProvider (
173
+ MyAuthStrategyProvider ,
174
+ );
165
175
166
176
this .sequence (MySequence );
167
-
168
- this .controller (MyController );
169
177
}
170
178
171
179
async start() {
172
180
await super .start ();
173
181
174
182
const server = await this .getServer (RestServer );
175
- console .log (` REST server running on port: ${server .getSync (' rest.port' )} ` );
183
+ const port = await server .get (' rest.port' );
184
+ console .log (` REST server running on port: ${port } ` );
176
185
}
177
186
}
178
187
```
179
188
180
189
You can try your authentication component by using your favourite REST client
181
190
and by setting the ` authorization ` header. Here is an example of what your
182
191
request might look like using curl:
192
+
193
+ ``` shell
194
+ curl -u username:password http://localhost:3000/whoami
183
195
```
196
+
197
+ or if you'd like to manually set the headers:
198
+
199
+ ``` shell
184
200
curl -X GET \
185
- http:// localhost:3000/whoami \
186
- -H 'authorization : Basic Zm9vOmJhcg= ='
201
+ http:/localhost:3000/whoami \
202
+ -H ' Authorization : Basic dXNlcm5hbWU6cGFzc3dvcmQ ='
187
203
```
188
204
189
205
## Related resources
@@ -192,7 +208,7 @@ For more info about passport, see [passport.js](http://passportjs.org/).
192
208
193
209
## Contributions
194
210
195
- - [ Guidelines] ( https://github.com/strongloop/loopback-next/wiki/Contributing#guidelines )
211
+ - [ Guidelines] ( https://github.com/strongloop/loopback-next/blob/master/docs/site/DEVELOPING.md )
196
212
- [ Join the team] ( https://github.com/strongloop/loopback-next/issues/110 )
197
213
198
214
## Tests
0 commit comments