mithril.js redirect user if not connected - mithril.js

How to use mithril.js and it's routing system to redirect my user to the login form when the user is not yet connected?
I define some routes:
m.route.mode = 'search';
m.route(document.getElementById('app'), "/", {
'/': LoginForm,
'/orders': OrderList,
'/order/new': OrderForm,
'/order/:orderId': OrderForm
});
But I want to redirect /orders and other routes to / if the user has not login.
Do I need to put the code in the controllers (OrderList.controller and OrderForm.controller)? or in the views (OrderList.view and OrderForm.view)?
window.OrderForm = {
controller: function () {
var ctrl = this
if (/* user not logged */) {
m.route('/')
return;
}
// controller code
},
view: function(ctrl) {
if (/* user not logged */) {
m.route('/')
return;
}
// view code
return m('....');
}
}

You should put redirect to the controllers.
In this case redirect is called before requestAnimationFrame, so you are redirected to appropriate controller and appropriate view is rendered.
In case redirecting in the views, you probably are not redirected properly, view is rendered anyway.

Related

Wait for state update in vuejs router´s beforeEnter

I want to restrict access to certain pages in my vue router. Instead of having the auth logic in each component, I would prefer, for instance, to just have a 'hasUserAccess' check in my child-routes where it´s needed
{
path: 'admin',
name: 'admin',
beforeEnter: hasUserAccess,
component: () => import(/* webpackChunkName: "admin" */ '#/_ui/admin/Admin.vue')
},
...
function hasUserAccess(to, from, next) {
if (myState.user.isAdmin) {
next();
} else {
next({ path: '/noaccess' });
}
}
This works as intended when navigating from another page to the 'admin' page. This does not work when i manually type the /admin url (or pressing f5 while on the admin page) because the user object hasn´t been fetched from the server yet (some other logic is taking care of fetching the user).
The 'beforeEnter' is async, but as far as I know it ain´t possible to 'watch' the user object, or await it, from the router since the router is not a typical vue component.
So how is this common problem normally solved?
Just apply the beforeEach to the router itself. On the router file, you could do this:
router.beforeEach((to, from, next) => {
//in case you need to add more public pages like blog, about, etc
const publicPages = ["/login"];
//check if the "to" path is a public page or not
const authRequired = !publicPages.includes(to.path);
//If the page is auth protected and hasUserAccess is false
if (authRequired && !hasUserAccess) {
//return the user to the login to force the user to login
return next("/login");
}
//The conditional is false, then send the user to the right place
return next();
});
Try to modify this at your convenience, but this is more or less what I do in a situation like yours.

How do I automatically redirect the user if they are already logged in using Vue and Firebase authentication?

Description
I am trying to automatically route the user to the "Games.vue" component if they are already logged in. For authentication I am using Firebase and I check if they are logged in using:
var user = firebase.auth().currentUser;
if (user) {
// User is signed in.
} else {
// No user is signed in.
}
What I want to have happen is for the user to not see the Login page if they are already signed in. So they are taken directly to the Games page. I don't know how to accomplish this using Vue. I need something to run before the Login-component that redirects if logged in.
Attempt at solution
The only way I know how to solve this is to show the Login page, check if the Firebase user is logged in and then go to the Games page. This can work, but it isn't the behavior I am looking for. I am using the Vue router. Thank you for your help.
I would suggest to use a VueRouter global guard like so:
const router = new VueRouter({ ... })
router.beforeEach((to, from, next) => {
if (!user) {
next('login');
} else {
next();
}
})
That being said, you then need a way to specify which route requires authentication. I would suggest to use route meta fields like so:
routes = [
{
name: 'login',
path: '/login',
meta: {
requiresAuth: false
}
},
{
name: 'games',
path: '/games',
meta: {
requiresAuth: true
}
}
]
Now your guards becomes:
if (!user && to.meta.requiresAuth) {
next('login');
} else {
next();
}
Vue router provides an example for this use case, take a look at the documentation.
TIP: Make sure to subscribe to auth changes using Firebase onAuthStateChanged method.
let user = firebase.auth().currentUser;
firebase.auth().onAuthStateChanged(function(user) {
user = user;
});
EDIT: To redirect once logged in, just watch for auth changes and redirect using router.push.
auth.onAuthStateChanged(newUserState => {
user = newUserState;
if (user) {
router.push("/games");
}
});

Authenticate with Moodle from a mobile app

