简体   繁体   中英

User loading after authentication with ember simple auth

I use ember simple auth to authenticate my users. It workls perfectly fine except when the user just logged in.

I have an helper that ask for the current user:

import Helper from '@ember/component/helper';
import { inject as service } from '@ember/service';

export default Helper.extend({
  currentUser: service('current-user'),
  compute([feature,currentUser]) {
    let role = currentUser.get('user.role')

Helper is used in a template embedded in a template in application.hbs

{{#if (permission-for "users" currentUser)}}
  <li>{{#link-to 'users'}}<i class="fa fa-user"></i> <span>Clients</span>{{/link-to}}</li>
  {{/if}}

The current user service is a duplicate of this one from the doc: https://github.com/simplabs/ember-simple-auth/blob/master/guides/managing-current-user.md#loading-the-user-with-its-id

And my application.js is also using the code from the same guide.

From what I tried, the sessionAuthenticated start to run, and during await this._loadCurrentUser(); the helper is executed, and it finish to run sessionAuthenticated

What happen is that the user attribute I want is undefined and it make it impossible to display interface elements according to the role of the User.

How can I fix this problem?

Edit for related question:How does ember simple auth is supposed to be used in template to determine if User is supposed to see some part of the interface or not? Like for example menu choices.

First I would recommend to not pass the currentUser service to the helper if you inject it to the service.

Next you can let the helper recompute after the user was loaded:

export default Helper.extend({
  currentUser: service('current-user'),
  init() {
    if(!this.currentUser.user) {
      this.currentUser.runAfterLoaded.push(() => this.recompute());
    }
  },
  compute([feature]) {
    if(!this.currentUser.user)
      return false;
    }
    let role = this.currentUser.get('user.role')
    ...
    return ..;
  }
});

you'll also want to add this.runAfterLoaded.forEach(x => x()) to the load() function in the current-user service after the this.set('user', user); as well as this.set('runAfterLoaded', []) to the init hook.


Another possibility is to build a mixin that you add to the relevant routes after the AuthenticatedRouteMixin that ensures the current user will be loaded.

The problem with your approach is the helper is being executed synchronously and isn't "watching" the currentUser service in a way that would recompute. It would be a lot easier to use a computed property to do what you want:

controllers/application.js

  currentUser: service(),

  hasPermissionForUsers: computed("currentUser.user", function() {
    const user = this.get("currentUser.user");

    if (! user) return false;

    return user.get("role") === "users"; // taking a random guess at what your helper does here
  })

This property will now re-compute once the user is loaded:

application.hbs

  {{#if hasPermissionForUsers}}
    <li>{{#link-to 'users'}}<i class="fa fa-user"></i> <span>Clients</span>{{/link-to}}</li>
  {{/if}}

If you have to use a helper, it is doable but it's not pretty. The reason it's not as elegant is because helpers don't have access to the same context so it's more difficult to recompute. You could do something like this:

import Helper from '@ember/component/helper';
import { inject as service } from '@ember/service';
import { run } from '@ember/runloop';
import { addObserver, removeObserver } from '@ember/object/observers';

export default Helper.extend({

  currentUser: service(),

  willDestroy() {
    this._super(...arguments);
    const container = this.get('_container');
    removeObserver(container, 'currentUser.user', this, this.update);
  },

  compute([feature, container]) {
    addObserver(container, 'currentUser.user', this, this.update);
    this.set('_container', container); // used for cleanup

    const user = this.get('currentUser.user');

    if (! user) return false;

    return user.get('role') === feature;
  },

  update() {
    run.once(this, this.recompute);
  }
});

Then use it like so:

application.hbs

{{#if (permission-for "users" this)}}
  <li>{{#link-to 'users'}}<i class="fa fa-user"></i> <span>Clients</span>{{/link-to}}</li>
{{/if}}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM