Laravel-Vue publishing components which should be protected by authentication - laravel

I am relatively new to Vue and started to build an SPA with Authentication and the Laravel Framework in the background. To achieve that I followed this tutorial:
https://codeburst.io/api-authentication-in-laravel-vue-spa-using-jwt-auth-d8251b3632e0
The auth is working perfectly fine. But what bugs my now is that routes/components which are protected with auth are also bundled in my app.js and are fully readable for everyone who is able to use the dev console.
Example
These are my routes:
export default new VueRouter({
routes: [
{
path: '/',
redirect: '/login',
},
{
path: '/login',
name: 'login',
component: AuthLogin,
meta: {
auth: false
},
},
{
path: '/order',
name: 'order',
component: OrderPage,
meta: {
auth: true
},
},
]
});
So /order and the corresponding component OrderPage ist protected by auth.
OrderPage:
<template>
<div>
Order Page
</div>
</template>
However the component OrderPage is readable in app.js in public directory. I can just search for the content "Order Page" and read it which is in my opinion not the goal of auth.
Is there a way to "isolate" the protected components and only export/bundle them when the auth is passed? Am I missing something?

Bundling based on Auth
You likely aren't bundling the javascript on the fly... You're transpiling and bundling long before the client visits your site, so no you shouldn't bundle when auth is passed. Bundling, transpiling, and minifying can be pretty resource intensive processes.
Isolation for Security
You could isolate code to a specific javascript file, there's no reason why you need to have everything bundled in the same app.js file. Laravel Mix can produce multiple bundles based on your configuration.
However, there's really no point from a security standpoint since client side code should never contain anything sensitive and all authorizations for actions should be performed on the server.
Production Readability
If you're worried about someone reading the client side code, minified javascript is incredibly hard to decipher since it's shrunk down and obfuscated. Production javascript should always be minified without source maps.

Related

How to properly connect Nuxt.js with a laravel backend?

I am starting a new project, Nuxt.js for the frontend and Laravel for the backend.
How can I connect the two?
I have installed a new Nuxt project using create-nuxt-app, and a new laravel project.
As far as I have searched, I figured I need some kind of environment variables.
In my nuxt project, I have added the dotenv package and placed a new .env file in the root of the nuxt project.
And added CORS to my laravel project, as I have been getting an error.
The variables inside are indeed accessible from the project, and im using them
like this:
APP_NAME=TestProjectName
API_URL=http://127.0.0.1:8000
And accessing it like this:
process.env.APP_NAME etc'
To make HTTP calls, I am using the official Axios module of nuxt.js, and to test it i used it in one of the components that came by default.
The backend:
Route::get('/', function () {
return "Hello from Laravel API";
});
and from inside the component:
console.log(process.env.API_URL)//Gives 127.0.0.1:8000
//But this gives undefined
this.$axios.$get(process.env.API_URL).then((response) => {
console.log(response);
});
}
What am I doing wrong here?
I have tried to describe my setup and problem as best as I can. If I overlooked something, please tell me and I will update my question. Thanks.
Taking for granted that visiting https://127.0.0.1:8000/ in your browser you get the expected response, lets see what might be wrong in the front end:
First you should make sure that axios module is initialized correctly. Your nuxt.config.js file should include the following
//inclusion of module
modules: [
'#nuxtjs/axios',
<other modules>,
],
//configuration of module
axios: {
baseURL: process.env.API_URL,
},
Keep in mind that depending on the component's lifecycle, your axios request may be occurring in the client side (after server side rendering), where the address 127.0.0.1 might be invalid. I would suggest that you avoid using 127.0.0.1 or localhost when defining api_uris, and prefer using your local network ip for local testing.
After configuring the axios module as above, you can make requests in your components using just relative api uris:
this.$axios.$get('/').then(response => {
console.log(response)
}).catch(err => {
console.error(err)
})
While testing if this works it is very helpful to open your browser's dev tools > network tab and check the state of the request. If you still don't get the response, the odds are that you'll have more info either from the catch section, or the request status from the dev tools.
Keep us updated!
Nuxt has a routing file stucture to make it easy to set up server side rendering but also to help with maintainability too. This can cause Laravel and Nuxt to fight over the routing, you will need to configure this to get it working correctly.
I'd suggest you use Laravel-Nuxt as a lot of these small problems are solved for you.
https://github.com/cretueusebiu/laravel-nuxt

How can I prerender a subset of my laravel+vue application?

I have a laravel application with my front-end written in Vuejs. I want to prerender the public pages only. What is the correct configuration for the prerender-spa-plugin to do this?
Most tutorials on the web show how to do it for the whole website, but I need only few pages pre-rendered. I must be missing something but I get only a blank page and my javascript is not loaded during the prerendering. I am not using vue router.
const path = require('path')
const PrerenderSPAPlugin = require('prerender-spa-plugin')
// In the mix webpack config -
plugins: [
...
new PrerenderSPAPlugin({
// Required - The path to the webpack-outputted app to prerender.
staticDir: path.join(__dirname, 'static'),
// Required - Routes to render.
routes: [ '/' ],
})
]
Error message: Unable to prerender all routes!
The javascript/vue files etc for the static part should all be in the static directory. It won't work if they are in the folder you normally use for organizing the rest of your application.
You need to use HTMLwebpackPlugin to copy over the html to the output directory (say, in public). Mix's copy happens too late. Chunks will help get only the js files you want.

JWT with Angular and SpringBoot

