Login page before main (Aurelia) - javascript

I want when user coming check if he login before - if not -> redirect to login page -> if his email & password are okay -> redirect back to welcome page.
What problem I have -> service work properly with login class but welcome class totally ignore any changes in service.
Code
users.js
export class Users {
users = [
{ name: 'Lucian', email: 'lucian1992#zalando.de', password: 'lucian' },
{ name: 'Corki', email: 'corki2010#supplier.de', password: 'corki' },
{ name: 'Vayne', email: 'vaynii#zalando.de', password: 'vayne' }];
securedUser = {};
error = {};
usedOnce = 0;
check(checkUser) {
this.usedOnce = 1;
this.securedUser = this.users.filter((user) => user.email === checkUser.email
&& user.password === checkUser.password)[0];
if (typeof this.securedUser === 'undefined'){
this.error = { message: "No such kind of user or wrong password" };
}
}
}
login.js
import {inject} from 'aurelia-framework';
import {Users} from 'users-list';
import {Router} from 'aurelia-router';
#inject(Users, Router)
export class Login {
constructor(userData, router) {
this.router = router;
this.users = userData.users;
this.check = userData.check;
this.securedUser = userData.securedUser; // Changed after check function
this.userError = userData.error;
}
checkUser = {};
login() {
this.check(this.checkUser);
if (typeof this.userError === 'undefined') {
alert(this.error.message);
} else {
this.router.navigate("")
}
}
}
welcome.js
import {inject} from 'aurelia-framework';
import {Users} from 'users-list';
import {Redirect} from 'aurelia-router';
#inject(Users)
export class Overview {
constructor(userData) {
this.usedOnce = userData.usedOnce;
this.securedUser = userData.securedUser; // This object changed in login.js, but totally ignores in this class
}
heading = 'Welcome to the Article Manager Prototype!';
canActivate() {
if (this.securedUser) {
return new Redirect('/login')
}
}
}
So, tech issue that securedUser changed in login.js, but totally ignored in welcome.js. Is this because of canActivate method? Because I also use activate() - the same problem.
Will appreciate any help with understanding the issue.

There is a solution for your problem in the official documentation:
import {Redirect} from 'aurelia-router';
export class App {
configureRouter(config) {
config.title = 'Aurelia';
config.addPipelineStep('authorize', AuthorizeStep);
config.map([
{ route: ['welcome'], name: 'welcome', moduleId: 'welcome', nav: true, title:'Welcome' },
{ route: 'flickr', name: 'flickr', moduleId: 'flickr', nav: true, auth: true },
{ route: 'child-router', name: 'childRouter', moduleId: 'child-router', nav: true, title:'Child Router' },
{ route: '', redirect: 'welcome' }
]);
}
}
class AuthorizeStep {
run(navigationInstruction, next) {
if (navigationInstruction.getAllInstructions().some(i => i.config.auth)) {
var isLoggedIn = /* insert magic here */false;
if (!isLoggedIn) {
return next.cancel(new Redirect('login'));
}
}
return next();
}
}
Notice the addition of config.addPipelineStep('authorize', AuthorizeStep); compared to the regular router config logic.
Source: http://aurelia.io/docs.html#/aurelia/framework/1.0.0-beta.1.2.2/doc/article/cheat-sheet/7
(you need to scroll down a bit to section "Customizing the Navigation Pipeline")

I tried an own example with this and maybe i found your Problem.
You are checking if your securedUser is null. If it is NOT null you will reditect to login
canActivate() {
if (this.securedUser) { // change to !this.securedUser
return new Redirect('/login')
}
}
And you are setting your securedUser initial to an empty object:
securedUser = {};
Because of that your first redirect was working even your if condition was wrong.
Don´t set a initial value, set undefined or change your if condition and check on sercuredUser properties.

Your solution might work, but if you have 50 routes that must be authorised you would have to use canActivate hook 50 times! That is not an elegant solution for an authorising workflow.
This is a more elegant solution:
Instead of having a "route" to login, create an isolated root component and then update your main.js file:
//for example, imagine that your root component is located at src/app/app.js
//and your login component at src/login/login.js
//app.isLoggedIn() checks if the credentials/tokens are OK
aurelia.start().then(a => {
let rootComponent = '' app.isLoggedIn() ? 'app/app' : 'login/login';
a.setRoot(rootComponent, document.body);
});
Now, in your login/login.js root component you have to configure the router:
configureRouter(config, router) {
config.title = 'YourTitle';
config.map([
{ route: '', name: 'user-password', moduleId: './user-password', title: 'Sign In' }, //route for "username/password" screen
{ route: 'forgot-password', name: 'forgot-pwd', moduleId: './forgot-pwd', title: 'Forgot Password?' } //example of "forgot password" screen
]);
config.mapUnknownRoutes(instruction => {
//if an unknown route has been found,
//a route from the app component, 'users/add' for example
//redirect to sign-in component
return './user-password';
});
this.router = router;
}
Create appropriated methods to authenticate the user and then redirect it to the app/app component:
//import and inject { Aurelia } from 'aurelia-framework';
this.aurelia.setRoot('app/app');
Now, if an unauthorised user access 'users/add', it will be redirected to the login page. If the login succeeds, the 'users/add' page will be shown.
Hope this helps!