My mobile app needs to log in to Moodle to get Json data from a webservice and display it using Angular.
In order to do that, I need to pass in a username and password and get a Moodle webservice token back, so my app doesn't need to log in again (at least until the token expires).
(this is one of those "ask and answer your own question" things, so my solution is below, but comments & suggestions welcome.)
With thanks to all the other StackOverflow pages I have used to create this solution!
See also - how to get data from your Moodle webservice with Angular.
Step 1. Check if a token already exists
jQuery(document).ready(function () {
/* when the user clicks log-out button, destroy the session */
$('#btn_logout').on('click', function () {
$('.pane').hide(); /* hide all screens */
$('#menu').toggleClass('ui-panel-open ui-panel-closed');
$.jStorage.deleteKey('session');
makeUserLogin();
});
var session = $.jStorage.get('session', ''); // syntax: $.jStorage.get(keyname, "default value")
if (session) { // if there is already a session, redirect to landing pane
showApp();
} else { // if there is no session *then* redirect to the login pane
makeUserLogin();
}
});
Step 2. create functions to show app & redirect to login page
function showApp() {
$('#home-pane').show(); /* show home screen */
$('#system-message').hide();
$('#login-pane').hide(); /* hide login screen*/
$('#menu_btn').removeClass('hidden'); /* show menu button so user can see rest of app */
}
function makeUserLogin() {
$('#btn_login').click(function () {
console.log('click event for login_button');
var username = $('#username').val();
var password = $('#password').val();
postCredentials(username, password, createSession);
});
$('#menu_btn').addClass('hidden'); /* hide menu button so user cannot see rest of app */
$('#home-pane').hide(); /* hide home screen */
$('#login-pane').show(); /* show login screen */
}
function postCredentials(username, password, callback) {
if ((username.length && password.length) && (username !== '' && password !='')) {
var url = 'https://moodle.yourcompany.com/local/login/token.php';
$.post(url, {
username: username,
password: password,
service: 'webservice_ws' // your webservice name
}).done(function (data) {
token = data.token;
dataString = JSON.stringify(data);
if (dataString.indexOf('error') > 0) {
showErrorDialog('<p class="error">Invalid user credentials, please try again</p>');
}
else {
createSession(token);
}
}).fail(function () {
showErrorDialog('<p class="error">Login failed</p>');
});
} else {
showErrorDialog('<p class="error">Please enter a username and password</p>');
}
}
function createSession(token) {
// syntax: $.jStorage.set('keyname', 'keyvalue', {TTL: milliseconds}); // {TTL... is optional time, in milliseconds, until key/value pair expires}
$.jStorage.set('session', token, { TTL: 28800000 });
// redirect to whatever page you need after a successful login
showApp();
}
function showErrorDialog(errorMsg) {
$('#system-message').html(errorMsg);
$('#system-message').fadeIn();
}

Laravel Auth loging out malicious user

I'm implementing a banning system. I have an admin view where the admin can ban users. I want to log out a user if the admin bans him in that moment. Something like Auth::logout($user). Is that possible?? Or do I have to add a filter to all my routes to check if the logged user is banned.
Filters are the way to go. It's easy and clean to solve this problem, see my example below.
if user is banned at any point it will logout user at his/her next request, you can redirect user with Session flash message, your login code works as it is.
Route::filter('auth', function()
{
if (Auth::guest())
{
if (Request::ajax())
{
return Response::make('Unauthorized', 401);
}
else
{
return Redirect::guest('login');
}
}
else
{
// If the user is banned, immediately log out.
if(Auth::check() && !Auth::user()->bannedFlag)
{
Auth::logout();
Session::flash('message','Your account is banned, please contact your administrator to active your account');
// redirect to login page
return Redirect::to('/');
}
}
});
and for your routes use group routes
Route::group(array('before' => 'auth'), function()
{
//use your routes
});

How do I pass the id of the logged in user to my chosen controller in grails using acegi

I have secured my Grails app using the ACEGI plugin and am using annotations on my controller methods to prompt the user to login.
My app has a static HTML front page with a login link on it which redirects to the login/auth page. On a successful login I want to load my own custom page for the authenticated user, called person/mainpage.
In my LoginController there is the following code...
def index = {
if (isLoggedIn()) {
redirect uri: '/'
}
else {
redirect action: auth, params: params
}
}
/**
* Show the login page.
*/
def auth = {
nocache response
if (isLoggedIn()) {
redirect uri: '/'
return
}
String view
String postUrl
def config = authenticateService.securityConfig.security
if (config.useOpenId) {
view = 'openIdAuth'
postUrl = "${request.contextPath}/login/openIdAuthenticate"
}
else if (config.useFacebook) {
view = 'facebookAuth'
postUrl = "${request.contextPath}${config.facebook.filterProcessesUrl}"
}
else {
view = 'auth'
postUrl = "${request.contextPath}${config.filterProcessesUrl}"
}
render view: view, model: [postUrl: postUrl]
}
This redirects the successful login back to the main page of the application (/), which is not what I want. Googling for a little while I found that I could define a default target for my authentication in securityconfig.groovy like this..
defaultTargetUrl = "/person/mainpage"
My question is how to identify which user logged in when I land on my mainpage action in my PersonController?
At first I changed my index action in LoginController to redirect to my page like this...
def index = {
if (isLoggedIn()) {
redirect controller: person, action: mainpage, params: params
}
else {
redirect action: auth, params: params
}
}
but the id of the logged in person does not appear in the params (which I think I am happy about because it seems crazy to be able to pull up pages just by defining a user row ID as a url parameter).
So what's the right way to do this? Basically I want my person/mainpage action to be able to resolve the currently logged in user.
You can access the logged in user using authenticateService. To get the user/person domain instance call authenticateService.userDomain() and to just get the Authentication (which has a getUsername() method that might be sufficient) call authenticateService.principal(). If your defaultTargetUrl is "/person/mainpage" then your PersonController's 'mainpage' action would look something like this:
class PersonController {
def authenticateService
def mainpage = {
def user = authenticateService.userDomain()
if (user) {
log.info "you're logged in as $user.username"
}
else {
log.info "you're not logged in"
}
[user: user]
}
}
and then you'd have the 'user' available in mainpage.gsp to render data from.