Скрытие маршрутов в баре Aurelia nav до аутентификации

Есть ли способ скрывать элементы в приложении Aurelia для начала аутентификации.

Сейчас я просто добавляю класс к каждому элементу на основе настраиваемого свойства. Это чувствует себя чрезвычайно взломанным.

    <li repeat.for="row of router.navigation" class="${row.isActive ? 'active' : ''}${!row.isVisible ? 'navbar-hidden' : ''}">
      <a href.bind="row.href">${row.title}</a>
    </li>

Ответы

Ответ 1

Здесь вы можете выбрать два направления.

Во-первых, показывать только навигационные ссылки на панели навигации, когда пользовательское свойство установлено так, как вы. Чтобы немного почистить его, можно использовать привязку show -

  <li repeat.for="row of router.navigation" show.bind="isVisible" class="${row.isActive ? 'active' : ''}">
    <a href.bind="row.href">${row.title}</a>
  </li>

Проблема здесь в том, что вам по-прежнему необходимо сохранить настраиваемое свойство, как вы уже делали. Альтернативой является reset маршрутизатор. Это в основном связано с построением набора маршрутов, которые доступны, когда пользователь не аутентифицирован, а затем отдельный набор после аутентификации пользователя -

this.router.configure(unauthenticatedRoutes);
// user authenticates
this.router.reset();
this.router.configure(authenticatedRoutes);

Это дает вам гибкость в перенастройке маршрутизатора, когда вам нужно.

Ответ 2

Эти ответы велики, хотя для целей аутентификации я не думаю, что у вас есть необходимые свойства безопасности. Например, если у вас есть маршрут /#/topsecret, скрывая его, он будет отключен из панели навигации, но не не позволит пользователю ввести его в URL-адрес.

Хотя это технически не соответствует теме, я думаю, что гораздо лучше использовать несколько оболочек, подробно описанных в этом ответе: Как визуализировать различные структуры представлений в Aurelia?

Основная идея - отправить пользователя в приложение для входа в приложение, а затем отправить его в основное приложение при входе в систему.

main.js

export function configure(aurelia) {
  aurelia.use
    .standardConfiguration()
    .developmentLogging();

  // notice that we are setting root to 'login'
  aurelia.start().then(app => app.setRoot('login'));
}

app.js

import { inject, Aurelia } from 'aurelia-framework';

@inject(Aurelia)
export class Login {
  constructor(aurelia) {
    this.aurelia = aurelia;
  }
  goToApp() {
    this.aurelia.setRoot('app');
  }
}

Я также написал подробный блог с примерами о том, как это сделать: http://davismj.me/blog/aurelia-login-best-practices-pt-1/

Ответ 3

Хотя мне нравится решение PW Kad (это просто кажется более чистым), вот подход, который я использовал с помощью пользовательского valueConvertor:

нав-bar.html

<ul class="nav navbar-nav">
    <li repeat.for="row of router.navigation | authFilter: isLoggedIn" class="${row.isActive ? 'active' : ''}" >

      <a data-toggle="collapse" data-target="#bs-example-navbar-collapse-1.in" href.bind="row.href">${row.title}</a>
    </li>
  </ul>

нав-bar.js

import { bindable, inject, computedFrom} from 'aurelia-framework';
import {UserInfo} from './models/userInfo';

@inject(UserInfo)
export class NavBar {
@bindable router = null;

constructor(userInfo){
    this.userInfo = userInfo;
}

get isLoggedIn(){
    //userInfo is an object that is updated on authentication
    return this.userInfo.isLoggedIn;
}

}

authFilter.js

export class AuthFilterValueConverter {
toView(routes, isLoggedIn){
    console.log(isLoggedIn);
    if(isLoggedIn)
        return routes;

    return routes.filter(r => !r.config.auth);
}
}

Обратите внимание на следующее:

  • Ваш isLoggedIn getter будет постоянно опробован
  • Вы можете добиться того же с привязкой if.bind = "! row.config.auth || $parent.isLoggedIn", но убедитесь, что ваше привязку if.bind появилось после вашего repeat.for

Ответ 4

Я понимаю, что это немного некромантии нити, но я хотел добавить ответ, потому что принятый ответ предлагает решение, явно рекомендованное против Aurelia docs (вам нужно прокрутить страницу до reset().

Я попробовал несколько других методов, в разной степени успеха, прежде чем понял, что искал это неправильно. Ограничение маршрутов вызывает озабоченность приложения, поэтому использование подхода AuthorizeStep - это, безусловно, способ блокировать переход кого-то из выбранного маршрута. Фильтрация маршрутов, которые пользователь видит на навигационной панели, на мой взгляд, является проблемой viewmodel. Я действительно не чувствовал, что это был конвертер значений, например, @MickJuice, поскольку каждый пример, который я видел, касался форматирования, а не фильтрации, а также я чувствовал себя немного чище/интуитивно понятным, чтобы поместить его в nav-bar просмотр модель. Мой подход был следующим:

// app.js
import AuthenticationService from './services/authentication';
import { inject } from 'aurelia-framework';
import { Redirect } from 'aurelia-router';

@inject(AuthenticationService)
export class App {
  constructor(auth) {
    this.auth = auth;
  }

  configureRouter(config, router) {
    config.title = 'RPSLS';
    const step = new AuthenticatedStep(this.auth);
    config.addAuthorizeStep(step);
    config.map([
      { route: ['', 'welcome'], name: 'welcome', moduleId: './welcome', nav: true, title: 'Welcome' },
      { route: 'teams', name: 'teams', moduleId: './my-teams', nav: true, title: 'Teams', settings: { auth: true } },
      { route: 'login', name: 'login', moduleId: './login', nav: false, title: 'Login' },
    ]);

    this.router = router;
  }
}

class AuthenticatedStep {
  constructor(auth) {
    this.auth = auth;
  }

  run(navigationInstruction, next) {
    if (navigationInstruction.getAllInstructions().some(i => i.config.settings.auth)) {
      if (!this.auth.currentUser) {
        return next.cancel(new Redirect('login'));
      }
    }

    return next();
  }
}

ОК, так что сам по себе ограничит доступ пользователей к маршрутам, если пользователь не войдет в систему. Я мог бы легко расширить это на что-то основанное на ролях, но на данный момент мне не нужно. Затем nav-bar.html находится прямо из скелета, но вместо привязки маршрутизатора непосредственно в nav-bar.html я создал nav-bar.js для использования полной модели представления, например:

import { inject, bindable } from 'aurelia-framework';
import AuthenticationService from './services/authentication';

@inject(AuthenticationService)
export class NavBar {
  @bindable router = null;

  constructor(auth) {
    this.auth = auth;
  }

  get routes() {
    if (this.auth.currentUser) {
      return this.router.navigation;
    }
    return this.router.navigation.filter(r => !r.settings.auth);
  }
}

Вместо того, чтобы перебирать router.navigation в этот момент, nav-bar.html будет перебирать свойство routes, указанное выше:

<ul class="nav navbar-nav">
   <li repeat.for="row of routes" class="${row.isActive ? 'active' : ''}">
     <a data-toggle="collapse" data-target="#skeleton-navigation-navbar-collapse.in" href.bind="row.href">${row.title}</a>
   </li>
</ul>

Опять же, ваш пробег может отличаться, но я хотел опубликовать его, поскольку я думал, что это довольно чистое и безболезненное решение общего требования.