Loopback-next: Loopback 4 authorization allowing access to all type of users

Created on 26 May 2020  路  8Comments  路  Source: strongloop/loopback-next

I am following this article for implementing authorization in my app. The user with the admin role can perform certain operations that other users can't.

But it is not working. The controllers are accessible to all type of users

Here is the code

Thank you in advance

user model has a property called role


@property({
    type: 'string',
  })
  role?: string;

authorizer.ts

import {AuthorizationContext, AuthorizationDecision, AuthorizationMetadata, Authorizer} from '@loopback/authorization';
import {Provider} from '@loopback/core';

export class MyAuthorizationProvider implements Provider<Authorizer> {
  constructor() {}

  /**
   * @returns authenticateFn
   */
  value(): Authorizer {
    return this.authorize.bind(this);
  }

  async authorize(
    authorizationCtx: AuthorizationContext,
    metadata: AuthorizationMetadata,
  ) {
    const clientRole = authorizationCtx.principals[0].role;
    const allowedRoles = metadata.allowedRoles;
    return allowedRoles?.includes(clientRole)
      ? AuthorizationDecision.ALLOW
      : AuthorizationDecision.DENY;
  }
}

application.ts

//Other imports        
        import {MyAuthorizationProvider} from './services/try';
        import {AuthorizationComponent, AuthorizationDecision, AuthorizationOptions, AuthorizationTags} from '@loopback/authorization';

       constructor(options: ApplicationConfig = {}) {
       super(options);
      // other code
        let app = new Application()
    const data: AuthorizationOptions = {
      precedence: AuthorizationDecision.DENY,
      defaultDecision: AuthorizationDecision.DENY,
    };

    const binding = app.component(AuthorizationComponent);
    app.configure(binding.key).to(data);

    app
      .bind('authorizationProviders.my-authorizer-provider')
      .toProvider(MyAuthorizationProvider)
      .tag(AuthorizationTags.AUTHORIZER);
}

user.controller.ts


 @get('/users/count', {
    responses: {
      '200': {
        description: 'User model count',
        content: {'application/json': {schema: CountSchema}},
      },
    },
  })

  @authenticate('jwt')
  @authorize({allowedRoles: ['admin']})

  async count(
    @param.where(User) where?: Where<User>,
  ): Promise<Count> {
    return this.userRepository.count(where);
  }
question

Most helpful comment

@pratikjaiswal15 can you share a simple app reproducing the behavior?

All 8 comments

Anyone please?

@pratikjaiswal15 can you share a simple app reproducing the behavior?

Here it is https://github.com/pratikjaiswal15/loopbackauthrization.
Authorization is not working. Access is allowed to all user roles.

@pratikjaiswal15 I am not sure, but the README of https://www.npmjs.com/package/@loopback/authorization seems to be missing some info. @jannyHou can you confirm?

Using a component is not the only way to enable authorization. Take a look at the LoopBack 4 Example app, how it implements authentication and authorization. Maybe you will find its way easier to understand and use.

Controllers like the ProductController just have to import a function basicAuthorization from src/services/basic.authorizor.ts, and add it in the list of voters like this:

@authorize({allowedRoles: ['admin'], voters: [basicAuthorization]})

The implementation of basicAuthorization is just for the demo, you can modify it according to your requirements any way you like.

Thanks for your reply. Now, I have copied the code of basic-authorizer from the shopping example in my app. But the userProfile contains only two fields id and name. Other fields like role or email are undefined. So, I am getting 401 every time.
It means token doesn't contain role. But while issuing toke I had used many fields.

Can you please help?
Thank you in advance

authorizer.ts

export async function basicAuthorization(
  authorizationCtx: AuthorizationContext,
  metadata: AuthorizationMetadata,
): Promise<AuthorizationDecision> {
  // No access if authorization details are missing
  let currentUser: UserProfile;
  if (authorizationCtx.principals.length > 0) {
    const user = _.pick(authorizationCtx.principals[0]
      , [
        'id',
        'name',
        'role',
        'email',
        'address'
      ]);

    console.log(user) // contains only id and name
    currentUser = {[securityId]: user.id, name: user.name, roles: user.role, email: user.email, address: user.address};
    console.log(currentUser)
  }
}

I have added try.ts file for authorization in services in repository https://github.com/pratikjaiswal15/loopbackauthrization.

@hacksparrow how to add property role in AuthorizationContext.principals?

I think now this issue can be closed @pratikjaiswal15 as we already solve this issue
https://github.com/strongloop/loopback-next/issues/5603

Was this page helpful?
0 / 5 - 0 ratings