Laravel API - Authentication works just after reloading the page - laravel

I am trying to build a Single Page Application (SPA) using VueJS as a front-end and Laravel as a back-end.
I am using laravel's passport to manage the authentication tokens etc.
The problem: After login I have to reload the page to be successfully authenticated.
Login method
data() {
return {
email: '',
password: '',
}
},
methods: {
login() {
var data = {
client_id: 2,
client_secret: '****************************',
grant_type: 'password',
username: this.email,
password: this.password
}
// send data
this.$http.post('oauth/token', data)
.then(response => {
// authenticate the user
this.$store.dispatch({
type: 'authenticate',
token: response.body.access_token,
expiration: response.body.expires_in + Date.now()
})
// redirect after successful login
if (this.$route.query.from)
this.$router.push(this.$route.query.from)
else
this.$router.push('/feed')
})
}
}
Get the user information from the backend (just works after refreshing the page)
setUser () {
// this route throws 'unauthenticated' error
// and works only after refreshing the page
this.$http.get('api/users/')
.then(response => {
this.$store.dispatch({
type: 'setUser',
id: response.body.id,
email: response.body.email,
name: response.body.name
})
})
}
}
Vuex store
export default new Vuex.Store({
state: {
isAuth: !!localStorage.getItem('token'),
user: {
id: localStorage.getItem('id'),
email: localStorage.getItem('email'),
name: localStorage.getItem('name')
}
},
getters: {
isLoggedIn(state) {
return state.isAuth
},
getUser(state) {
return state.user
}
},
mutations: {
authenticate(state, { token, expiration }) {
localStorage.setItem('token', token)
localStorage.setItem('expiration', expiration)
state.isAuth = true
},
setUser(state, { id, email, name }) {
localStorage.setItem('id', id)
localStorage.setItem('email', email)
localStorage.setItem('name', name)
state.user.id = id
state.user.email = email
state.user.name = name
}
},
actions: {
authenticate: ({ commit }, { token, expiration }) => commit('authenticate', { token, expiration }),
setUser: ({ commit }, { id, email, name }) => commit('setUser', { id, email, name })
}
})
Laravel route
Route::group(['middleware' => 'auth:api'], function() {
Route::get('/users', 'UsersController#users');
});
Laravel function
public function users(Request $request)
{
return $request->user();
}
The error message
When I reload the page the error message disappears and I am successfully authenticated.
I would be very happy for any kind of help!

Thanks to Frank Provost I figured out the answer. In case anybody else comes across the same problem:
I was not passing the token with every request.
I had to change this
Vue.http.headers.common['Authorization'] = 'Bearer ' + Vue.auth.getToken()
to this
Vue.http.interceptors.push((request, next) => {
request.headers.set('Authorization', 'Bearer ' + Vue.auth.getToken())
request.headers.set('Accept', 'application/json')
next()
})
Now, everything works as expected - no need to refresh the url.

Related

How to put in Axios request 2 params

Im try to create a simple CRUD App on Laravel with Vue.Js (Vuex also)
In Laravel im create resource controller UserController
Im have a problem with update method in this controller
This method was accepted only PUT, PATCH HTTP Request methods
location: app/Http/Controllers/Admin/UserController.php
This is how it looks
public function update(Request $request, $id)
{
return $request->all();
}
In my Vue Component im try to send 2 parameters ID and DATA
But all the time in response im get a empty array
This is my Vuex file
location: resources/js/components/admin/store/modules/user.js
This is code of Axios request:
async updateUserInfo(ctx, id, data)
{
return new Promise((resolve, reject) => {
axios({
url: '/users/' + id,
method: 'put',
data: data,
headers: {'Content-Type': 'multipart/form-data'},
})
.then((resp) => {
console.log(resp)
// ctx.commit('updateUser', resp.data.user)
resolve(resp)
})
.catch((error) => {
console.log(error)
// ctx.commit('updateErrors', error.response.data.errors);
reject(error)
})
})
},
This is my Vue Component where im try call this function
location: resources/js/components/admin/views/components/user/EditComponent.vue
Code:
data()
{
return{
formData: {
address: '',
birthday: '',
email: '',
name: '',
password: '',
passwordConfirmation: '',
phone: '',
surname: '',
}
}
},
methods:{
...mapActions('user', ['editUserInfo', 'updateUserInfo']),
async onClickUpdateInfo(id)
{
this.updateUserInfo(id, this.formData);
}
},
my Submit button in form
<button #click.prevent="onClickUpdateInfo(id)" class="btn btn-success text-white">Обновить</button>[![enter image description here][1]][1]
You should pass context and payload to Vuex action. So I'm guessing you do not have access to form data inside your action, right?
Try this: async updateUserInfo(ctx, { id, data })
And then in the vue component: this.updateUserInfo({ id, data: this.formData });

Vuejs route loading based on user type

