Skip to content

Commit 86cc2c1

Browse files
committed
fixup!: custom user model
1 parent ba54e64 commit 86cc2c1

File tree

4 files changed

+119
-7
lines changed

4 files changed

+119
-7
lines changed

extensions/authentication-jwt/README.md

Lines changed: 114 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -178,6 +178,120 @@ The code snippet for whoAmI function:
178178
The complete file is in
179179
[user.controller.ts](https://github.com/strongloop/loopback-next/tree/master/extensions/authentication-jwt/src/__tests__/fixtures/controllers/user.controller.ts)
180180

181+
## Customize Model
182+
183+
1. Create your own user model and repository by `lb4 model` and
184+
`lb4 repository`.
185+
186+
2. The user service requires the user model, to provide your own one, you need
187+
to copy the
188+
[`user.service.ts`](https://github.com/strongloop/loopback-next/blob/master/extensions/authentication-jwt/src/services/user.service.ts)
189+
file into your application, e.g. copy to file
190+
`myapp/src/services/custom.user.service.ts`, and replace the default `User`,
191+
`UserRepository` with `MyUser`, `MyUserRepository`:
192+
193+
<details>
194+
<summary><strong>Check The Code</strong></summary>
195+
<p>
196+
197+
```ts
198+
import {UserService} from '@loopback/authentication';
199+
import {repository} from '@loopback/repository';
200+
import {HttpErrors} from '@loopback/rest';
201+
import {securityId, UserProfile} from '@loopback/security';
202+
import {compare} from 'bcryptjs';
203+
// User --> MyUser
204+
import {MyUser} from '../models';
205+
// UserRepository --> MyUserRepository
206+
import {MyUserRepository} from '../repositories';
207+
208+
export type Credentials = {
209+
email: string;
210+
password: string;
211+
};
212+
213+
// User --> MyUser
214+
export class CustomUserService implements UserService<MyUser, Credentials> {
215+
constructor(
216+
// UserRepository --> MyUserRepository
217+
@repository(MyUserRepository) public userRepository: MyUserRepository,
218+
) {}
219+
220+
// User --> MyUser
221+
async verifyCredentials(credentials: Credentials): Promise<MyUser> {
222+
const invalidCredentialsError = 'Invalid email or password.';
223+
224+
const foundUser = await this.userRepository.findOne({
225+
where: {email: credentials.email},
226+
});
227+
if (!foundUser) {
228+
throw new HttpErrors.Unauthorized(invalidCredentialsError);
229+
}
230+
231+
const credentialsFound = await this.userRepository.findCredentials(
232+
foundUser.id,
233+
);
234+
if (!credentialsFound) {
235+
throw new HttpErrors.Unauthorized(invalidCredentialsError);
236+
}
237+
238+
const passwordMatched = await compare(
239+
credentials.password,
240+
credentialsFound.password,
241+
);
242+
243+
if (!passwordMatched) {
244+
throw new HttpErrors.Unauthorized(invalidCredentialsError);
245+
}
246+
247+
return foundUser;
248+
}
249+
250+
// User --> MyUser
251+
convertToUserProfile(user: MyUser): UserProfile {
252+
return {
253+
[securityId]: user.id.toString(),
254+
name: user.username,
255+
id: user.id,
256+
email: user.email,
257+
};
258+
}
259+
}
260+
```
261+
262+
</p>
263+
</details>
264+
265+
3. Bind `MyUserRepository` (and `MyUserCredentialsRepository` if you create your
266+
own as well) to the corresponding key in your `application.ts`:
267+
268+
```ts
269+
import {CustomUserService} from './services/custom-user-service';
270+
import {MyUserRepository, MyUserCredentialsRepository} from './repositories';
271+
import {UserServiceBindings} from '@loopback/extension-authentication-jwt';
272+
273+
export class TestApplication extends BootMixin(
274+
ServiceMixin(RepositoryMixin(RestApplication)),
275+
) {
276+
constructor(options: ApplicationConfig = {}) {
277+
super(options);
278+
// ...other setup
279+
this.component(JWTAuthenticationComponent);
280+
// Bind datasource
281+
this.dataSource(DbDataSource, UserServiceBindings.DATASOURCE_NAME);
282+
// Bind user service
283+
this.bind(UserServiceBindings.USER_SERVICE).toClass(CustomUserService),
284+
// Bind user and credentials repository
285+
this.bind(UserServiceBindings.USER_REPOSITORY).toClass(
286+
UserRepository,
287+
),
288+
this.bind(UserServiceBindings.USER_CREDENTIALS_REPOSITORY).toClass(
289+
UserCredentialsRepository,
290+
),
291+
}
292+
}
293+
```
294+
181295
## Future Work
182296

183297
The security specification is currently manually added in the application file.

extensions/authentication-jwt/src/__tests__/acceptance/jwt.component.test.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ describe('jwt authentication', () => {
5555
});
5656

5757
await app.boot();
58-
userRepo = await app.get(UserServiceBindings.USER_REPOSITORY_NAME);
58+
userRepo = await app.get(UserServiceBindings.USER_REPOSITORY);
5959
await createUsers();
6060
await app.start();
6161
}

extensions/authentication-jwt/src/jwt-authentication-component.ts

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -34,10 +34,8 @@ export class JWTAuthenticationComponent implements Component {
3434

3535
// user bindings
3636
Binding.bind(UserServiceBindings.USER_SERVICE).toClass(MyUserService),
37-
Binding.bind(UserServiceBindings.USER_REPOSITORY_NAME).toClass(
38-
UserRepository,
39-
),
40-
Binding.bind(UserServiceBindings.USER_CREDENTIALS_REPOSITORY_NAME).toClass(
37+
Binding.bind(UserServiceBindings.USER_REPOSITORY).toClass(UserRepository),
38+
Binding.bind(UserServiceBindings.USER_CREDENTIALS_REPOSITORY).toClass(
4139
UserCredentialsRepository,
4240
),
4341
];

extensions/authentication-jwt/src/keys.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ export namespace UserServiceBindings {
3030
'services.user.service',
3131
);
3232
export const DATASOURCE_NAME = 'jwtdb';
33-
export const USER_REPOSITORY_NAME = 'repositories.UserRepository';
34-
export const USER_CREDENTIALS_REPOSITORY_NAME =
33+
export const USER_REPOSITORY = 'repositories.UserRepository';
34+
export const USER_CREDENTIALS_REPOSITORY =
3535
'repositories.UserCredentialsRepository';
3636
}

0 commit comments

Comments
 (0)