Скрытие маршрутов в баре 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>
Опять же, ваш пробег может отличаться, но я хотел опубликовать его, поскольку я думал, что это довольно чистое и безболезненное решение общего требования.