I want to integrate a JWT authentication in my current Angular application which is connected to a spring boot backend.
I looked through quiet a lot of tutorials, but most of them did not fit, since they were connected to Auth0. I want to handle the usermanagement by myself.
I found this example:
Angular: https://medium.com/#juliapassynkova/angular-springboot-jwt-integration-p-1-800a337a4e0
Spring Boot: https://medium.com/#nydiarra/secure-a-spring-boot-rest-api-with-json-web-token-reference-to-angular-integration-e57a25806c50
Unfortunately, this Angular Frontend is Angular 4 and I'm using Angular 6 already. They use the 'angular2-jwt' which is not compatible with Angular 6. I have to use 'auth0/angular-jwt'.
My problem is, that after I use my login form, the browser opens again a login popup to login the backend. But even with the right credentials, it doesn't work. I'm guessing, that some credentials are missing in the request. In the app.module.ts are 2 old angular2-jwt code, which i don't know how to upgrade it to auth0/angular-jwt
export function authHttpServiceFactory(http: Http) {
return new AuthHttp(new AuthConfig({
headerPrefix: 'Bearer',
tokenName: TOKEN_NAME,
globalHeaders: [{'Content-Type': 'application/json'}],
noJwtError: false,
noTokenScheme: true,
tokenGetter: (() => localStorage.getItem(TOKEN_NAME))
}), http);
}
and
providers: [
{provide: AuthHttp, useFactory: authHttpServiceFactory, deps: [Http]},
]
Can someone help me with this issue. May be I'm wrong with my guessing and it could be something else?
A side note; I just changed my frontend but trying to connect to the backend from the example. If I'm using both front- and backend from the example, its working fine.
I have passed successful migration from angular2-jwt to auth0/angular-jwt several months ago. What you have to keep in mind while doing so is:
auth0/angular-jwt uses new angular HttpClient library, so if you want to use so, you have to migrate all your application to it (I suggest doing so anyway, new library is quite amazing)
new angular-jwt uses HttpInterceptors - this allows you to attach JWT directly to HttpClient filters chain. So you don't have to migrate your code above. You have to remove it completely and replace with interceptor initialization: (copy-paste from auth0/angular-jwt documentation):
import { JwtModule } from '#auth0/angular-jwt';
import { HttpClientModule } from '#angular/common/http';
export function tokenGetter() {
return localStorage.getItem('access_token');
}
#NgModule({
bootstrap: [AppComponent],
imports: [
// ...
HttpClientModule,
JwtModule.forRoot({
config: {
tokenGetter: tokenGetter,
whitelistedDomains: ['localhost:3001'],
blacklistedRoutes: ['localhost:3001/auth/']
}
})
]
})
export class AppModule {}
Remember to apply this code in your root module - then use your HttpClient without any changes and interceptors will apply JWT automatically. In case of problems - blame whitelistedDomains/blacklistedRoutes. These fields are very poorly implemented at the moment and are causing problems with regular expressions etc.
As migration is not straightforward, and took me a lot of time, feel free to ask about it. There's high probability, that I'll know the answers.

How to use Vue.js plugins and components in Laravel

I am using Vue.js (within the Laravel framework) and I'm new to both. I'm trying to understand some basic ideas about some code I"m trying to use:
App.js:
import Vue from 'vue';
import Toasted from 'vue-toasted';
Vue.component('toast-alert', require('./components/ToastAlert.vue'));
Vue.use(Toasted);
ToastAlert.vue:
<template>
</template>
<script>
export default {
props: {
},
mounted() {
this.showToast()
},
data() {
return {
message: 'Status Update',
}
},
methods: {
showToast() {
this.$toasted.show(this.message, {
duration: 3000
});
}
}
}
</script>
Questions:
I understand the import tells the script that we ant to pull in certain node modules but I don't totally understand what use() is for. I have read documentation to see thats what you do with plugins (https://v2.vuejs.org/v2/guide/plugins.html), but not really understanding more than that.
Again from the documentation, I see that when registering a Vue component, the second parameter is a list of options, ie: template, props, methods etc. I'm a bit confused about what require does and how it translates the vue file (which is a composed of tags and a tag exporting an object) into a final object which meets the standards of Vue.component.
1) In Vue, calling Vue.use( Plugin, Options ) makes the plugin available throughout the application. It's basically a way to bootstrap a plugin i.e. Vue-Toasted, so you can use it throughout your application. You can define configuration options as well here.
2) Vue.component is used to register (your own) components in the application. It allows them to be used within each other component, without having to define them in each file. Think of the app.js file as the bootstrap file, it defines all of the plugins, components, etc. and registers them for use in Vue. require is importing the file and Vue is parsing the template and object. Note this is all compiled in webpack and cannot load in a browser as-is.

Removing # from url is showing me 404 after page refresh, I am using Vue Js in Laravel Application

I am developing a laravel(5.4) application in which i am using vue js(2.0) for SPA, my problem is i want to remove #(hash) from URL.
please suggest me any solution?
This is my HTML
<ul class="category-list">
<li><router-link to="/testlink.html">Tets Link</router-link></li>
<li><router-link to="/demotestlink.html">Demo Test LInk</router-link></li>
</ul>
This is my vue js code
export default new VueRouter({
[
{
path: '/testlink.html',
component:require('./components/demo/Testlink')
}
],
mode: 'history',
});
and i have made a Testlink.vue file inside components/demo folder in Assets
Note: FYI, I am using vue.js(2.0) in Laravel(5.4) Application
From Vue-Router documentation, I found this.
The default mode for vue-router is hash mode - it uses the URL hash to simulate a full URL so that the page won't be reloaded when the URL changes.
To get rid of the hash, we can use the router's history mode, which leverages the history.pushState API to achieve URL navigation without a page reload:
const router = new VueRouter({
mode: 'history',
routes: [...]
})
I tried the above and it worked fine for me. For more information read here

Resources