Related

Ionic 4 Deeplink plugin return false route not matched

I am Implementing Deeplink in ionic 4 application. Application in getting launched but deeplink plugin always returns false;
app.routing.ts:
{
path: 'viewdiary/:id/public',
loadChildren: () => import('./pages/viewdiary/viewdiary.module').then( m => m.ViewdiaryPageModule)
},
app.compoent.ts:
setupDeepLink(){
this.deeplinks.route({
'/viewdiary/:id/public': 'viewdiary/:id/public'
}).subscribe((match)=>{
console.log('deeplink matched', match);
const internalPath = `${match.$route}/${match.$args['id']}/${match.$route}`;
console.log(internalPath);
this.zone.run(()=>{
this.general.goToPage(internalPath);
});
},
nomatch=>{
// nomatch.$link - the full link data
console.error("Got a deeplink that didn't match", nomatch);
})
};
My Public diary Page link is 'https://www.example.com/diary/12542/public';
it looks like a routing issue tried many thing changes names but nothing works. I am clueless what going wrong.
Figured out how to achieve it with the help of Another Answer on Stackoverflow
import { Platform, NavController } from '#ionic/angular';
constructor(public navCtrl: NavController){}
this.deeplinks.routeWithNavController(this.nav, {
'/viewdiary/:diary/:id/:public': 'viewdiary'
}).subscribe((match) => {
console.log('success' + JSON.stringify(match));
}, (noMatch) => {
console.log('error' + JSON.stringify(noMatch));
});
For me, this approach did not work either. So, in my application I handle deep links as follows:
const {App}: { App: AppPlugin } = Plugins;
...
export class AppComponent {
private setupDeepLinks(): void {
App.addListener('appUrlOpen', (data: any) => {
this.ngZone.run(() => {
// Example url: https://my-domain.com/tabs/tab2
// slug = /tabs/tab2
const slug = data.url.split('my-domain.com').pop();
if (slug) {
this.router.navigateByUrl(slug);
}
});
});
}
}
Or you can implement your own more complex logic inside the listener if needed

VUE.js records undefined