I am returning user type in all my components but i need to add validation of it in my routes, not sure how to.
Code
This is my route.js file where the routes i need users to be authenticated are defined in meta
import Vue from "vue";
import VueRouter from 'vue-router';
import store from './store';
Vue.use(VueRouter);
const router = new VueRouter({
mode: "history",
routes: [
// ADMIN ROUTES
{
path: '/dashboard',
name: 'dashboard',
component: Dashboard,
meta: {
requiresAuth: true,
layout: 'admin'
}
},
]
});
router.beforeEach((to, from, next) => {
if (to.matched.some(record => record.meta.requiresAuth)) {
if (!store.getters.isLoggedIn) {
next({
name: 'login'
})
} else {
next()
}
} else {
next()
}
})
router.afterEach((to, from) => {
Vue.nextTick(() => {
document.title = to.pageTitle || 'CC';
});
});
export default router;
As you can see I have requiresAuth: true, which only allows authenticated user to access this route, I also need to add another value which says if user type == admin that way not all logged in users can access to such route but only admins.
This is my logged user info which is accessible in all components and is included type value
Question
How can I add user type to routes meta?
Note
my type value can be one of this 3 conditions
admin (admins role)
customer (any other user role)
undefined (user with no role assigned)
Update
Forgot to mention that in all my components I also have this function
beforeRouteEnter (to, from, next) {
const token = localStorage.getItem('access_token')
return token ? next() : next('/login')
},
This simply check if my user is logged in based on saved token in localStorage
Update 2
I've also tried to get my user type in component function like code below, but is returned this.$store is undefined
beforeRouteEnter (to, from, next) {
if (this.$store.getters.loggedUser.type != 'admin') {
next({
name: 'home'
})
} else {
next()
}
}
The component instance this is not avaliable inside beforeRouteEnter See here.
One way to do what you want is to add another meta attribute to your admin routes and check the user type for each route that has admin: true.
Your router code would look something like this:
const router = new VueRouter({
mode: "history",
routes: [
// ADMIN ROUTES
{
path: '/dashboard',
name: 'dashboard',
component: Dashboard,
meta: {
requiresAuth: true,
layout: 'admin',
admin: true
}
},
]
});
router.beforeEach((to, from, next) => {
if (to.matched.some(record => record.meta.requiresAuth)) {
if (!store.getters.isLoggedIn) {
next({
name: 'login'
})
}
}
if (to.matched.some(record => record.meta.admin)) {
if (store.getters.loggedUser.type !== 'admin') {
// Do something if the user is not an admin
// maybe redirect to a forbidden page
}
}
next()
})

Am i missing something, this.form.fill() doesn't seems to work for me

My UserController Function:
public function profile()
{
return auth('api')->user();
}
i'm working on project that frontend with vue and backend with laravel.
My Vue.js Code:
import Form from 'vform';
export default {
data () {
return {
form: new Form({
id:'',
name: '',
email: '',
password: '',
type:'',
bio:'',
photo:''
})
}
},
mounted() {
console.log('Component mounted.')
},
created(){
axios.get("api/profile")
.then( ({data}) => (this.form.fill(data)))
}
}
i try to show data in form, but when i call this function it not return the data. what i am doing wrong? i know there is problem with this function this.form.fill(data) but i don't know what actual the problem is.

getting 500 server error while sending data to database through controller from vue

I am trying to send some data from my vue component to database using a laravel controller. To avoid blank input error, I already made all my table columns nullable except the ID. Still when I am trying to send the data using post method, i am getting error 500.
Here is my vue method:
addRecord(){
fetch('api/video_call', {
method: 'post',
body: JSON.stringify(this.call_detail),
headers: {
'content-type': 'application/json'
}
})
.then(res => res.json())
.then( data=> {
this.call_detail.receiver_caller_id = '';
this.call_detail.sender_caller_id = '';
this.call_detail.receiver_id= '';
this.call_detail.sender_id= '';
this.call_detail.call_received='';
alert('Test Done');
this.fetchCallDetail();
})
.catch(err => console.log(err));
}
}
here is the data that I am returning from vue:
data(){
return {
users: [],
call_details: [],
call_detail: {
id: '',
receiver_caller_id: '',
sender_caller_id: '',
receiver_id: '',
sender_id: '',
call_received: ''
},
call_detail_id: '',
pagination: {},
call_allowed: false
}
}
Here is my route in api.php
Route::post('video_call', 'VideoCallController#store');
And finally here is the store function in controller:
public function store(Request $request)
{
$record = $request->isMethod('put')?VideoCall::findOrFail($request->call_detail_id):new VideoCall;
$record->id= $request->input('call_detail_id');
$record->receiver_id= $request->input('receiver_id');
$record->sender_id= $request->input('sender_id');
$record->sender_call_id= $request->input('sender_call_id');
$record->receiver_call_id= $request->input('receiver_call_id');
$record->call_recieved=$request->input('call_received');
if($record->save())
{
return new VideoCallResource($record);
}
}
I used this methods in my previous apps to send data from vue to database and it worked just fine. In this app it is returning error.

How to have multiple passport for different user types in MEAN stack

In my project, I am using the passport feature in MEAN stack for user authentication. I have logins for 4 different user types(patient , doctor , and so on.) Can I have multiple passports for all different user types??
Below mentioned is the code for User(patient) Passport. I tried creating different passports, but I don't know how to link them to the project.
const passport = require('passport');
const localStrategy = require('passport-local').Strategy;
const mongoose = require('mongoose');
var User = mongoose.model('User');
passport.use(
new localStrategy({ usernameField: 'email' },
(username, password, done) => {
User.findOne({ email: username },
(err, user) => {
if (err)
return done(err);
// unknown user
else if (!user)
return done(null, false, { message: 'Email is not registered' });
// wrong password
else if (!user.verifyPassword(password))
return done(null, false, { message: 'Wrong password.' });
// authentication succeeded
else
return done(null, user);
});
})
);

Resources