From 6b8e236ee4fac8e6eb5ad70ce2cde0fd36bac6a1 Mon Sep 17 00:00:00 2001 From: jannyHou Date: Tue, 26 Mar 2019 16:48:22 -0400 Subject: [PATCH] fixup!: address feedback --- .../docs/authentication-strategy.md | 11 ++++++---- .../docs/controller-functions.md | 16 ++++++++++----- .../docs/strategies/basic-auth.md | 17 +++++++++------- .../authentication/docs/strategies/jwt.md | 20 +++++++++++-------- 4 files changed, 40 insertions(+), 24 deletions(-) diff --git a/packages/authentication/docs/authentication-strategy.md b/packages/authentication/docs/authentication-strategy.md index 23ca55a1ee55..11a11397b413 100644 --- a/packages/authentication/docs/authentication-strategy.md +++ b/packages/authentication/docs/authentication-strategy.md @@ -4,10 +4,13 @@ import {Request} from '@loopback/rest'; interface AuthenticationStrategy { - // The resolver will read the options object from metadata, call `strategy.setOptions` - options: object; - authenticate(request: Request): Promise; - setOptions(options: object); + // The resolver will read the `options` object from metadata, then invoke the + // `authenticate` with `options` if it exists. + authenticate( + request: Request, + options: object, + ): Promise; + // This is a private function that extracts credential fields from a request, // it is called in function `authenticate`. You could organize the extraction // logic in this function or write them in `authenticate` directly without defining diff --git a/packages/authentication/docs/controller-functions.md b/packages/authentication/docs/controller-functions.md index d65021ea925a..6d42d816ea04 100644 --- a/packages/authentication/docs/controller-functions.md +++ b/packages/authentication/docs/controller-functions.md @@ -5,7 +5,7 @@ the beginning of markdown file [authentication-system](./authentication-system.md). Please note how they are decorated with `@authenticate()`, the syntax is: -`@authenticate(, {action: , session: })` +`@authenticate(strategy_name, options)` - /login @@ -48,10 +48,16 @@ class LoginController{ @inject(AuthenticationBindings.SERVICES.JWT_TOKEN) JWTtokenService: TokenService, ) {} + // I was about to create a local login example, while if the credentials are + // provided in the request body, all the authenticate logic will happen in the + // controller, the auth action isn't even involved. + // See the login endpoint in shopping example + // https://github.com/strongloop/loopback4-example-shopping/blob/master/src/controllers/user.controller.ts#L137 + // Describe the response using OpenAPI spec - @post('/loginOAI/local', RESPONSE_SPEC_FOR_JWT_LOGIN) + @post('/loginOAI/basicAuth', RESPONSE_SPEC_FOR_JWT_LOGIN) @authenticate('basicAuth') - localLoginReturningJWTToken() { + basicAuthLoginReturningJWTToken() { await token = JWTtokenService.generateToken(this.userProfile); // Action `send` will serialize token into response according to the OpenAPI spec. return token; @@ -60,9 +66,9 @@ class LoginController{ // OR // Serialize the token into response in the controller directly without describing it // with OpenAPI spec - @post('/loginWithoutOAI/local') + @post('/loginWithoutOAI/basicAuth') @authenticate('basicAuth') - localLoginReturningJWTToken() { + basicAuthLoginReturningJWTToken() { await token = JWTtokenService.generateToken(this.userProfile); // It's on users to serialize the token into the response. await writeTokenToResponse(); diff --git a/packages/authentication/docs/strategies/basic-auth.md b/packages/authentication/docs/strategies/basic-auth.md index 1a3a6610376f..19af3cd7f984 100644 --- a/packages/authentication/docs/strategies/basic-auth.md +++ b/packages/authentication/docs/strategies/basic-auth.md @@ -4,14 +4,21 @@ You could find the `AuthenticationStrategy` interface in file ```ts import {Request} from '@loopback/rest'; +interface BasicAuthOptions = { + // Define it as anyobject in the pseudo code + [property: string]: any; +}; + class BasicAuthenticationStrategy implements AuthenticationStrategy { options: object; constructor( - @inject(AUTHENTICATION_BINDINGS.SERVICES.USER) userService: UserService, - @inject(AUTHENTICATION_BINDINGS.BASIC.OPTIONS) options?: object, + @inject(AUTHENTICATION_BINDINGS.USER_SERVICE) userService: UserService, + @inject(AUTHENTICATION_BINDINGS.BASIC_AUTH_OPTIONS) options?: BasicAuthOptions, ) {} - authenticate(request: Request): Promise { + authenticate(request: Request, options: BasicAuthOptions): Promise { + // override the global set options with the one passed from the caller + options = options || this.options; // extract the username and password from request const credentials = await this.extractCredentials(request); // `verifyCredentials` throws error accordingly: user doesn't exist OR invalid credentials @@ -19,10 +26,6 @@ class BasicAuthenticationStrategy implements AuthenticationStrategy { return await userService.convertToUserProfile(user); } - setOptions(newOptions: object) { - Object.assign(options, newOptions); - } - extractCredentials(request): Promise { // code to extract username and password from request header } diff --git a/packages/authentication/docs/strategies/jwt.md b/packages/authentication/docs/strategies/jwt.md index 8d43d0b3df14..67278a7f6a14 100644 --- a/packages/authentication/docs/strategies/jwt.md +++ b/packages/authentication/docs/strategies/jwt.md @@ -4,14 +4,22 @@ You could find the `AuthenticationStrategy` interface in file ```ts import {Request} from '@loopback/rest'; +interface JWTAuthOptions = { + // Define it as anyobject in the pseudo code + [property: string]: any; +}; class JWTAuthenticationStrategy implements AuthenticationStrategy { - options: object; constructor( - @inject(AUTHENTICATION_BINDINGS.SERVICES.USER) tokenService: TokenService, - @inject(AUTHENTICATION_BINDINGS.BASIC.OPTIONS) options?: object, + @inject(AUTHENTICATION_BINDINGS.USER_SERVICE) tokenService: TokenService, + @inject(AUTHENTICATION_BINDINGS.JWT_AUTH_OPTIONS) options?: JWTAuthOptions, ) {} - authenticate(request: Request): Promise { + authenticate( + request: Request, + options: JWTAuthOptions, + ): Promise { + // override the global set options with the one passed from the caller + options = options || this.options; // extract the username and password from request const token = await this.extractCredentials(request); // `verifyToken` should decode the payload from the token and convert the token payload to @@ -19,10 +27,6 @@ class JWTAuthenticationStrategy implements AuthenticationStrategy { return await tokenService.verifyToken(token); } - setOptions(newOptions: object) { - Object.assign(options, newOptions); - } - extractCredentials(request): Promise { // code to extract json web token from request header/cookie/query }