Skip to content

Commit

Permalink
fixup!: address feedback
Browse files Browse the repository at this point in the history
  • Loading branch information
jannyHou authored and emonddr committed Mar 27, 2019
1 parent 03a163f commit 6b8e236
Show file tree
Hide file tree
Showing 4 changed files with 40 additions and 24 deletions.
11 changes: 7 additions & 4 deletions packages/authentication/docs/authentication-strategy.md
Original file line number Diff line number Diff line change
Expand Up @@ -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<UserProfile | undefined>;
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<UserProfile | undefined>;

// 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
Expand Down
16 changes: 11 additions & 5 deletions packages/authentication/docs/controller-functions.md
Original file line number Diff line number Diff line change
Expand Up @@ -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(<strategy_name>, {action: <action_name>, session: <enabled_or_not>})`
`@authenticate(strategy_name, options)`

- /login

Expand Down Expand Up @@ -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;
Expand All @@ -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();
Expand Down
17 changes: 10 additions & 7 deletions packages/authentication/docs/strategies/basic-auth.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,25 +4,28 @@ 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<UserProfile | undefined> {
authenticate(request: Request, options: BasicAuthOptions): Promise<UserProfile | undefined> {
// 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
const user = await userService.verifyCredentials(credentials);
return await userService.convertToUserProfile(user);
}

setOptions(newOptions: object) {
Object.assign(options, newOptions);
}

extractCredentials(request): Promise<Credentials> {
// code to extract username and password from request header
}
Expand Down
20 changes: 12 additions & 8 deletions packages/authentication/docs/strategies/jwt.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,25 +4,29 @@ 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<UserProfile | undefined> {
authenticate(
request: Request,
options: JWTAuthOptions,
): Promise<UserProfile | undefined> {
// 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
// userProfile object.
return await tokenService.verifyToken(token);
}

setOptions(newOptions: object) {
Object.assign(options, newOptions);
}

extractCredentials(request): Promise<string> {
// code to extract json web token from request header/cookie/query
}
Expand Down

0 comments on commit 6b8e236

Please sign in to comment.