Страница входа в СПА в Полимере
Я довольно новичок в Polymer и использовал шаблон Polymer 2.0 Starter Kit для всех своих приложений. Большинство моих приложений очень похожи - страница входа, которая перенаправляет вас на разные порталы в зависимости от роли пользователя (обычно администратора или пользователя). Порталы имеют app-drawer
с настройкой разных видов через iron-pages
,
Мой текущий поток дублирует my-app
шаблон в каждом "портале". Я просто не уверен, что это правильный способ сделать это. Я объясню дальше.
С помощью my-app
как из стартового комплекта с железными страницами для загрузки login-view
, admin-portal
и пользовательский портал, по умолчанию login-view
,
После входа пользователя приложение загрузится admin-portal
или же user-portal
в зависимости от того, какой пользователь вошел в систему.
И то и другое admin-portal
а также user-portal
имеют структуру, очень похожую на my-app, с app-drawer
а потом iron-pages
загрузка представлений, специфичных для возможностей администратора или пользовательских возможностей. В основном мне было интересно, если это лучшая практика - у вас всегда есть вложенный iron-pages
, Есть ли там, чтобы отвлечь login-view
?
Код:
my-app - готовый шаблон
<app-location
route="{{route}}"
url-space-regex="^[[rootPath]]">
</app-location>
<app-route
route="{{route}}"
pattern="[[rootPath]]:page"
data="{{routeData}}"
tail="{{subroute}}">
</app-route>
<iron-pages
selected="[[page]]"
attr-for-selected="name"
fallback-selection="view404"
role="main">
<login-view name="login" current-user="{{currentUser}}"></login-view>
<superuser-portal name="superuser"></superuser-portal>
<admin-portal name="admin" current-user="{{currentUser}}"></admin-portal>
<doctor-portal name="doctor" current-user="{{currentUser}}"></doctor-portal>
<my-view404 name="view404"></my-view404>
</iron-pages>
_routePageChanged(page) {
//console.log(this.user.email);
// If no page was found in the route data, page will be an empty string.
// Default to 'view1' in that case.
this.page = page || 'login';
}
_pageChanged(page) {
console.log('_pageChanged: ' + page);
let resolvedPageUrl = this.resolveUrl('my-' + page + '.html');
if(page === 'login') {
resolvedPageUrl = this.resolveUrl('login-view.html');
} else if(page === 'superuser') {
resolvedPageUrl = this.resolveUrl('superuser-portal.html');
} else if(page === 'admin') {
resolvedPageUrl = this.resolveUrl('admin-portal.html');
} else if(page === 'doctor') {
resolvedPageUrl = this.resolveUrl('doctor-portal.html');
}
console.log('resolvedPageUrl: ' + resolvedPageUrl);
Polymer.importHref(
resolvedPageUrl,
null,
this._showPage404.bind(this),
true);
}
admin-portal - опять же, в основном так же, как готовый шаблон
<app-route route="{{route}}" pattern="/admin/:page" data="{{routeData}}" tail="{{subroute}}">
</app-route>
<!-- <firebase-auth id="auth" user="{{user}}" on-error="handleError"></firebase-auth> -->
<app-drawer-layout fullbleed narrow="{{narrow}}">
<app-drawer id="drawer" slot="drawer" swipe-open="[[narrow]]">
<div class="drawerHeader">
<div class="drawerTitle">GetonHealth</div>
<div class="drawerSubtitle">[[displayName]]</div>
</div>
<div style="margin-top: 24px; color: white;">
<vaadin-list-box>
<iron-selector attr-for-selected="name" selected="{{routeData.page}}">
<vaadin-item name="calendar">
<iron-icon icon="vaadin:calendar"></iron-icon>
Calendar
</vaadin-item>
<vaadin-item name="doctors">
<iron-icon icon="vaadin:specialist"></iron-icon>
Manage Doctors
</vaadin-item>
<vaadin-item name="view3">
<iron-icon icon="vaadin:cog-o"></iron-icon>
Settings
</vaadin-item>
<vaadin-item name="view4">
<iron-icon icon="vaadin:info-circle-o"></iron-icon>
Help
</vaadin-item>
<vaadin-item name="logout">
<iron-icon icon="vaadin:exit-o"></iron-icon>
Sign Out
</vaadin-item>
</iron-selector>
</vaadin-list-box>
</div>
</app-drawer>
<app-header-layout>
<app-header>
<app-toolbar effects="waterfall">
<paper-icon-button icon="my-icons:menu" drawer-toggle=""></paper-icon-button>
<div class="main-title" main-title>[[pageTitle]]</div>
</app-toolbar>
</app-header>
<iron-pages selected="[[page]]" attr-for-selected="name" fallback-selection="view404" role="main">
<admin-dashboard name="dashboard"></admin-dashboard>
<admin-manage-doctors name="doctors"></admin-manage-doctors>
<manage-doctor-detail name="doctor" page-title="{{pageTitle}}"></manage-doctor-detail>
<admin-calendar-view name="calendar" narrow="[[narrow]]"></admin-calendar-view>
<admin-new-event name="newevent"></admin-new-event>
<admin-event-detail name="event" page-title="{{pageTitle}}"></admin-event-detail>
<admin-reschedule-view name="reschedule" page-title="{{pageTitle}}"></admin-reschedule-view>
<admin-new-appointment name="newappointment" current-user="{{currentUser}}"></admin-new-appointment>
<my-view404 name="view404"></my-view404>
</iron-pages>
</app-header-layout>
</app-drawer-layout>
</template>
<script>
class AdminPortal extends Polymer.Element {
static get is() { return 'admin-portal'; }
static get properties() {
return {
pageTitle: String,
displayName: String,
currentUser: {
type: Object,
value: {}
},
page: {
type: String,
reflectToAttribute: true,
observer: '_pageChanged',
},
routeData: Object,
subroute: Object,
};
}
static get observers() {
return [
'_routePageChanged(routeData.page)',
];
}
_routePageChanged(page) {
// If no page was found in the route data, page will be an empty string.
// Default to 'view1' in that case.
this.page = page || 'calendar';
}
_pageChanged(page) {
console.log('_pageChanged: ' + page);
let resolvedPageUrl = this.resolveUrl('my-' + page + '.html');
if (page === 'dashboard') {
this.set('pageTitle', 'Dashboard');
resolvedPageUrl = this.resolveUrl('admin/views/admin-dashboard.html');
} else if (page === 'doctors') {
this.set('pageTitle', 'Manage doctors');
resolvedPageUrl = this.resolveUrl('admin/views/admin-manage-doctors.html');
} else if (page === 'doctor') {
this.set('pageTitle', '');
resolvedPageUrl = this.resolveUrl('admin/views/manage-doctor-detail.html');
} else if (page === 'calendar') {
this.set('pageTitle', 'Calendar');
this.set('queryParams', {});
resolvedPageUrl = this.resolveUrl('admin/views/admin-calendar-view.html');
} else if (page === 'newevent') {
this.set('pageTitle', 'Create new event');
resolvedPageUrl = this.resolveUrl('admin/views/admin-new-event.html');
} else if (page === 'event') {
resolvedPageUrl = this.resolveUrl('admin/views/admin-event-detail-test.html');
} else if (page === 'newappointment') {
resolvedPageUrl = this.resolveUrl('admin/views/admin-new-appointment.html');
} else if (page === 'reschedule') {
resolvedPageUrl = this.resolveUrl('admin/views/admin-reschedule-view.html');
} else if (page === 'logout') {
this.logout();
return;
}
Polymer.importHref(
resolvedPageUrl,
null,
this._showPage404.bind(this),
true);
if (!this.$.drawer.persistent) {
this.$.drawer.close();
}
}
Войти ракурс
performLogin() {
this.$.auth.signInWithEmailAndPassword(this.username, this.password)
.then(response => {
this.username = '';
this.password = '';
this.getUserFromFirestore(response);
}).catch(error => {
console.error(error);
this.$.inputPassword.invalid = true;
this.$.inputPassword.errorMessage = error.message;
this.$.inputPassword.validate();
});
}
getUserFromFirestore(user) {
firestore.collection('users').doc(user.uid)
.get()
.then(doc => {
console.log(doc.data());
//this.set('currentUser', this.docToObject(doc));
this.changePage(user.uid, doc.data().role);
})
.catch(error => {
console.error(error);
});
}
changePage(uid, role) {
let page = '';
if (role === 'superuser') {
page = '/superuser/dashboard';
} else if (role === 'admin') {
page = '/admin/calendar';
} else if (role === 'doctor') {
page = '/doctor/clinics';
}
setTimeout(() => {
window.history.pushState({}, null, page);
window.dispatchEvent(new CustomEvent('location-changed'));
}, 1000);
}
1 ответ
Ничто не кажется особенно неправильным с этой реализацией, и это кажется простым. Логин, имеющий собственный вид, тоже подойдет. С ним связан отображаемый DOM ("Пожалуйста, войдите в систему", имя пользователя, поле пароля), поэтому нет ничего плохого в том, чтобы иметь его в качестве выбираемого представления со знанием аутентификации внутри него.
Просто убедитесь, что страница входа не является привратником значимых действий. То есть пользователь не может добавлять / удалять данные из магазина, просто меняя страницы в инспекторе. iron-pages
! == безопасность, только навигация.
Кроме того, это не против того, чтобы iron-pages
, iron-pages
по сути прославленный element.setAttribute('hidden', '')
а также element.removeAttribute('hidden')
, Тем не менее, общая ошибка с вложенными iron-pages
должен отслеживать состояние выхода при переходе в родительском iron-pages
, Например, логин переходит к администратору, затем в админ вы переходите, чтобы перепланировать, затем вы входите в систему как другой администратор, администраторский портал, вероятно, не должен автоматически перепланировать.