I am creating an application where I have a list of users, when I click on a single user, it takes me to that specific users profile (Profile.vue). I am using ASP.NET Core API with Vue.js as my front end. My API is working so when I click on the user, I am able to see the data coming from my database using Chrome dev Tools and Postman. When I open Vue Dev Tools in Chrome, I see that the data is "undefined". For example, I am just trying to get the users firstName to display so I know that its working.
This is how I am routing my page from the list of users to a specific users profile
methods: {
editItem(lastName) {
this.$http.get(`http://localhost:61601/api/GetInquiry/${lastName}`)
this.$router.push({ path: `/Profile/${lastName}` })
},
async GetAllInquiries() {
this.loading = true
try {
this.records = await api.GetAllInquiries()
} finally {
this.loading = false
}
},
Once I am routed, Here is my Profile.Vue that will show the users information
<template>
<div>
<h2>Student Info</h2>
Student Name: {{ records.firstName }}
<br />
</div>
</template>
<script>
import api from '../store/api.js'
export default {
data() {
return {
records: {
firstName: this.firstName
},
}
},
async created() {
this.GetInquiriesByUser()
},
methods: {
async GetInquiriesByUser() {
this.loading = true
},
post: function () {
this.$http.get('http://localhost:61601/api/inquiry', {
firstName: this.firstName
})
}
}
}
</script>
API.js
import Vue from 'vue'
import axios from 'axios'
const client = axios.create({
baseURL: 'http://localhost:61601/api/',
json: true
})
export default {
async execute(method, resource, data) {
return client({
method,
url: resource,
data,
}).then(req => {
return req.data
})
},
GetAllInquiries() {
return this.execute('get', '/Inquiry')
},
GetInquiriesByUser() {
return this.execute('get', '/GetInquiry/')
},
create(data) {
return this.execute('post', '/', data)
},
update(id, data) {
return this.execute('put', `/${id}`, data)
},
delete(id) {
return this.execute('delete', `/${id}`)
}
}
GetInquiryByUser Controller
[Route("api/[controller]")]
public class GetInquiryController : BaseController
{
private GetInquiryByUser manager;
public GetInquiryController(IConfiguration config) : base(config)
{
manager = new GetInquiryByUser(config);
}
[HttpGet("{lastName}")] //api/GetInquiry/yourlastname
public IEnumerable<InquiryModel> Get([FromRoute]string lastName)
{
return manager.GetInquiriesByUser(lastName);
}
}
The Inquiry contoller gets the list of all users and my GetInquiryByUser is passing the lastName to get that specific users profile. (eventually I will pass a unique id, just testing for now)
I am using hash mode for vue routing as well. At first I was confused on what mode I was using and I had a combination of history and hash, but I think I am all hash mode now.
If someone can point me into the right directions, that would be awesome! Please let me know if I need to porvide more details.

Vue-router 2 changes route but does not update the view?

I have a login issue with website that uses:
Vue.js v2.0.3
vue-router v2.0.1
vuex v0.8.2
In routes.js I have a simple interceptor setup
router.beforeEach((to, from, next) => {
if (to.matched.some(record => record.meta.requiresAuth)) {
// this route requires auth, check if logged in
// if not, redirect to login page.
if (!router.app.auth.isUserLoggedIn) {
next({
path: '/login',
query: { redirect: to.fullPath }
})
} else {
next()
}
} else {
next() // make sure to always call next()!
}
})
And in login.vue,which handles the login page logic after using Google API only for login succeeds I call this:
this.login(userData).then(
() => this.$router.push(this.redirectToAfterLogin), // Login success
() => {} // Login failed
)
mounted: function(){
if (this.auth.isUserLoggedIn){
// Let's just redirect to the main page
this.$router.push(this.redirectToAfterLogins)
}else{
Vue.nextTick(() => {
this.loadGooglePlatform()
})}}
computed: {
redirectToAfterLogin: function() {
if (this.$route.query.redirect){
return this.$route.query.redirect
}else{
return '/'
}
}
}
router.js
var VueRouter = require('vue-router')
// Router setup
export const router = new VueRouter({
linkActiveClass: "is-active",
mode: 'history',
saveScrollPosition: true,
routes: [
{ path: '', name: 'root', redirect: '/home' },
{ path: '/login', name: 'login', meta: { loadingNotRequired: true }, component: require('./pages/login.vue') },
{ path: '/logout', name: 'logout', meta: { loadingNotRequired: true }, component: require('./pages/logout.vue') },
{ path: '/home', name: 'home', title: 'Home', redirect: '/home/random', component: require('./pages/home.vue'),
children: [
{ path: 'random', name: 'random', meta: { requiresAuth: true }, title: 'Random', component: require('./pages/random.vue') }
]
}
]
})
// Redirect to login page if not logged In
router.beforeEach((to, from, next) => {
if (to.matched.some(record => record.meta.requiresAuth)) {
// this route requires auth, check if logged in
// if not, redirect to login page.
if (!router.app.auth.isUserLoggedIn) {
next({
path: '/login',
query: { redirect: to.fullPath }
})
} else {
next()
}
} else {
next() // make sure to always call next()!
}
})
Now here this.login is just the call to vuex, to update the logged in user.
What happens is that after login, URL changes to /home, but the DOM does not update!
Only way that successfully changed the DOM was forcing location.reload() and that is not what I want to do, as it loses my dynamically loaded G scripts in Head.
Any idea on what to do to force the view to update DOM?
NOTE: it happens only on the first login of user, if he logs out and back-in, the redirecting is fine
Not a perfect solution may be, as it is going to recreate the component but it will work for every case when having same route & needs to update the component.
Just update the <router-view/> or <router-view></router-view> with
<router-view :key="$route.fullPath"></router-view>
Vue re-uses components where possible. You should use beforeRouteUpdate to react to a route switch that uses the same component.
I have the same problem "URL changes to /home, but the DOM does not update".
In my project, the tag "transition" maked the problem.
Hope it is helpful!
Maybe you should set the redirectToAfterLogin function into methods, like this it will be recalculated each times. The computed will be modified only if used v-model changed. To stick to the meaning of the function name, I would set the router push inside.
login.vue :
mounted: function(){
if (this.auth.isUserLoggedIn){
// Let's just redirect to the main page
// this.$router.push(this.redirectToAfterLogins)
this.redirectToAfterLogins()
}else{
Vue.nextTick(() => {
this.loadGooglePlatform()
})
}
},
// computed: {
methods: {
this.login(userData).then(
// () => this.$router.push(this.redirectToAfterLogin), // Login success
() => this.redirectToAfterLogin(), // Login success
() => {} // Login failed
),
redirectToAfterLogin: function() {
if (this.$route.query.redirect){
// return this.$route.query.redirect
this.$router.push(this.$route.query.redirect)
}else{
// return '/'
this.$router.push('/')
}
}
}
https://v2.vuejs.org/v2/guide/computed.html#Computed-Properties
https://v2.vuejs.org/v2/guide/computed.html#Computed-Caching-vs-Methods
"However, the difference is that computed properties are cached based on their dependencies. A computed property will only re-evaluate when some of its dependencies have changed. This means as long as message has not changed, multiple access to the reversedMessage computed property will immediately return the previously computed result without having to run the function again."
methods vs computed and filters :
Access vue instance/data inside filter method

what does the `run() {}` do in javascript/Aurelia?

I see in Aurelia site, one of the article uses run() {}. What does this method in general do? it is a lifecycle hook or it is a new Javascript 2016 method?
http://aurelia.io/hub.html#/doc/article/aurelia/framework/latest/cheat-sheet/7
import {Redirect} from 'aurelia-router';
export class App {
configureRouter(config) {
config.title = 'Aurelia';
config.addPipelineStep('authorize', AuthorizeStep);
config.map([
{ route: ['welcome'], name: 'welcome', moduleId: 'welcome', nav: true, title:'Welcome' },
{ route: 'flickr', name: 'flickr', moduleId: 'flickr', nav: true, auth: true },
{ route: 'child-router', name: 'childRouter', moduleId: 'child-router', nav: true, title:'Child Router' },
{ route: '', redirect: 'welcome' }
]);
}
}
class AuthorizeStep {
run(navigationInstruction, next) {
if (navigationInstruction.getAllInstructions().some(i => i.config.auth)) {
var isLoggedIn = /* insert magic here */false;
if (!isLoggedIn) {
return next.cancel(new Redirect('login'));
}
}
return next();
}
}
You can add multiple pipeline steps to your router config. Each of the pipelines must implement PipelineStep interface:
interface PipelineStep {
/**
* Execute the pipeline step. The step should invoke next(), next.complete(),
* next.cancel(), or next.reject() to allow the pipeline to continue.
*
* #param instruction The navigation instruction.
* #param next The next step in the pipeline.
*/
run(instruction: NavigationInstruction, next: Next): void;
}
(source code)
As you can see there must be run method. At some point later run methods from all the steps will be executed.
So the answer to your question: no, it's not something ES2015 introduces, but rather a convention pipeline steps must follow.

Root route is ignored when I add /admin route in FlowRouter

My home route works when it's by itself:
FlowRouter.route('/', {
name: 'home',
triggersEnter: [
function(context, redirect) {
var ExperimentsSub, handle, randomExperiment;
console.log('Home triggers');
ExperimentsSub = new SubsManager;
handle = ExperimentsSub.subscribe('randomExperiment');
if (handle.ready && Experiments.find.count) {
randomExperiment = Experiments.findOne;
return redirect('/experiment/' + randomExperiment._id);
}
}
],
action: function() {
console.log('Rendering home');
return BlazeLayout.render('layout', {
content: 'home'
});
}
});
But when I add in my /admin route, surfing to / routes through the admin route instead.
FlowRouter.route('/admin', {
name: 'admin',
triggersEnter: [console.log('Admin triggers'), !Roles.userIsInRole(this.userId, ['admin']) ? FlowRouter.go(FlowRouter.path('login')) : void 0],
action: function() {
console.log('Rendering admin');
return BlazeLayout.render('layout', {
content: 'admin'
});
}
});
I know this because of the console logging I'm doing. When I surf to / with both routes, the console output is Rendering admin. Why is it doing this, and how can I fix it?
The problem was in my admin route triggers. I was not assigning an array of functions. I'm not clear why this created the side effects I saw, but correcting it fixed the route.
The route with the fixed triggers property looks like this:
FlowRouter.route '/admin',
name: 'admin'
triggersEnter: [ (context, redirect) ->
console.log 'Admin triggers'
unless Roles.userIsInRole this.userId, ['admin']
redirect FlowRouter.path('login')
]
action: ->
console.log 'Rendering admin'
BlazeLayout.render 'layout', content: 'admin'

Categories

Resources